写在前
本篇通过代码方式来展示Spring循环依赖的出现过程,以及是如何解决循环依赖,最后再通过源码来看看Spring中具体是如何解决的。
代码示例
其他前置代码
public interface IApi {
void say();
}
//实例A
@Component
public class InstanceA implements IApi {
@Autowired
private InstanceB instanceB;
public InstanceB getInstanceB() {
return instanceB;
}
public void setInstanceB(InstanceB instanceB) {
this.instanceB = instanceB;
}
public InstanceA(InstanceB instanceB) {
this.instanceB = instanceB;
}
public InstanceA() {
System.out.println("InstanceA实例化");
}
@Override
public void say() {
System.out.println("I'm A");
}
}
//实例B
@Component
public class InstanceB {
@Autowired
private InstanceA instanceA;
public InstanceA getInstanceA() {
return instanceA;
}
public void setInstanceA(InstanceA instanceA) {
this.instanceA = instanceA;
}
public InstanceB(InstanceA instanceA) {
this.instanceA = instanceA;
}
public InstanceB() {
System.out.println("InstanceB实例化");
}
}
//动态代理
public class JdkDynimcProxy implements InvocationHandler {
private Object target;
public JdkDynimcProxy(Object target) {
this.target = target;
}
public Object getProxy() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("测试");
return method.invoke(target,args);
}
}
public class JdkProxyBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
// 假设B 被切点命中 需要创建代理
if(bean instanceof InstanceA/*判断是不是被增强的类,是不是需要创建动态代理*/) {
JdkDynimcProxy jdkDynimcProxy = new JdkDynimcProxy(bean);
return jdkDynimcProxy.getProxy();
}
return bean;
}
}
@FunctionalInterface
public interface ObjectFactory<T> {
/**
* Return an instance (possibly shared or independent)
* of the object managed by this factory.
* @return the resulting instance
* @throws BeansException in case of creation errors
*/
T getObject() throws BeansException;
}
什么是循环依赖
如图所示:即在A类中注入了B的实例,在B中也注入了A的实例,那么Spring在创建这些实例的时候,就会出现循环依赖。
引入一级缓存
public class MainTest {
private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
public static void loadBeanDefinition(){
RootBeanDefinition aRootBeanDefinition = new RootBeanDefinition(InstanceA.class);
RootBeanDefinition bRootBeanDefinition = new RootBeanDefinition(InstanceB.class);
beanDefinitionMap.put("instanceA",aRootBeanDefinition);
beanDefinitionMap.put("instanceB",bRootBeanDefinition);
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
loadBeanDefinition();
for (String key : beanDefinitionMap.keySet()) {
getBean(key);
}
InstanceA instanceA = (InstanceA) getBean("instanceA");
instanceA.say();
}
// 一级缓存
public static Map<String,Object> singletonObjects = new ConcurrentHashMap<>();
public static Object getBean(String beanName) throws IllegalAccessException, InstantiationException {
Object singleton = getSingleton(beanName);
if (singleton != null){
return singleton;
}
// 实例化
RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
Class<?> beanClass = beanDefinition.getBeanClass();
Object instanceBean = beanClass.newInstance();
// 添加一级缓存
singletonObjects.put(beanName,instanceBean);
// 属性赋值
Field[] declaredFields = beanClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
Annotation annotation = declaredField.getAnnotation(Autowired.class);
if (annotation != null){
String name = declaredField.getName();
declaredField.setAccessible(true);
declaredField.set(instanceBean,getBean(name));
}
}
// 初始化
return instanceBean;
}
public static Object getSingleton(String beanName){
if (singletonObjects.containsKey(beanName)){
return singletonObjects.get(beanName);
}
return null;
}
}
引入一级缓存,似乎是可以解决了循环依赖如下图所示。但是,试想一下,如果在多线程情况下,就会出现问题,会获取到不完整的Bean。首先想到的是可以加锁,加锁确实是可以解决多线程下循环依赖的问题,但是不利于扩展,Spring当然不会这么干。
引入二级缓存
//================二级缓存
public class MainTest {
private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
public static void loadBeanDefinition(){
RootBeanDefinition aRootBeanDefinition = new RootBeanDefinition(InstanceA.class);
RootBeanDefinition bRootBeanDefinition = new RootBeanDefinition(InstanceB.class);
beanDefinitionMap.put("instanceA",aRootBeanDefinition);
beanDefinitionMap.put("instanceB",bRootBeanDefinition);
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
loadBeanDefinition();
for (String key : beanDefinitionMap.keySet()) {
getBean(key);
}
InstanceA instanceA = (InstanceA) getBean("instanceA");
instanceA.say();
}
// 一级缓存
public static Map<String,Object> singletonObjects = new ConcurrentHashMap<>();
// 二级缓存 为了将成熟bean和不完整的bean分开
public static Map<String,Object> earlySingletonObjects = new ConcurrentHashMap<>();
public static Object getBean(String beanName) throws IllegalAccessException, InstantiationException {
Object singleton = getSingleton(beanName);
if (singleton != null){
return singleton;
}
// 实例化
RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
Class<?> beanClass = beanDefinition.getBeanClass();
Object instanceBean = beanClass.newInstance();
// 添加二级缓存
earlySingletonObjects.put(beanName,instanceBean);
// 属性赋值
Field[] declaredFields = beanClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
Annotation annotation = declaredField.getAnnotation(Autowired.class);
if (annotation != null){
String name = declaredField.getName();
declaredField.setAccessible(true);
declaredField.set(instanceBean,getBean(name));
}
}
// 初始化
// 添加一级缓存
singletonObjects.put(beanName,instanceBean);
return instanceBean;
}
public static Object getSingleton(String beanName){
if (singletonObjects.containsKey(beanName)){
return singletonObjects.get(beanName);
}else if (earlySingletonObjects.containsKey(beanName)){
return earlySingletonObjects.get(beanName);
}
return null;
}
}
引入了二级缓存,首先从一级缓存中获取完整的Bean直接返回,获取不到再去二级缓存中获取不完整的Bean,进行属性赋值操作后再放入到一级缓存中。使用二级缓存解决了耦合、以及循环依赖问题。那么为什么还要引入三级缓存?
引入三级缓存
public class MainTest {
private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
public static void loadBeanDefinition(){
RootBeanDefinition aRootBeanDefinition = new RootBeanDefinition(InstanceA.class);
RootBeanDefinition bRootBeanDefinition = new RootBeanDefinition(InstanceB.class);
beanDefinitionMap.put("instanceA",aRootBeanDefinition);
beanDefinitionMap.put("instanceB",bRootBeanDefinition);
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
loadBeanDefinition();
for (String key : beanDefinitionMap.keySet()) {
getBean(key);
}
InstanceA instanceA = (InstanceA) getBean("instanceA");
instanceA.say();
}
// 一级缓存
public static Map<String,Object> singletonObjects = new ConcurrentHashMap<>();
// 二级缓存 为了将成熟bean和不完整的bean分开
public static Map<String,Object> earlySingletonObjects = new ConcurrentHashMap<>();
// 三级缓存
public static Map<String,ObjectFactory> singletonFactories = new ConcurrentHashMap<>();
// 循环依赖标识
public static Set<String> singletonCurrennlyInCreation = new HashSet<>();
public static Object getBean(String beanName) throws IllegalAccessException, InstantiationException {
Object singleton = getSingleton(beanName);
if (singleton != null){
return singleton;
}
// 正在创建
if (!singletonCurrennlyInCreation.contains(beanName)){
singletonCurrennlyInCreation.add(beanName);
}
// 实例化
RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
Class<?> beanClass = beanDefinition.getBeanClass();
Object instanceBean = beanClass.newInstance();
// 创建动态代理
// 只在循环依赖的情况下,在实例化后创建动态代理
// 那么需要判断是不是循环依赖
singletonFactories.put(beanName, () -> new JdkProxyBeanPostProcessor().getEarlyBeanReference(earlySingletonObjects.get(beanName),beanName));
// 添加二级缓存
earlySingletonObjects.put(beanName,instanceBean);
// 属性赋值
Field[] declaredFields = beanClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
Annotation annotation = declaredField.getAnnotation(Autowired.class);
if (annotation != null){
String name = declaredField.getName();
declaredField.setAccessible(true);
declaredField.set(instanceBean,getBean(name));
}
}
// 初始化
// 正常是初始化之后在创建动态代理
if (earlySingletonObjects.containsKey(beanName)){
instanceBean = getSingleton(beanName);
}
// 添加一级缓存
singletonObjects.put(beanName,instanceBean);
return instanceBean;
}
public static Object getSingleton(String beanName){
Object bean = singletonObjects.get(beanName);
// 说明是循环依赖
if (bean == null && singletonCurrennlyInCreation.contains(beanName)){
// 从二级缓存拿
bean = earlySingletonObjects.get(beanName);
if (bean == null){
// 从三级缓存拿
ObjectFactory objectFactory = singletonFactories.get(beanName);
if (objectFactory != null){
bean = objectFactory.getObject();
earlySingletonObjects.put(beanName,bean);
}
}
}
return bean;
}
}
例如出现这么一种情况,Bean A的aop动态代理创建时在初始化之后,但是循环依赖的Bean如果使用了AOP。 那无法等到解决完循环依赖再创建动态代理,因为这个时候已经注入属性,所以如果循环依赖的Bean使用了aop。需要提前创建aop。
小结
如果只有一级缓存解决循环依赖也是可以的,只不过性能最低、耦合性、扩展性最差。如果只有二级缓存解决循环依赖也是可以的,耦合性太高。所以三级缓存解决循环依赖和处理多线程读取不完整Bean是最完美的方案。
源码
前面的流程在前面的文章中已有分析过,getBean()才是真正的取创建Bean实例,getBean()里面又去调用了doGetBean()方法,因此这里就从doGetBean()方法开始。
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
/**
* 在这里 传入进来的name 可能是 别名, 也有可能是工厂bean的name,所以在这里需要转换
*/
final String beanName = transformedBeanName(name);
Object bean;
//尝试去缓存中获取对象
//详细往下看此方法源码
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
/**
* /*
* 如果 sharedInstance 是普通的单例 bean,下面的方法会直接返回。但如果
* sharedInstance 是 FactoryBean 类型的,则需调用 getObject 工厂方法获取真正的
* bean 实例。如果用户想获取 FactoryBean 本身,这里也不会做特别的处理,直接返回
* 即可。毕竟 FactoryBean 的实现类本身也是一种 bean,只不过具有一点特殊的功能而已。
*/
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
/**
* spring 只能解决单例对象的setter 注入的循环依赖,不能解决构造器注入
*/
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
/**
* 判断AbstractBeanFacotry工厂是否有父工厂(一般情况下是没有父工厂因为abstractBeanFactory直接是抽象类,不存在父工厂)
* 一般情况下,只有Spring 和SpringMvc整合的时才会有父子容器的概念,
* 比如我们的Controller中注入Service的时候,发现我们依赖的是一个引用对象,那么他就会调用getBean去把service找出来
* 但是当前所在的容器是web子容器,那么就会在这里的 先去父容器找
*/
BeanFactory parentBeanFactory = getParentBeanFactory();
//若存在父工厂,切当前的bean工厂不存在当前的bean定义,那么bean定义是存在于父beanFacotry中
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
//获取bean的原始名称
String nameToLookup = originalBeanName(name);
//若为 AbstractBeanFactory 类型,委托父类处理
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// 委托给构造函数 getBean() 处理
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// 没有 args,委托给标准的 getBean() 处理
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
/**
* 方法参数 typeCheckOnly ,是用来判断调用 #getBean(...) 方法时,表示是否为仅仅进行类型检查获取 Bean 对象
* 如果不是仅仅做类型检查,而是创建 Bean 对象,则需要调用 #markBeanAsCreated(String beanName) 方法,进行记录
*/
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//检查当前创建的bean定义是不是抽象的bean定义
checkMergedBeanDefinition(mbd, beanName, args);
/**
*
* @Bean
public DependsA dependsA() {
return new DependsA();
}
@Bean
@DependsOn(value = {"dependsA"})
public DependsB dependsB() {
return new DependsB();
}
* 处理dependsOn的依赖(这个不是我们所谓的循环依赖 而是bean创建前后的依赖)
*/
//依赖bean的名称
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
// <1> 若给定的依赖 bean 已经注册为依赖给定的 bean
// 即循环依赖的情况,抛出 BeanCreationException 异常
for (String dep : dependsOn) {
//beanName是当前正在创建的bean,dep是正在创建的bean的依赖的bean的名称
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
//保存的是依赖 beanName 之间的映射关系:依赖 beanName - > beanName 的集合
registerDependentBean(dep, beanName);
try {
//获取depentceOn的bean
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
//创建单例bean
if (mbd.isSingleton()) {
//把beanName 和一个singletonFactory 并且传入一个回调对象用于回调
sharedInstance = getSingleton(beanName, () -> {
try {
//进入创建bean的逻辑
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
//创建bean的过程中发生异常,需要销毁关于当前bean的所有信息
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
getSingleton
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
/**
* 第一步:我们尝试去一级缓存(单例缓存池中去获取对象,一般情况从该map中获取的对象是直接可以使用的)
* IOC容器初始化加载单实例bean的时候第一次进来的时候 该map中一般返回空
*/
Object singletonObject = this.singletonObjects.get(beanName);
/**
* 若在第一级缓存中没有获取到对象,并且singletonsCurrentlyInCreation这个list包含该beanName
* IOC容器初始化加载单实例bean的时候第一次进来的时候 该list中一般返回空,但是循环依赖的时候可以满足该条件
*/
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
/**
* 尝试去二级缓存中获取对象(二级缓存中的对象是一个早期对象)
* 何为早期对象:就是bean刚刚调用了构造方法,还来不及给bean的属性进行赋值的对象(纯净态)
* 就是早期对象
*/
singletonObject = this.earlySingletonObjects.get(beanName);
/**
* 二级缓存中也没有获取到对象,allowEarlyReference为true(参数是有上一个方法传递进来的true)
*/
if (singletonObject == null && allowEarlyReference) {
/**
* 直接从三级缓存中获取 ObjectFactory对象 这个对接就是用来解决循环依赖的关键所在
* 在ioc后期的过程中,当bean调用了构造方法的时候,把早期对象包裹成一个ObjectFactory
* 暴露到三级缓存中
*/
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
//从三级缓存中获取到对象不为空
if (singletonFactory != null) {
/**
* 在这里通过暴露的ObjectFactory 包装对象中,通过调用他的getObject()来获取我们的早期对象
* 在这个环节中会调用到 getEarlyBeanReference()来进行后置处理
*/
singletonObject = singletonFactory.getObject();
//把早期对象放置在二级缓存,
this.earlySingletonObjects.put(beanName, singletonObject);
//ObjectFactory 包装对象从三级缓存中删除掉
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
这里的逻辑与上面的Demo示例类似的逻辑,继续往下走的源码在前面的文章中已有,这里不做赘述。
问题:
- 为什么使用二级缓存和三级缓存?上面的已讲清楚
- spring有没有解决构造函数的循环依赖?没有,因为构造函数还在实例化的过程中,连实例都没有,无法解决循环依赖。会直接报错。
- spring有没有解决多例下的循环依赖?多例创建是不存在一级缓存中,因此不能解决。