Spring源码分析——循环依赖
Spring源码分析——循环依赖
在spring中,涉及到一个概念,叫做循环依赖,或者叫做循环引用。意思就是说,一个bean他的属性,依赖了另外一个bean,而他所依赖的bean,有恰好依赖与他。这种情况下,spring对此做了特殊处理,但是仅限于单例模式。
具体流程
处理循环依赖的具体流程,首先是在一个bean实例化后初始化前,如果判断判断符合循环依赖的条件,则提前把他暴露出去,但是不是暴露这个bean,而是封装成一个ObjectFactory对象,存放到二级缓存singletonFactories中,他的类型是Map<String,ObjectFactory<?>>。接下来在属性注入的端,发现他依赖了另外一个bean,那么又会去getBean进行bean的创建和初始化,然后同样也在实例后初始化前把他封装为ObjectFactory对象,放入二级缓存,然后就进行属性注入。而他又回过头来依赖了原来的bean,所有又调用了getBean获取原来的bean,这是后getBean一进来,从二级缓存中取到了,就不会往下进行这个bean的实例化了,然后完成了先把他赋值个第二个bean的成员变量,然后原来的bean也完成属性注入和初始化回调。
具体步骤:
- A依赖了B,B又依赖A
- getBean(A),创建A
- 判断符合循环依赖条件,把A的ObjectFactory对象放入二级缓存,这个对象的getObject方法,会返回A
- 进行属性注入
- 发现依赖了B,getBean(B),进行B的创建
- B也走了上面1-5步
- B 依赖了 A,所以A又调用 getBean(A)
- 这是二级缓存中已经存了A的ObjectFactory,就调用ObjectFactory的getObject方法,返回A,不再继续往下进行实例化
- B 先完成属性注入和初始化回调
- A 也完成属性注入和初始化回调
尝试从缓存中获取的具体流程
在调用getBean方法创建或后取一个bean是,首先会去缓存中取,如果从三个缓存池的随便一个当中取到了,就不会往下进行实例化。
getBean或走到doGetBean方法,然后里面有一行代码,是关于从缓存中尝试获取bean的逻辑
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
/**
* 尝试从BeanFactory的三个缓存池中获取该bean
* 获取得到则返回,不走下面的创建初始化方法。
* 此处作用:
* 1.给已经创建过的bean,再调getBean是获取该bean
* 2.处理循环依赖时返回该bean的半成品(已创建未初始化)
*/
Object sharedInstance = getSingleton(beanName);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
已经完成初始化的bean,以及循环依赖时提前暴露的bean,在这里都可以获取到,不管是哪一种,只要获取到了,就不会往下进行重复的实例化工作。
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String)
@Override
@Nullable
public Object getSingleton(String beanName) {
/* allowEarlyReference为true表示允许循环引用 */
return getSingleton(beanName, true);
}
- 1
- 2
- 3
- 4
- 5
- 6
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
/*如果从一级缓存取到则直接返回,一般出现在获取已经完成的bean,或者单向引用 */
Object singletonObject = this.singletonObjects.get(beanName);
/*获取不到且当前beanName对应的Bean正在创建中(实例化后初始化前)*/
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
/*先从三级缓存中取*/
singletonObject = this.earlySingletonObjects.get(beanName);
/*三级完成取不到 && 允许循环引用*/
if (singletonObject == null && allowEarlyReference) {
/*从二级缓存中获取当前Bean对应的ObjectFactory */
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
/*获取到了,则调用getObject,获取当前正在创建中的对象*/
singletonObject = singletonFactory.getObject();
/*添加到三级缓存*/
this.earlySingletonObjects.put(beanName, singletonObject);
/*从二级缓存中删除,下次就直接从二级缓存中取了*/
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
这里可以看到spring的三个缓存次,singletonObjects-一级缓存池,也就是俗称的单例缓存池,singletonFactories-二级缓存池,earlySingletonObjects-三级缓存池,他们的类型全都是map,key就是beanName
- 从一级缓存取singletonObjects到则直接返回
- 从一级缓存去不到,如果运行循环引用,就从三级缓存池earlySingletonObjects中取,取到了直接返回
- 从二级缓存取不到,就从二级缓存singletonFactories中取,如果去到了,就调用取出来的ObjectFactory对象singletonFactory 的getObject方法,返回实例化后初始化前的bean,并且放入三级缓存,从二级缓存中删除
这里为什么要有三级缓存呢,而且二级缓存取出来的不是Object,而是ObjectFactory?这里先把问题留着,我们可以往下看,在进行提前暴露处理时,看看放入singletonFactories的ObjectFactory对象里面getObject方法的具体实现,就会有答案。
是否循环依赖依赖的判断
如果从缓存总没取到bean,就会进入doCreateBean方法,进行bean的创建在bean创建完成以后,会有一步是否运行循环依赖的判断
/**
* createBeanInstance(beanName, mbd, args)实例化后,初始化前
* 判断是否支持循环引用,是否单例 && 支持循环引用 && 正在创建中(beanName在singletonsCurrentlyInCreation中)
* this.allowCircularReferences默认为true
* 这里为了解决循环引用,先缓存一个工厂,存放实例化后初始化前的单例
* org.springframework.beans.factory.ObjectFactory<T>
* T getObject()
*/
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- bean是否单例模式,默认肯定是单例
- 支持循环依赖,默认也是支持的
- bean是否正在创建中,这个是在调用creatBean方法前,会先把他的beanName放入一个set的集合(singletonsCurrentlyInCreation)中,标记为正在创建
所以如无意外,肯定成立
条件成立成立举进入提前暴露的处理阶段
提前暴露处理
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
/*在二级缓存中,存放当前bean对应的工厂*/
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
addSingletonFactory就是把当前正在创建的bean提前暴露的处理,key是beanName,value是ObjectFactory对象
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
/**
* singletonObjects是BeanFactory中的三级缓存,Map<String, Object>
* 专门缓存ObjectFactory,也就是俗称的Bean半成品,
* 实际上是个工厂,调用getObject就会返回该创建中的bean
*/
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
/*把ObjectFactory保存到singletonFactories中 */
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
回到刚刚的地方,可以看到ObjectFactory的getObject方法,这里调用的是getEarlyBeanReference方法
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
- 1
那么到时候从二级缓存获取到该ObjectFactory对象后,调用getObject方法时,就会去调用getEarlyBeanReference方法,那么我们看看getEarlyBeanReference的具体操作
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
/*判断:不是一个合成的Bean && BeanFactory中存在InstantiationAwareBeanPostProcessors*/
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
/*遍历所有的SmartInstantiationAwareBeanPostProcessor,执行getEarlyBeanReference方法,返回一个有可能被修改后的bean */
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
// 所以利用SmartInstantiationAwareBeanPostProcessor可以改变一下提前暴露的对象
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
return exposedObject;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
可以看到,他不是单纯的返回该bean。在返回该bean前,会先进行bean后置处理器的处理。这里所有的SmartInstantiationAwareBeanPostProcessor接口的实现类的getEarlyBeanReference方法可以得到回调。我们随便挑一个他的实现了看看
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getEarlyBeanReference
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
- 1
- 2
- 3
- 4
- 5
- 6
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
<span class="token comment">// 如果该类有advice则创建proxy.</span> Object<span class="token punctuation">[</span><span class="token punctuation">]</span> specificInterceptors <span class="token operator">=</span> <span class="token function">getAdvicesAndAdvisorsForBean</span><span class="token punctuation">(</span>bean<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> beanName<span class="token punctuation">,</span> null<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>specificInterceptors <span class="token operator">!=</span> DO_NOT_PROXY<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>advisedBeans<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>cacheKey<span class="token punctuation">,</span> Boolean<span class="token punctuation">.</span>TRUE<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 创建代理对象 */</span> Object proxy <span class="token operator">=</span> <span class="token function">createProxy</span><span class="token punctuation">(</span> bean<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> beanName<span class="token punctuation">,</span> specificInterceptors<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">SingletonTargetSource</span><span class="token punctuation">(</span>bean<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>proxyTypes<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>cacheKey<span class="token punctuation">,</span> proxy<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 返回代理对象 */</span> <span class="token keyword">return</span> proxy<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">this</span><span class="token punctuation">.</span>advisedBeans<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>cacheKey<span class="token punctuation">,</span> Boolean<span class="token punctuation">.</span>FALSE<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> bean<span class="token punctuation">;</span> <span class="token punctuation">}</span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
可以看到,这里返回的有可能是个代理对象,那么我么取到的就不是原来的bean,而是原来bean的代理对象了。
这也回答了刚刚那个问题:
这里为什么要有三级缓存呢,而且二级缓存取出来的不是Object,而是ObjectFactory?这里先把问题留着,我们可以往下看,在进行提前暴露处理时,看看放入singletonFactories的ObjectFactory对象里面getObject方法的具体实现,就会有答案。
二级缓存存的是个ObjectFactory,那是因为调用他的getObject方法,返回的不一定是原来的bean,spring会在里面进行一些bean后置处理器的回调工作,允许修改该bean,或返回一个代理对象。getObject后返回的对象,又存的三级缓存中,从二级缓存删除,是因为不再进行重复的回调,这里返回经过处理后的对象,以后就从三级缓存中取了,没有必要进行重复处理。
属性注入触发getBean的位置
在doCreatBean方法中,创建完该bean,提前暴露完后。就会进行属性注入
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
// 这一步也是非常关键的,这一步负责属性装配,因为前面的实例只是实例化了,并没有设值,这里就是设值
// 并且标注了@PostConstruct的方法,也会在此调用,属于初始化回调
populateBean(beanName, mbd, instanceWrapper);
- 1
- 2
- 3
进入populateBean(beanName, mbd, instanceWrapper),首先声明,下面的方法有点长,因为涉及到不用类型的属性注入,不用从头到尾看,我们挑其中一个方法看就行了
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { if (bw == null) { if (mbd.hasPropertyValues()) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance"); } else { // Skip property population phase for null instance. return; } }
<span class="token comment">// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the</span> <span class="token comment">// state of the bean before properties are set. This can be used, for example,</span> <span class="token comment">// to support styles of field injection.</span> <span class="token comment">// 到这步的时候,bean 实例化完成(通过工厂方法或构造方法),但是还没开始属性设值,</span> <span class="token comment">// InstantiationAwareBeanPostProcessor 的实现类可以在这里对 bean 进行状态修改</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>mbd<span class="token punctuation">.</span><span class="token function">isSynthetic</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token function">hasInstantiationAwareBeanPostProcessors</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">for</span> <span class="token punctuation">(</span>InstantiationAwareBeanPostProcessor bp <span class="token operator">:</span> <span class="token function">getBeanPostProcessorCache</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>instantiationAware<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token comment">// 调用InstantiationAwareBeanPostProcessor实现类的postProcessAfterInstantiation方法</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>bp<span class="token punctuation">.</span><span class="token function">postProcessAfterInstantiation</span><span class="token punctuation">(</span>bw<span class="token punctuation">.</span><span class="token function">getWrappedInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> beanName<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token comment">// 如果返回 false,代表不需要进行后续的属性设值,也不需要再经过其他的 BeanPostProcessor 的处理</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// bean 实例的所有属性都在这里了</span> PropertyValues pvs <span class="token operator">=</span> <span class="token punctuation">(</span>mbd<span class="token punctuation">.</span><span class="token function">hasPropertyValues</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">?</span> mbd<span class="token punctuation">.</span><span class="token function">getPropertyValues</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">:</span> null<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">int</span> resolvedAutowireMode <span class="token operator">=</span> mbd<span class="token punctuation">.</span><span class="token function">getResolvedAutowireMode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 如果自动装配类型为1-byName 或 2-byType 则进入此分支 但这里是标签形式的,不是注解@Autowire</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>resolvedAutowireMode <span class="token operator">==</span> AUTOWIRE_BY_NAME <span class="token operator">||</span> resolvedAutowireMode <span class="token operator">==</span> AUTOWIRE_BY_TYPE<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> MutablePropertyValues newPvs <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MutablePropertyValues</span><span class="token punctuation">(</span>pvs<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 1-AUTOWIRE_BY_NAME 通过名字找到所有属性值,如果是 bean 依赖,先初始化依赖的 bean。记录依赖关系</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>resolvedAutowireMode <span class="token operator">==</span> AUTOWIRE_BY_NAME<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token function">autowireByName</span><span class="token punctuation">(</span>beanName<span class="token punctuation">,</span> mbd<span class="token punctuation">,</span> bw<span class="token punctuation">,</span> newPvs<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// 2-AUTOWIRE_BY_TYPE 通过类型装配。复杂一些</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>resolvedAutowireMode <span class="token operator">==</span> AUTOWIRE_BY_TYPE<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token function">autowireByType</span><span class="token punctuation">(</span>beanName<span class="token punctuation">,</span> mbd<span class="token punctuation">,</span> bw<span class="token punctuation">,</span> newPvs<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> pvs <span class="token operator">=</span> newPvs<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">boolean</span> hasInstAwareBpps <span class="token operator">=</span> <span class="token function">hasInstantiationAwareBeanPostProcessors</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">boolean</span> needsDepCheck <span class="token operator">=</span> <span class="token punctuation">(</span>mbd<span class="token punctuation">.</span><span class="token function">getDependencyCheck</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> AbstractBeanDefinition<span class="token punctuation">.</span>DEPENDENCY_CHECK_NONE<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 通过BeanPostProcessor完成注解版的自动装配 */</span> PropertyDescriptor<span class="token punctuation">[</span><span class="token punctuation">]</span> filteredPds <span class="token operator">=</span> null<span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>hasInstAwareBpps<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">if</span> <span class="token punctuation">(</span>pvs <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> pvs <span class="token operator">=</span> mbd<span class="token punctuation">.</span><span class="token function">getPropertyValues</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>InstantiationAwareBeanPostProcessor bp <span class="token operator">:</span> <span class="token function">getBeanPostProcessorCache</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>instantiationAware<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> PropertyValues pvsToUse <span class="token operator">=</span> bp<span class="token punctuation">.</span><span class="token function">postProcessProperties</span><span class="token punctuation">(</span>pvs<span class="token punctuation">,</span> bw<span class="token punctuation">.</span><span class="token function">getWrappedInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> beanName<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>pvsToUse <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">if</span> <span class="token punctuation">(</span>filteredPds <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> filteredPds <span class="token operator">=</span> <span class="token function">filterPropertyDescriptorsForDependencyCheck</span><span class="token punctuation">(</span>bw<span class="token punctuation">,</span> mbd<span class="token punctuation">.</span>allowCaching<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// 这里有个非常有用的 BeanPostProcessor 进到这里: AutowiredAnnotationBeanPostProcessor</span> <span class="token comment">// 对采用 @Autowired、@Value 注解的依赖进行设值,这里的内容也是非常丰富的</span> pvsToUse <span class="token operator">=</span> bp<span class="token punctuation">.</span><span class="token function">postProcessPropertyValues</span><span class="token punctuation">(</span>pvs<span class="token punctuation">,</span> filteredPds<span class="token punctuation">,</span> bw<span class="token punctuation">.</span><span class="token function">getWrappedInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> beanName<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>pvsToUse <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> pvs <span class="token operator">=</span> pvsToUse<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>needsDepCheck<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">if</span> <span class="token punctuation">(</span>filteredPds <span class="token operator">==</span> null<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> filteredPds <span class="token operator">=</span> <span class="token function">filterPropertyDescriptorsForDependencyCheck</span><span class="token punctuation">(</span>bw<span class="token punctuation">,</span> mbd<span class="token punctuation">.</span>allowCaching<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">checkDependencies</span><span class="token punctuation">(</span>beanName<span class="token punctuation">,</span> mbd<span class="token punctuation">,</span> filteredPds<span class="token punctuation">,</span> pvs<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>pvs <span class="token operator">!=</span> null<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token comment">// 设置 bean 实例的属性值</span> <span class="token function">applyPropertyValues</span><span class="token punctuation">(</span>beanName<span class="token punctuation">,</span> mbd<span class="token punctuation">,</span> bw<span class="token punctuation">,</span> pvs<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
我们看autowireByName(beanName, mbd, bw, newPvs)方法,其他的可以忽略
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#autowireByName
protected void autowireByName( String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
String<span class="token punctuation">[</span><span class="token punctuation">]</span> propertyNames <span class="token operator">=</span> <span class="token function">unsatisfiedNonSimpleProperties</span><span class="token punctuation">(</span>mbd<span class="token punctuation">,</span> bw<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>String propertyName <span class="token operator">:</span> propertyNames<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">containsBean</span><span class="token punctuation">(</span>propertyName<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token comment">/** * 属性注入,getBean获取依赖的Bean,有可能没有,需要创建 * 有可能已经创建完成,直接从一级缓存singleObjects中获取, * 或者涉及到循环引用,从三级缓存SingletonFactoryes中获取 */</span> Object bean <span class="token operator">=</span> <span class="token function">getBean</span><span class="token punctuation">(</span>propertyName<span class="token punctuation">)</span><span class="token punctuation">;</span> pvs<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>propertyName<span class="token punctuation">,</span> bean<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/*注册一下依赖关系*/</span> <span class="token function">registerDependentBean</span><span class="token punctuation">(</span>propertyName<span class="token punctuation">,</span> beanName<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>logger<span class="token punctuation">.</span><span class="token function">isTraceEnabled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">if</span> <span class="token punctuation">(</span>logger<span class="token punctuation">.</span><span class="token function">isTraceEnabled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
可以看到里面有调用了getBean方法,获取或创建依赖的bean。
这时就会进行依赖的bean的创建,然后依赖的bean也走了相同的流程,在进入原来的bean的getBean方法,就可以从二级缓存中获取到该bean的ObjectFactory对象,然后调用getObject方法,获取到该bean的半成品。
- A依赖了B,B又依赖A
- getBean(A),创建A
- 判断符合循环依赖条件,把A的ObjectFactory对象放入二级缓存,这个对象的getObject方法,会返回A
- 进行属性注入
- 发现依赖了B,getBean(B),进行B的创建
- B也走了上面1-5步
- B 依赖了 A,所以A又调用 getBean(A)
- 这是二级缓存中已经存了A的ObjectFactory,就调用ObjectFactory的getObject方法,返回A,不再继续往下进行实例化
- B 先完成属性注入和初始化回调
- A 也完成属性注入和初始化回调
一般循环依赖分析到这里就结束了,但其实下面还有一步
循环引用完成后对bean的类型进行判断
在doCreateBean方法中差不多结尾处,有这么一段长长的方法
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
/**
* 这里也涉及循环引用的问题:
* 此时该bean已经实例化完成,执行了BeanPostProcesser的两个回调方法,
* 有可能该Bean的类型已经改变,也就是说和他实例化时的类型不一致,
* 因为循环引用是在该bean在实例化后初始化前提前暴露,让别的bean引用而完成的
* 此时已经是该bean初始化完成,如果类型不一致,又检测到有其他已经创建完成的bean依赖了这个bean,就会报错
*/
if (earlySingletonExposure) {
// 尝试从缓存中获取单例,注意后面的参数为false,表示不从第三级缓存singletonFactories中获取,为什么呢?因为这里不允许循环依赖
Object earlySingletonReference = getSingleton(beanName, false);
//如果不为null,就会进入if条件中,因为earlySingletonReference不为null,说明存在循环引用,
//为什么呢?因为第一个处理的时候,会将引用放到singletonFactories缓存中,当循环依赖注入的时候,
//会通过singletonFactories中拿到提前暴露的引用,然后放到第二级缓存earlySingletonObjects中。
//所以,在这里拿到了earlySingletonReference,表明存在循环引用。
if (earlySingletonReference != null) {
//如果相等,那么就什么也不做,将earlySingletonReference返回回去即可
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
/**
* 下面就是类型不相等的处理
* 类型不相等 && 已经有创建完成的bean依赖此Bean
* 满足这两个条件,就报错
*/
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
因为在循环引用中,先完成初始化的bean引用到的bean是未完成初始化的bean,而初始化回调有可能修改了该bean的类型,但是先完成初始化的bean因为已经完成了实例化和初始化的整个工作,可以认为已经投入使用中了,这时是不允许他的引用的对象类型发生改变的,否则先完成初始化的bean所引用的bean的类型,跟单例缓存池中的存放的类型就不一致了,也就是不是同一个对象了。