单例bean循环依赖:
先创建ABean
1.0. 记录正在创建ABean singletonCurrentlyInCreation<ABean>
1.1.实例化ABean–>得到一个对象–>存入singletonFactories
1.2. 填充BBean属性–>去单例池找BBean–>没有就创建
1.3. 进行其他依赖注入
1.4. 初始化前,初始化
1.5. 初始化后
1.6. 放入单例池
创建BBean
2.1. 实例化BBean–>得到一个对象
2.2. 填充ABean属性–>去单例池找ABean–>没有就判断creatingSet–>出现循环依赖–>earlySingletonObjects–>singletonFactories–>Lambda表达式–>执行–> 执行结果创建ABean代理对象或者ABean原始对象,存入earlySingletonObject
2.3. 进行其他依赖注入
2.4. 初始化前,初始化
2.5. 初始化后
2.6. 放入单例池
创建CBean
3.1. 实例化BBean–>得到一个对象
3.2. 填充ABean属性–>去单例池找ABean–>没有就判断creatingSet–>出现循环依赖–>从earlySingletonObjec获取ABean
3.3. 进行其他依赖注入
3.4. 初始化前,初始化
3.5. 初始化后
3.6. 放入单例池
在ABean执行到1.2时会去创建BBean,进入到BBean的生命周期,造成循环依赖
spring为了解决循环依赖进行了三级缓存
1.singletonObjects 单例池
2.earlySingletonObjects 没有经过完整生命周期的单例对象,主要作用时保存单例bean对象,而跳出循环依赖
3.singletonFactories 实例化后没有经过依赖注入的对象,主要作用时生成单例bena对象,并将其存入earlySingletonObjects
//this.getEarlyBeanReference(beanName, mbd, bean)判断是否需要AOP,需要返回AOP代理对象,否则返回原始对象
//该逻辑在bean对象实例化后,依赖注入前
this.addSingletonFactory(beanName, () -> {return this.getEarlyBeanReference(beanName, mbd, bean);});
辅助
- singletonCurrentlyInCreation
- earlyProxyReferences
@Nullable
//从单例池获取bean
protected Object getSingleton(String beanName, boolean allowEarlyReference) {Object singletonObject = this.singletonObjects.get(beanName);//判断bean是否在创建中if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {//从二级缓存earlySingletonObjects中获取bean对象singletonObject = this.earlySingletonObjects.get(beanName);//没有获取到bean对象并且允许循环依赖if (singletonObject == null && allowEarlyReference) {synchronized(this.singletonObjects) {singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {//从二级缓存earlySingletonObjects中获取bean对象singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null) {//从三级缓存singletonFactories中获取singletonFactory对象ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);if (singletonFactory != null) {//执行获取bean对象的逻辑singletonObject = singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}}}return singletonObject;
}
初始化后生成的代理对象和循环依赖生成的AOP代理对象不同导致的问题:
//以下逻辑在bean实例化之后
boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);if (earlySingletonExposure) {if (this.logger.isTraceEnabled()) {this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");}//进行三级缓存this.addSingletonFactory(beanName, () -> {return this.getEarlyBeanReference(beanName, mbd, bean);});}Object exposedObject = bean;try {//依赖注入this.populateBean(beanName, mbd, instanceWrapper);//bean初始化,返回bean对象,如果bean因为AOP以外的代理对象生成,且返回的是该对象exposedObject = this.initializeBean(beanName, exposedObject, mbd);} catch (Throwable var18) {if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {throw (BeanCreationException)var18;}throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);}if (earlySingletonExposure) {//从单例池拿bean对象,如果因为循环依赖则会从二级缓存中拿到AOP生成的代理对象Object earlySingletonReference = this.getSingleton(beanName, false);if (earlySingletonReference != null) {//如果是循环依赖生成的earlySingletonReference,判断exposedObject是否非AOP代理对象if (exposedObject == bean) {exposedObject = earlySingletonReference;} else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {String[] dependentBeans = this.getDependentBeans(beanName);Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);String[] var12 = dependentBeans;int var13 = dependentBeans.length;for(int var14 = 0; var14 < var13; ++var14) {String dependentBean = var12[var14];if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);}}//如果是不同的代理对象,则提示ERROR(避免最后生成的对象不是AOP代理对象,但是循环依赖的BBean依赖注入的是ABean因为AOP生成的代理对象,可以通过在ABean的BBean属性上添加@Laze,则ABean中添加@Async(某些PostProcessor会新生成代理对象,@Transactional不是实现PostProcessor生成代理对象,则不会出现问题)的方法也不会抛出ERROR)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.");}}}}
@Lazy解决循环依赖
@Lazy注解会在bean进行依赖注入(以上步骤的第二步)时生成一个代理对象,不会影响bean之后的流程,则不会出现循环依赖。
原型bean循环依赖
原型bean无法解决循环依赖问题。
构造器的循环依赖
无法实例化对应bean则直接提示ERROR,可在构造器加@Lazy解决。