Spring 循环依赖代码分析

一、说明:

1、当组件是单例并使用setter给属性赋值时不会出现循环依赖异常错误。如果组件不是单例或用构造器赋值都会出现循环依赖异常错误。
2、一级缓存:singletonObjects
二级缓存:earlySingletonObjects
三级缓存:singletonFactories

二、代码:

代码执行流程:
contextLoader
->configureAndRefreshWebApplicationContext
->wac.refresh();
->finishBeanFactoryInitialization(beanFactory)
->beanFactory.preInstantiateSingletons()
->getBean
->doGetBean

  • 1、从三级缓存中获取对象

Object sharedInstance = this.getSingleton(beanName);
从一级,二级,三级缓存获取bean,有以下三种情况:
1、一级获取到则返回。
2、二级获取到则返回。
3、三级获取到,放入二级缓存,从三级缓存删除,如果被代理返回代理bean,具体实现方式可以参考下面2.2.2中getEarlyBeanReference方法内的逻辑。
代码如下:
ObjectFactory singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}

  • 2、创建对象

sharedInstance = this.getSingleton(beanName, () -> {
return this.createBean(beanName, mbd, args);
});
this.getSingleton中内容如下:
2.1.this.beforeSingletonCreation(beanName);
singletonsCurrentlyInCreation(Set集合,当前正常创建的类放入集合)中放入beanName

2.2.创建bean:singletonObject = singletonFactory.getObject();进入
AbstractAutowireCapableBeanFactory.createBean(beanName, mbd, args)
->doCreateBean
2.2.1、用反射创建bean并返回,方法是:createBeanInstance
如果是使用构造器给属性赋值,此时bean并未放入三级缓存,会出现循环依赖错误。只有bean实例化结束才会执行2.2.2存入三级缓存。
2.2.2、判断是否单例,是否是正在创建的bean。这里如果@Scope(“proprety”)是不存入三级缓。所以使用@Scope(“proprety”)注解的类会出现循环依赖错误。
满足的话放入三级缓存。三级缓存中存入的是singletonFactory,其中getObject方法被实现执行getEarlyBeanReference方法,此方法返回代理对象。注意此时放入三级缓存的对象还没有给属性赋值也没执行初始化。

代码如下:
boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
if (earlySingletonExposure) {
this.addSingletonFactory(beanName, () -> {
return this.getEarlyBeanReference(beanName, mbd, bean);
});
}

2.2.3
执行属性赋值:
this.populateBean(beanName, mbd, instanceWrapper);
属性赋值的时候会调用getBean方法获取属性值。重复以上步骤。
初始化方法:
exposedObject = this.initializeBean(beanName, exposedObject, mbd);

2.3.this.singletonsCurrentlyInCreation.remove(beanName)
singletonsCurrentlyInCreation(Set集合,当前正在创建的组件名称集合)中移除beanName

2.4.this.addSingleton(beanName, singletonObject);
this.singletonObjects.put(beanName, singletonObject);
放入到了一级缓存,移除二级和三级缓存,此时缓存的bean执行了属性赋值和初始化。

三,结论

一、测试代码
@Controller
public class AController {
@Autowired
Bcontroller bcontroller;
@RequestMapping(“helloA”)
@ResponseBody
public String helloA(String name){
return name;
}
}

@Controller
public class Bcontroller {
@Autowired
AController aController;
@RequestMapping(“helloB”)
@ResponseBody
public String helloB(String name){
return name;
}
}
说明:
当Acontroller被spring容器创建时,还没执行属性赋值时把对象就放入三级缓存了以上2.2.2步,执行属性赋值会调用bcontroller的创建方法,当bcontroller执行到属性赋值的时候,会调用创建Acontroller方法,先从三级缓存里面取出,创建好bcontroller,Acontroller获取bcontroller属性后,继续创建完成。

你可能感兴趣的:(笔记,spring)