一种是A依赖了B,B又依赖了A,
另一种情况是A自己依赖了自己。
无线套娃
Spring运用了三级缓存解决了循环依赖
具体流程图如下
B中从三级缓存取出的A早期引用和A本身是一个引用,这样当A完成了初始化后,B中的A也完成了初始化
如果单纯的解决普通bean循环依赖,A在赋值前,把早期bean放入缓存,然后B在赋值A时,从缓存中取出。其实用一层缓存就够了,为什么需要做3层缓存呢?
上面说为什么需要做3层缓存,其中一个原因就是为了解决代理类的循环依赖。如果我们只用一层缓存,那么B依赖的就是一个普通的bean,而不是一个代理bean。
而我们的第三级缓存中调用的工厂方法
getEarlyBeanReference生成早期bean,并且会调用事务代理的后置处理器【AnnotationAwareAspectJAutoProxyCreator】的父类【AbstractAutoProxyCreator】的getEarlyBeanReference生成代理(如果有加事务注解)
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
// 会调用事务的后置处理器AbstractAutoProxyCreator的getEarlyBeanReference方法生成代理
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
return exposedObject;
}
【AbstractAutoProxyCreator】生成代理的方法做了处理,只会被代理一次,这样就解决了一个bean被多次代理(生成多个代理类)的问题
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 已经被代理则直接返回
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 代理的逻辑....
// 标记已经被代理
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
如果A被循环依赖且被事务代理,根据上面的逻辑,B中的A是代理类,而A自己因为循环依赖中的B先一步生成了A的代理,所以A不会在initializeBean中生成代理类。这样会导致两个bean不相等,所以spring在bean初始化的最后,会进行校验,如果A没有被代理并且缓存中有A,这样会把缓存中的A赋值A自己,这样就解决了两个A不一致的问题。
if (earlySingletonExposure) {
// 只从一二级缓存中找(是不是被循环依赖了)
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
// 创建的bean是否经BeanPostProcessor变成代理
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
// ...
}
}
没有循环依赖的话,initializeBean方法中会调用beanPostProcessor的after方法,生成所有的代理(包括事务)
比如A加了@async,A->b->A就会循环依赖报错,
原因是bean在初始化最后校验中,如果发现A已经被代理,且被循环依赖,就会直接报错
(而加事务不会,因为A中还是普通的bean,代理bean的是B中的A,所以不会进这个逻辑)
(@async的后处理器【AsyncAnnotationBeanPostProcessor】跟【AnnotationAwareAspectJAutoProxyCreator】不同的是,【AnnotationAwareAspectJAutoProxyCreator】有一个getEarlyBeanReference方法,循环依赖的时getEarlyBeanReference会调用这个方法先一步生成代理类,而@async的代理只能在initializeBean方法中调用的beanPostProcessor的after方法来生成)
if (earlySingletonExposure) {
// 只从一二级缓存中找(是不是被循环依赖了)
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
// 创建的bean是否经BeanPostProcessor变成代理
// 还是普通bean
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
// 已经变成代理则报错
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
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.");
}
}
}
}
参考文章
Spring getBean是如何解决循环依赖和多次动态代理
一文告诉你Spring是如何利用"三级缓存"巧妙解决Bean的循环依赖问题的
Spring的BeanFactoryPostProcessor和BeanPostProcessor
女同事问敖丙什么是 Spring 循环依赖?我…
Spring 中的 bean 生命周期?