错误信息:
org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name ‘a’: Bean with name ‘a’ has been injected into other beans [b] 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.
解决方案:
你的服务依赖
@Service
public class B {
@Autowired
private A a;
}
@Service
public class A {
@Autowired
private B b;
@Async
public void test () {}
}
添加懒加载:
@Service
public class B {
// 对实例A进行一个懒加载
@Lazy
@Autowired
private A a;
}
原因分析:
spring循环依赖不在赘述,根本在于,后置处理的时候,AsyncAnnotationBeanPostProcessors处理器增强处理以后,返回了一个cglib的代理对象,
此时我们已经发现了注入到B对象的A属性是原始的实例,但是A初始化后已经是一个包装过后的实例了(cglib),因为spring默认是单例,这肯定会出问题。初始化完后,发现spring还会进行一次对比,
// AbstractAutowireCapableBeanFactory.doCreateBean
if (earlySingletonExposure) {
// 依然从缓存中获取,注意这里第二个参数是false,也就是说只能从一级缓存、二级缓存中获取
// 因为此时还未放入一级缓存,所以肯定是没有的,只能从二级缓存中获取
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
// 这里会进行一个比较,看二级缓存中的bean实例是否与初始化后的bean实例相等,此时发现并不相等
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
// 接下来就会判断这个bean是否有其他bean进行依赖,如果有则说明注入到其他bean的依赖不是最终包装过后的bean
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.");
}
}
}
}