循环依赖就是bean之间相互引用,如用户bean与角色bean相互持有对方的引用,IOC容器创建好用户bean后要为角色属性赋值,然后就要新建一个角色bean然后为其属性赋值后再提供给用户bean使用,但这时角色bean的属性包括用户。这就是循环依赖的问题,IOC容器已经做好了设计解决这个问题。解决方法主要是加了3级缓存。
- singletonObjects:一级缓存,保存完全初始化好的bean。
- earlySingletonObjects:二级缓存,保存创建好但没完成属性赋值的bean。
- singletonFactories,三级循环,存放用来获取单例bean的工厂。
- singletonsCurrentlyInCreation,存放正在创建的bean的名称。
这几个是DefaultSingletonBeanRegistry的成员属性,DefaultListableBeanFactory继承后,容器就有了管理循环依赖的能力。
考察下基于@Autowired的循环依赖
通过一个案例来说明这种情况。创建用户类User和角色类Role,User中用@Autowired注入Role类型属性,Role中用@Autowired注入User类型属性。然后添加测试类,创建ApplicationConxt时会刷新容器,触发bean创建。
@Component
public class User {
@Autowired
Role role;
}
@Component
public class Role {
@Autowired
User user;
}
测试类:
package org.cosmos.spring.circular;
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext("org.cosmos.spring.circular");
}
}
1.1 初始化Role
IOC容器先初始化字母表排序靠前的Role
1.1.1 getSingleton
执行流程:preInstantiateSingletons->getBean->doGetBean,doGetBean执行到getSingleton时有控制循环依赖的地方。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized(this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//...
//控制循环依赖
this.beforeSingletonCreation(beanName);
//...
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
} //catch...finally...
beforeSingletonCreation会检查当前创建的bean是否在singletonsCurrentlyInCreation中,如果存在则说明当前对象在一个创建流程中出现2次,这时抛出异常。
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
第一次把role的bean名称添加进singletonsCurrentlyInCreation。
1.1.2 早期引用的处理
getSingleton会执行ObjectFactory参数的getObject方法,也就是执行createBean真正创建role。createBean->doCreateBean,doCreateBean中用createBeanInstance创建出刚实例化但尚未进行属性赋值的role,然后有对早期引用的处理。这里的早期,指的是bean刚创建出来属性没赋值。
//...
boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
if (earlySingletonExposure) {
//...
this.addSingletonFactory(beanName, () -> {
return this.getEarlyBeanReference(beanName, mbd, bean);
});
}
//...
判断条件:单例、允许出现循环依赖(当前版本默认允许)、在singletonsCurrentlyInCreation集合中。满足条件进入if分支。
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);
}
}
}
方法内部把创建role对象的工厂保存到三级缓存singletonFactories中,并从二级缓存中移除。
1.1.3 属性赋值
populateBean为role对象的属性赋值,用所有后置处理器的postProcessProperties时,很明显CommonAnnotationBeanPostProcessor不会收集到@Resource等标记的属性,AutowiredAnnotationBeanPostProcessor会收集到@Autoweired标注的属性。
CommonAnnotationBeanPostProcessor继续调inject方法,执行流程:inject->resolveFieldValue->beanFactory的resolveDependency方法。
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field)this.member;
Object value;
try{
//...
value = this.resolveFieldValue(field, bean, beanName);
}//catch...
}
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
//...
Object value;
try {
value = AutowiredAnnotationBeanPostProcessor.this.beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
} // catch...
这里是DefaultListableBeanFactory,继续执行resolveDependency->doResolveDependency。
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
//...
if (result == null) {
result = this.doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
//...
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
//...
}
doResolveDependency中调DependencyDescriptor的resolveCandidate方法,resolveCandidate的第一个参数是doResolveDependency解析出来的role对象的属性user。
这个方法果然是去容器中去取user对象了。
1.2 初始化Uer
创建user对象和创建role一样,都是执行getBean->doGetBean,也会把user放入singletonsCurrentlyInCreation集合中。继续createBean->doCreateBean,同样有针对uer的早期引用处理,把role对象的工厂保存到三级缓存中并从二级缓存中移除。
最后到了属性赋值环节,因为User类用了@Autowired注入了role,所以CommonAnnotationBeanPostProcessor处理方法和上面一样,最终getBean(role)。
1.2.1 再次调用getBean获取role
执行getBean(role)到doGetBean,会调getSingleton(role)。这个重载方法是循环。
public Object getSingleton(String beanName) {
return this.getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
//从二级缓存找,双重检查锁保证线程安全
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized(this.singletonObjects) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
//从三级缓存找
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//刚开时创建role时,早期引用处理时把role放到了三级缓存
singletonObject = singletonFactory.getObject();
//role的三级缓存删了,并放入二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
1.2.2 Role初始化之后
通过getSingleton获取到role对象后,getBean(role)执行完毕,返回获得到role对象。这时user还处于属性注入阶段。回到CommonAnnotationBeanPostProcessor处理@Autoweired标注字段的处理逻辑中。
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field)this.member;
Object value;
if (this.cached) {
try {
value = AutowiredAnnotationBeanPostProcessor.this.resolvedCachedArgument(beanName, this.cachedFieldValue);
} // catch ...
} else {
value = this.resolveFieldValue(field, bean, beanName);
}
if (value != null) {
//获取到role后,用反射将role设置到User的属性中
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
接着user的populateBean和initializeBean方法继续执行,这里和循环依赖无关。doCreateBean执行完返回createBean,然后返回getSingleton:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized(this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//...
this.beforeSingletonCreation(beanName);
boolean newSingleton = false;
try {
//user对象创建完成后返回这里
singletonObject = singletonFactory.getObject();
newSingleton = true;
} //catch ...
finally {
//...
this.afterSingletonCreation(beanName);
}
if (newSingleton) {
this.addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
通过singletonFactory的getObject返回user对象后,执行afterSingletonCreation,从singletonsCurrentlyInCreation集合中删除user。
protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)){
//throw ...
}
}
然后执行addSingleton,user对象放入一级缓存,并从二三级缓存中移除。最终一个user对象完全创建出来了。
protected void addSingleton(String beanName, Object singletonObject) {
synchronized(this.singletonObjects) {
//放入一级缓存
this.singletonObjects.put(beanName, singletonObject);
//从二级和三级缓存中移除
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
1.3 回到Role的创建
user对象创建出来并完成属性赋值和全部初始化了,返回到role对象的属性赋值,此时会将完全创建好的user对象注入,然后完成后面的populateBean和initializeBean。后面和user对象一样,返回singletonFactory方法执行afterSingletonCreation和addSingleton,把role对象从singletonsCurrentlyInCreation集合中删除、放入一级缓存并从二三级缓存中移除。至此,循环依赖的问题解决了,两个对象都完全创建好了。
通过一副图,快速抓住循环依赖的精髓: