前言
上篇介绍了 Spring 是如何完成自动装配,但是,如果程序员这样配置 Bean
A.java
package com.playwin.bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class A {
@Autowired
private B b;
}
B.java
package com.playwin.bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class B {
@Autowired
A a;
}
A Bean 需要注入 B Bean,而 B Bean 中需要注入 A Bean。
按照上篇介绍,Spring 在 A 实例化后,开始属性注入,如果这个属性也是一个 Bean,会提前实例化。但是,B Bean 实例化也是调用 getBean 方法,同样会走到这里,难道又去实例化 A ?,然后有去实例化 B,然后 ....。
Spring 在实例化一个 Bean 前,不是会检查缓存吗,不会 把 A 存到缓存中吗?那么问题来了,在 A 注入属性 B 的时候,A 这时候是没实例化完成的,不是一个完整的 Bean,这样的半成品的 A 就放到 B 里面,还有可能 A 需要被代理,最后得到的 A,和从 B Bean 属性中的 A 不是同一个对象,这岂不是很乌龙。看来只有看源码才会得到答案。
回顾
在看源码前,先回顾一下前几篇的几处细节。
singletonsCurrentlyInCreation
在 Spring 初始化前,会调用 beforeSingletonCreation(beanName);
protected void beforeSingletonCreation(String beanName) {
// 在这正在实例化 Bean 会被加入到 singletonsCurrentlyInCreation 集合
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
把将要实例化的 Bean 添加到 singletonsCurrentlyInCreation 表示这个 Bean 正在创建,记住这一步很重要。
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
//sharedInstance = getSingleton(beanName, () -> {
// try {
// return createBean(beanName, mbd, args);
// }
// catch (BeansException ex) {
// ....
// }
// }
//);
// 返回完整的 Bean
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
}finally {
// 移出正在创建 Bean 集合
afterSingletonCreation(beanName);
}
protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
在实例化完成之后,包括属性注入,代理等,才会移除该集合。
循环依赖
这次源码可能比较跳,不是按顺序看下来,会标记好方法的。
暴露工厂
//sharedInstance = getSingleton(beanName, () -> {
// try {
// return createBean(beanName, mbd, args);
// }
// catch (BeansException ex) {
// ....
// }
// }
//);
// 返回完整的 Bean
singletonObject = singletonFactory.getObject();
这行代码会到 doCreateBean 方法
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
// 删除代码
....
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
// 删除代码
....
}
// 删除代码
....
return exposedObject;
}
有两行注释非常明显
Eagerly cache singletons to be able to resolve circular references even when triggered by lifecycle interfaces like BeanFactoryAware.
circular references 循环引用,说明这下面代码与循环依赖有关。
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));
public boolean isSingletonCurrentlyInCreation(String beanName) {
return this.singletonsCurrentlyInCreation.contains(beanName);
}
BeanDefinition 是否是单例,this.allowCircularReferences
/** Whether to automatically try to resolve circular references between beans. */
private boolean allowCircularReferences = true;
默认为 true。以及是否包含在 SingletonCurrentlyInCreation 集合中。这个 Bean 到这里仅仅是一个对象,并没有注入属性等一系列操作,所以它还在这个集合中。也就是一般情况下,这个变量 earlySingletonExposure 都是为 true。
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
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);
}
}
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
执行这行代码,Spring 把这个刚刚实例化成对象的 Bean 包装成了一个 singletonFactory 放到了 singletonFactories 集合中。
如果你到这还看不懂 Spring 为什么这么做,继续往下看。
注入 singletonFactorie
A 在执行这之后,会去注入属性,也就是上面配置 B,调用 getBean 方法,B 同样走到这里,开始注入 A,同样是调用 getBean 方法,进入 doGetBean。
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 表面意思转化 BeanName
// 把别名转为标准 BeanName
// 有关 FactoryBean BeanName 操作
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
// 从缓存中取出 Bean,BeanDefinition 实例化后都会保存到对应的缓存中
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("....");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
// BeanDefinition 未实例化,走下面逻辑
else {
// 删除代码
.....
}
return (T) bean;
}
doGetBean 最开始有一步重要的操作,从缓存中查找 Bean。
Object sharedInstance = getSingleton(beanName);
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
先从所有实例化好的 Bean 集合 singletonObjects 里拿,这时的 A 没有实例化好,还在属性注入,所以这里的 singletonObject 是空的,再判断 isSingletonCurrentlyInCreation(beanName)
这个 Bean 是否是正在创建,这时 A 也是在里面的,if
成立,进入代码块,singletonObject = this.earlySingletonObjects.get(beanName);
在 earlySingletonObjects 集合中取出来,前面在 doCreateBean 方法时缓存包装 A 对象的工厂,A 就已经从这个集合移出了,allowEarlyReference 传进来是true,Spring 写死了。ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
拿出前面在 doCreateBean 方法时缓存包装 A 对象的工厂, singletonObject = singletonFactory.getObject();
再从工厂里拿出 A,返回一个早期 A 代理引用对象。
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
总结
在单例 Bean 实例化的时候,Spring 会先暴露一个包装 A 对象的工厂,如果需要循环依赖,会从工厂中拿出 A 的引用对象,这样 A 注入完 B,引用对象也会完成。
为什么说 Spring 默认支持循环依赖?
有两个在循环依赖关键点判断的时候,allowEarlyReference 和 allowCircularReferences 属性 Spring 默认都是为 true