spring 循环依赖源码分析|8月更文挑战

139 阅读2分钟

什么是循环依赖?

很简单,就是A对象依赖了B对象,B对象依赖了A对象。

比如:

// A依赖了B  
class A{   
    public B b;
}
// B依赖了A
class B{    
    public A a;
}

解决循环依赖思路分析

A创建时--->需要B---->B去创建--->需要A,从而产生了循环
image.png

那么如何打破这个循环,加个中间人(缓存)

Image

但是这又出现了新的问题: 如果A的原始对象注入给B的属性之后,A的原始对象进行了AOP产生了一个代理对象,此时就会出现,对于A而言,它的Bean对象其实应该是AOP之后的代理对象,而B的a属性对应的并不是AOP之后的代理对象,这就产生了冲突。 举个栗子:

@Componentpublic class User {
}
@Componentpublic class LubanBeanPostProcessor implements BeanPostProcessor { 
    @Override    
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {        
    // 注意这里,生成了一个新的User对象        
    if (beanName.equals("user")) {            
            System.out.println(bean);            
            User user = new User();            
            return user;        
            }        
        return bean;    
        }
    }
public class Test {   
public static void main(String[] args) {        
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);                
    User user = context.getBean("user", User.class);        
    System.out.println(user);    
    }
}

运行main方法,得到的打印如下:

com.luban.service.User@5e025e70
com.luban.service.User@1b0375b3

所以最终的解决方案为:

() -> getEarlyBeanReference( beanName , mbd , bean )

image.png

三级缓存:

  1. singletonObjects:缓存某个beanName对应的经过了完整生命周期的bean
  2. earlySingletonObjects:缓存提前通过原始对象进行了AOP之后得到的代理对象,原始对象还没有进行属性注入和后续的BeanPostProcessor等生命周期
  3. singletonFactories:缓存的是一个ObjectFactory,也就是一个Lambda表达式。在创建一个Bean时,在每个Bean的生成过程中,都会提前暴露一个Lambda表达式,并保存到三级缓存中,这个Lambda表达式可能用到,也可能用不到,如果没有出现循环依赖依赖本bean,那么这个Lambda表达式无用,本bean按照自己的生命周期执行,执行完后直接把本bean放入singletonObjects中即可,如果出现了循环依赖依赖了本bean,则从三级缓存中获取Lambda表达式,并执行Lambda表达式得到一个AOP之后的代理对象(如果有AOP的话,如果无需AOP,则直接得到一个原始对象),并把得到的对象放入二级缓存
  4. 其实还要一个缓存,就是earlyProxyReferences,它用来记录某个原始对象是否进行过AOP了。

spring源码分析

  • 第一次创建bean对象之前调用beforeSingletonCreation(beanName)将bean对象名字添加到singletonsCurrentlyInCreation集合中
  • 第一次创建bean对象对应的类实例后调用addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))------>添加到singletonFactories中, 注意这个lamda表达式此时不会执行
  • 而在循环依赖中会第二次调用到创建bean对象时,调用getSingleton(beanName, true)时,从singletonFactories中返回对应的早期bean对象的引用,并添加到earlySingletonObjects中

AbstractBeanFactory#doGetBean()---- org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean()

sequenceDiagram
doGetBean->>getSingleton: (beanName, singletonFactory)
getSingleton->>createBean: (beanName, mbd(bean的元数据信息,包含bean的类对象,bean的类上注解,bean实际位置路径等等), args--构造函数参数一般是空的)
createBean->>doCreateBean: (beanName, mbdToUse(bean的元数据信息,包含bean的类对象,bean的类上注解,bean实际位置路径等等), args--构造函数参数一般是空的)