Spring循环依赖注入流程分析
我们在使用Spring做开发的时候经常会遇到以下这种情况,CircularRefA 对象里面需要注入CircularRefB,CircularRefB对象里面需要依赖注入CircularRefA 。代码如下:
@Component
public class CircularRefA {
@Autowired
private CircularRefB circularRefB;
}
@Component
public class CircularRefB {
@Autowired
private CircularRefA circularRefA;
}
我们开始吧,假设Spring容器先触发beanFactory.get("circularRefA ") 这个动作。
circularRefA 第一次doGetBean
//获取一个bean实例
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// 1、这个方法很重要要去看看,作用就是从缓冲中拿bean实例
Object sharedInstance = getSingleton(beanName);
// 2、如果缓存里面能拿到实例
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
//省略....
}
}
// 改方法是FactoryBean接口的调用入口
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
//省略....
}
getSingleton
这个方法循环依赖的关键点之一,所以我把代码贴出来,小伙伴留意下三级缓存这个东东。
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) {
// 三级缓存调用getObject()
singletonObject = singletonFactory.getObject();
// 三级缓存升级到二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
// 移除三级缓冲
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
其实这段方法没啥代码逻辑的,就是根据beanName去缓存里面获取实例,如果存在实例就直接返回,不存在就返回一个null 。
很显然circularRefA第一次进来,肯定获取到null ,那么代码继续往下执行。
if (mbd.isSingleton()) {
// 我们转到定义,看看这个方法里面的一些代码逻辑 , 这个方法的第二个参数是一个匿名ObjectFactory接口实现类 ,这个要理解
sharedInstance = getSingleton(beanName, () -> {
try {
// 创建bean
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
// 这方法是FactoryBean接口的调用入口
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 获取circularRefA 实例
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,"代码太多了我把这些删了");
}
if (logger.isDebugEnabled()) {
logger.debug("代码太多了我把这些删了" + beanName + "'");
}
// 1、把beanName 加入到singletonsCurrentlyInCreation Set集合中,标志beanName正在创建
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
//2、这个就是调用刚才介绍的-匿名ObjectFactory接口实现类方法,
// 换句话说就是调用到createBean() 方法
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 3、当前beanName实例创建完成后,把beanName从singletonsCurrentlyInCreation Set集合中移除
afterSingletonCreation(beanName);
}
// 4、如果这个是新创建的对象,就要把这个对象放入到singletonObjects 缓存中,
// 移除 earlySingletonObjects、singletonFactories缓存中对应的实例
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
上面的getSingleton() 这个方法看了下,也没啥负载的逻辑。
第一步:beforeSingletonCreation() 把“circularRefA” 放入到 singletonsCurrentlyInCreation Set集合中,标志"circularRefA" 正在创建。
第二步:就调用singletonFactory.getObject() 得到"circularRefA" 实例,也就是调用createBean() 方法。
doCreateBean
我们就直接去看createBean() -> doCreateBean() ,doCreateBean() 方法我也只贴依赖注入的核心代码。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 1、创建bean实例
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
//2、来收集bean需要注入的(方法、属性)并且封装成Metadata对象存入缓存中
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// 是否 单例bean提前暴露
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");
}
// 3、这个就是添加三级缓存的地方 ( () -> getEarlyBeanReference(beanName, mbd, bean) ) lamda表达式 , getEarlyBeanReference() 得到一个 ObjectFactory<?>对象
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
// 4、populateBean方法做依赖注入
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// 省略 ...
return exposedObject;
}
//添加三级缓存
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
// 将singletonFactory添加到三级缓存
this.singletonFactories.put(beanName, singletonFactory);
// 移除二级缓冲
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
“circularRefA” 第一次进入doCreateBean 主要做了如下事情:
-
调用createBeanInstance方法创建了一个CircularRefA 对象实例,这个时候circularRefA 实例是一个半成品,它的属性还没做依赖注入
-
来收集bean需要注入的(方法、属性)并且封装成Metadata对象存入缓存中
-
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean) ) ,第二个参数就是一个 ObjectFactory 接口的匿名实现类 ,将其放入三级缓存 singletonFactories 中
-
populateBean() 做依赖注入,因为"circularRefA" 对象了需要注入一个 CircularRefB 实例对象 。在这里依赖注入CircularRefB 实例对象会触发 beanFactory.getBean(“circularRefB”) 操作,然后将其结果反射复制到circularRefA对象中。
既然触发到beanFactory.getBean(“circularRefB”)操作,是不是又回到getBean方法的起始点 ?
circularRefB 第一次doGetBean
很显然circularRefB第一次进来,走的流程跟circularRefA是一模一样的 。这个要想得通,这个想不通下面就不要看了 。
接下来到了CircularRefB实例做依赖注入circularRefA对象的时候,同样也会触发beanFactory.getBean(“circularRefA”) 的操作 。
circularRefA 第二次doGetBean
circularRefA 第二次进入了doGetBean() ,同样执行下面的这段代码。代码如下:
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("代码太多直接删除了");
}
else {
logger.trace("代码太多直接删除了");
}
}
// 这方法是FactoryBean接口的调用入口
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
第二次进入getSingleton() 去获取circularRefA 跟第一次进入getSingleton() 获取circularRefA 不同的地方是:“第二次进入getSingleton() 方法的时候,singletonFactories有相应的缓存对象信息了 ” 。这个三级缓存设置上面介绍了 ,内容如下:
我还是把getSingleton() 方法在贴出来,看起来方便一点,代码如下:
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) {
// 三级缓存调用getObject()
singletonObject = singletonFactory.getObject();
// 三级缓存升级到二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
// 移除三级缓冲
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
既然在三级缓存里面能获取到 ObjectFactory接口实现类对象,singletonFactory.getObject() 获取"circularRefA" 实例就是调用到
其实getEarlyBeanReference() 这个方法啥事情也没做,就把前面介绍的 半成品 circularRefA 返回回去
总结
-
既然成功的拿到【circularRefA】实例,大家在回头想想是不是circularRefB实例要做依赖注入,才引发了beanFactory.getBean(“circularRefA”) 操作。现在 circularRefA 实例已经创建好了( 这个时候circularRefA 还是一个半成品的,circularRefA对象中 circularRefB字段里面还是为NULL ),那么circularRefB 依赖注入是不是可以顺利完成 。 circularRefB依赖注入完成,换句话说circularRefB对应的bean也就创建成功了。
-
大家在回头想想是不是circularRefA实例要依赖注入circularRefB,才引发了beanFactory.getBean(“circularRefB”) 操作 。现在circularRefB 实例创建完成了,circularRefA 依赖注入操作是不是也顺利完成了 。此时的circularRefA 实例不再是半成品的。
-
circularRefA 实例既然不是半成品 ,circularRefB对象中的 【circularRefA】 属性引用的 CircularRefA对象也是一个完整的实例( 它们引用的是同一块内存地址 )
-
要了解createBean() 流程可参考这篇文章