Spring循环依赖,只支持setter方式的依赖注入,不支持构造函数的依赖注入。这一点其实很好理解。
new ServiceA(new ServiceB(new ServiceA(......))));
这样会一层层的依赖下去。
public class MySpringTest1 {
public static void main(String[] args) throws InterruptedException {
//注解方式启动spring
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig1.class);
}
}
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh(); //从该方法开始进入
}
1.org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
doGetBean方法被getBean方法调用
该方法刚开始调用 getSingleton(beanName) 方法,该方法内使用三级缓存获取对象,由于该开始并没有对象被创建,所以开始时调用getSingleton(beanName) 方法返回的值为空
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
2.org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(beanName, BeanFactory<?>)
该方法在doGetBean方法中被调用(开始getSingleton(beanName) 返回的值为空,会走到这里)
该方法传入两个参数一个为 当前的beanName 令一个参数时 beanFactory,在里面会调用传入beanFactory的getObject方法返回该beanName的对象
最后将创建好的对象通过addSingleton(beanName, singletonObject);方法将bean放入到一级缓存中。
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
3.org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean(beanName, mbdToUse, args)
该方法被createBean方法调用
方法一开始调用createBeanInstance(beanName, mbd, args)方法,通过反射创建原始对象,并用instanceWrapper包装
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
总结
A 与B 对象相互依赖
A首先创建,并将A对象标记为正在创建中,然后将创建方法放到三级缓存中(factory)。创建过程中,在填充属性时发现需要B,于是去创建B(尝试从三级缓存中获取,但是获取不到),并将B也标记为正在创建中
B创建的时候,在填充属性的时候发现需要A,于是又去创建对象A,尝试从三级缓存中获取A,可以获取到,并将A放入二级缓存,于是B就成功创建了,并放入一级缓存,同时清空二三级缓存,同时返回B
返回B以后,A也成功赋值创建,就完成了A和B的创建。
面试回答:
缓存解决循环依赖的思路有两种:
第一种:不管有没有循环依赖,都提前创建好代理对象,并将代理对象放入缓存。出现循环依赖时,其它对象直接就可以取到代理对象并注入,两个级别的缓存就够了。
第二种:不提前创建好代理对象,在出现循环依赖被其它对象注入时,才实时生成代理对象。
Spring选择了后一种,如果使用两个缓存解决循环依赖,意味着Bean在构造完成后就创建代理对象,这样就违背了Spring的设计原则。Spring结合AOP和Bean的生命周期,是在Bean创建完成之后通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来完成的,在这个后置处理器的postProcessAfterInitialization方法中对初始化后的Bean完成AOP代理。使用第一种方案如果出现了循环依赖,那没有办法,只有先给Bean先创建代理,但是在Spring设计之初就是让Bean在生命周期的最后一步完成代理而不是在实例化之后就立马完成代理。
主要原因更是:在加载一个bean的时候,根本不知道他会不会有循环依赖,如果不用一个objectFactory的话,就得直接创建最终暴露的代理对象(早期bean)这样的话,没有循环依赖的情况下就是把最终暴漏的对象提前创建了(这不符合bean的一半创建流程:实例话-》填充bean【属性赋值】-〉初始化bean【代理包装】),所以说objectFactory是起到一个延迟创建bean或者是不创建bean的作用(只是提供一种可能的能力),很巧妙!
参考地址: