什么是循环依赖?
很简单,就是A对象依赖了B对象,B对象依赖了A对象。
比如:
// A依赖了B
class A{
public B b;
}
// B依赖了A
class B{
public A a;
}
解决循环依赖思路分析
A创建时--->需要B---->B去创建--->需要A,从而产生了循环
那么如何打破这个循环,加个中间人(缓存)
但是这又出现了新的问题: 如果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 )
三级缓存:
- singletonObjects:缓存某个beanName对应的经过了完整生命周期的bean
- earlySingletonObjects:缓存提前通过原始对象进行了AOP之后得到的代理对象,原始对象还没有进行属性注入和后续的BeanPostProcessor等生命周期
- singletonFactories:缓存的是一个ObjectFactory,也就是一个Lambda表达式。在创建一个Bean时,在每个Bean的生成过程中,都会提前暴露一个Lambda表达式,并保存到三级缓存中,这个Lambda表达式可能用到,也可能用不到,如果没有出现循环依赖依赖本bean,那么这个Lambda表达式无用,本bean按照自己的生命周期执行,执行完后直接把本bean放入singletonObjects中即可,如果出现了循环依赖依赖了本bean,则从三级缓存中获取Lambda表达式,并执行Lambda表达式得到一个AOP之后的代理对象(如果有AOP的话,如果无需AOP,则直接得到一个原始对象),并把得到的对象放入二级缓存
- 其实还要一个缓存,就是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--构造函数参数一般是空的)