Spring —— 循环依赖
Spring Bean默认都是以单例的形式存在,但是也支持prototype形式,这里主要介绍单例Bean。
示例
@Component
public class X {
@Autowired
private Y y;
public X() {
System.out.println("X construct...");
}
}
@Component
public class Y {
@Autowired
private X x;
public Y() {
System.out.println("Y construct...");
}
}
@Configuration
@ComponentScan("com.ljc")
public class AppConfig {
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
context.getBean(X.class);
// 优雅关闭,SpringWEB中已有相关实现
context.registerShutdownHook();
}
Bean循环依赖过程
getSingleton
方法时获取单例Bean的方法,其中包含了对象正在创建的标记、对象的创建和初始化、对象放入单例缓冲几个重要步骤。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
// 使用单例对象的高速缓存Map作为锁,保证线程同步
synchronized (this.singletonObjects) {
// 从单例对象的高速缓存Map中获取beanName对应的单例对象
Object singletonObject = this.singletonObjects.get(beanName);
// 如果单例对象获取不到
if (singletonObject == null) {
// 循环依赖提前标记
beforeSingletonCreation(beanName);
boolean newSingleton = false;
try {
// 从单例工厂中获取对象,如果还未创建,会创建一个实例
singletonObject = singletonFactory.getObject();
// 生成了新的单例对象的标记为true,表示生成了新的单例对象
newSingleton = true;
}
if (newSingleton) {
// 放生成的bean放入单例缓存中
addSingleton(beanName, singletonObject);
}
}
// 返回该单例对象
return singletonObject;
}
}
beforeSingletonCreation(beanName)
会在实例化对象前将beanName放入到一个Set集合中,表明当前bean处于创建过程。
接着就是在执行singletonFactory.getObject();
方法时,如果不存在对象就会创建一个对象。
下面是创建Bean的最主要方法,这里只罗列的部分较为重要的代码:
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
BeanWrapper instanceWrapper = null;
// 获取factoryBean实例缓存
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 没有就创建实例, 这里通过newInstance创建对象
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 判断当前bean是否需要提前曝光:单例&允许循环依赖&当前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");
}
// 为避免后期循环依赖,可以在bean初始化完成前将创建实例的ObjectFactory加入工厂
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
// 属性渲染
populateBean(beanName, mbd, instanceWrapper);
// 执行初始化init方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
}
}
当从factoryBeanInstanceCache
缓存中取不到相关的Bean时,就会通过createBeanInstance
方法创建一个Object对象(这里还不能说是一个Bean对象,因为只是通过反射实例化出了一个对象,并没有进行过属性渲染,执行初始化方法等步骤);
后面根据isSingleton() && allowCircularReferences &&isSingletonCurrentlyInCreation(beanName))三个boolean值来判断是否开启循环依赖,其中isSingleton()
和 isSingletonCurrentlyInCreation(beanName))
在单例对象中都是会返回true,所以一般可以通过修改allowCircularReferences
的值来设置是否开启循环依赖,而默认是为true,即支持循环依赖。
当earlySingletonExposure为true时执行下面方法
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) {
// 如果单例对象的高速缓存【beam名称-bean实例】没有beanName的对象
if (!this.singletonObjects.containsKey(beanName)) {
// 将beanName,singletonFactory放到单例工厂的缓存【bean名称 - ObjectFactory】
this.singletonFactories.put(beanName, singletonFactory);
// 从早期单例对象的高速缓存【bean名称-bean实例】 移除beanName的相关缓存对象
this.earlySingletonObjects.remove(beanName);
// 将beanName添加已注册的单例集中
this.registeredSingletons.add(beanName);
}
}
}
该方法会将一个singletonFactory
放入到singletonFactories
Map中,然后从earlySingletonObjects删除。这里就是常说的对象的提前暴露。
这个singletonFactory其实就是之前实例化生成的对象经过几层包装生成的ObjectFactory对象,这里之所以不直接将生成的bean对象放入到Map中,是因为该对象还不是最终的Bean,后续还要经历一些生命周期,例如AOP增强,最终生成一个代理对象。
添加到Map后就会调用populateBean
方法,这里就是产生依赖注入环节的地方。