注:首先如果程序中出现了循环依赖本身就是程序设计存在问题,尽量在设计上避免出现循环依赖。在springboot框架中已经默认不支持循环依赖的存在了,除非设置spring.main.allow-circular-references=true
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 ‘getBeanNamesOfType’ with the ‘allowEagerInit’ flag turned off, for example.
上面这句异常是在spring容器中某个bean存在多个版本时抛出的错误,出现在代码中存在bean的循环依赖时。但是spring明明利用三级缓存机制解决了循环依赖问题为什么还会出现这种报错呢?接下来我们通过代码复现+源码分析彻底弄懂这个问题。同时论证下三级缓存的优点,为什么不用二级缓存。
存在Messenger和ServiceA,Messenger中定义了通知第三方的消息逻辑send(),ServiceA中定义了主要业务逻辑method(),要求send()不能影响method()的响应时长故需要对send()方法做异步处理添加了 @Async注解。
@Service
public class ServiceA {
@Autowired
private Messenger messenger;
@Transactional
public void method(){
// 主要业务
// 不重要通知
messenger.send();
}
}
------------------------------------
@Service
public class Messenger {
@Autowired
private ServiceA serviceA;
@Async
public void send(){
// 通知逻辑
//...
}
@Transactional
public void transaction(){
}
}
现在对如上逻辑进行初始化分析,若不带@Aysnc注解按spring正常的循环依赖处理步骤应该如下图所示。
若带 @Async注解程序运行时会发现报错如下:
org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'messenger': Bean
with name 'messenger' has been injected into other beans [serviceA] 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.
若带 @Async注解的初始化流程图如下:
上面报错换成人话:在步骤7时已经将三级缓存中提前暴露的messenger进行代理增强移入二级缓存并且注入到ServiceA中了。但是在步骤12时messenger由于@Async注解被AsyncAnnotationBeanPostProcessor后置处理器进行代理增强,且与二级缓存中的messenger代理增强不相等,若将步骤12产生的messenger代理增强作为最终版本,则ServiceA的messenger不是最终版本,此时在spring容器中存在messenger的两个版本。
接下来针对关键步骤进行源码分析,需要有spring源码基础
步骤7的上一步是,初始化ServiceA是需要注入Messenger属性,此时从容器中获取Messenger。
接下来看从容器中获取Messenger的核心方法DefaultSingletonBeanRegistry.getSingleton()
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 一级缓存中获取Messenger
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 一级缓存中未获取到Messenger
synchronized (this.singletonObjects) {
// 在二级缓存获取
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 二级缓存没获取到,在三级缓存中获取
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 执行存入三级缓存时预设的lamda表达式增强方法
singletonObject = singletonFactory.getObject();
// 放入二级缓存,清空三级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
Messenger因为在步骤2是提前暴露放入到了三级缓存中,所以在此出三级缓存中可以获取到Messenger,三级缓存中放置的是ObjectFactory,调用其getObject方法获取Messenger的增强代理对象。
AbstractAutowireCapableBeanFactory.getEarlyBeanReference()
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
// 遍历全部的BeanPostProcessor,如果其实现了SmartInstantiationAwareBeanPostProcessor接口则调用其getEarlyBeanReference方法对bean进行早期增强
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
// 这里调用AnnotationAwareAspectJAutoProxyCreator.getEarlyBeanReference()
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
AnnotationAwareAspectJAutoProxyCreator.getEarlyBeanReference() ——》AbstractAutoProxyCreator.getEarlyBeanReference()
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
// 获取bean的缓存key
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 将bean代理前的值记录于缓存,代表这个bean因为循环依赖的缘故已经被AnnotationAwareAspectJAutoProxyCreator提前进行了代理增强,在后续步骤12时可以根据缓存判断是否已被提前增强,避免被AnnotationAwareAspectJAutoProxyCreator进行重复代理增强。
this.earlyProxyReferences.put(cacheKey, bean);
// 获取代理增强对象
return wrapIfNecessary(bean, beanName, cacheKey);
}
获取代理增强对象流程在后面分析。
此时Messenger完成了创建、参数注入过程,在步骤12进行初始化和bean的前置后置处理。
AbstractAutowireCapableBeanFactory.initializeBean()
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
// 执行bean实现的各种Aware接口如:BeanNameAware/BeanFactoryAware
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 执行bean的处理器中的before方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 调用初始化方法如 实现InitializingBean接口的afterPropertiesSet方法,和xml中指的的init-method
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 执行bean的后置处理器中的方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
这里主要看下执行bean的后置处理
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// 这里的getBeanPostProcessors()包含AnnotationAwareAspectJAutoProxyCreator和AsyncAnnotationBeanPostProcessor
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
AnnotationAwareAspectJAutoProxyCreator后置处理器由于在步骤7时已经对Messenger进行了提前增强,所以在此处返回对象本身不会进行重复增强了。AsyncAnnotationBeanPostProcessor却会对Messenger进行代理增强,所以此处返回的current是AsyncAnnotationBeanPostProcessor产生的代理类。
首先看下AnnotationAwareAspectJAutoProxyCreator.postProcessAfterInitialization()
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 如果该对象在处理循环依赖时三级缓存升级二级缓存的过程中调用getEarlyBeanReference方法进行了代理增强,earlyProxyReferences中会缓存该对象的cacheKey,
// 所以此处为false,不会重复进行代理了
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 进行代理对象创建
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
再看下AsyncAnnotationBeanPostProcessor.postProcessAfterInitialization(),因为AnnotationAwareAspectJAutoProxyCreator未对Messenger进行代理增强所以此处返回的是一个被AsyncAnnotationBeanPostProcessor增强的Messenger的代理类。
public Object postProcessAfterInitialization(Object bean, String beanName) {
// 是否是AOP的基础建设类,即springAOP原生的类,不做任何处理
if (this.advisor == null || bean instanceof AopInfrastructureBean) {
// Ignore AOP infrastructure such as scoped proxies.
return bean;
}
// 是否是AOP代理类
if (bean instanceof Advised) {
Advised advised = (Advised) bean;
if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
// Add our local Advisor to the existing proxy's Advisor chain...
// 将当前后置处理器中的advisor添加到当前代理对象的advisor链中
if (this.beforeExistingAdvisors) {
advised.addAdvisor(0, this.advisor);
}
else {
advised.addAdvisor(this.advisor);
}
return bean;
}
}
// 到此处说明当前bean非AOP代理对象,在此处进行代理增强,添加切面链
if (isEligible(bean, beanName)) {
ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
if (!proxyFactory.isProxyTargetClass()) {
evaluateProxyInterfaces(bean.getClass(), proxyFactory);
}
proxyFactory.addAdvisor(this.advisor);
customizeProxyFactory(proxyFactory);
// 返回代理对象
return proxyFactory.getProxy(getProxyClassLoader());
}
// No proxy needed.
return bean;
}
步骤13是spring在处理循环依赖时为了避免容器中bean的版本一致性进行的一个兜底判断逻辑。
首先看下spring创建bean、暴露三级缓存、bean参数注入、初始化及后置处理、循环依赖兜底判断的核心串联方法AbstractAutowireCapableBeanFactory.doCreateBean()方法
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 创建bean实例,调用构造方法,如果有定义带参构造,则自动在beanfactory获取对应类型的入参,
// 如果beanfactory未获取到,且没有无参构造,则抛出异常
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// 是否提前暴露,就是将半成品的bean加入三级缓存,此时可以通过getBean拿到半成品的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");
}
// 加入三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
// 初始化bean实例
Object exposedObject = bean;
try {
// Bean属性填充
populateBean(beanName, mbd, instanceWrapper);
// 调用初始化方法/应用BeanPostProcessor后置处理器
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
// 看下二级缓存中有无已经增强过的代理类,如果有的话取出来代替现在的类
//(因为如果出现了循环依赖某类A在三级缓存升级为二级缓存是进行了代理类增强,A类的后置处理中就不会再进行代理增强了,而是在此处获取二级缓存中的代理)
Object earlySingletonReference = getSingleton(beanName, false);
// 比较下后置处理后的bean还是否原来的bean如果还是说明没有进行代理增强,替换成二级缓存中的。
if (earlySingletonReference != null) {
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 " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
上面方法太长了,写一段伪代码着重讲下循环依赖的兜底判断及当前场景异常抛出的原因
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 步骤1.利用反射调用构造方法创建Messenger
BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
Object bean = instanceWrapper.getWrappedInstance();
// 步骤2.提前暴露将Messenger保存到三级缓存singletonFactories中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
Object exposedObject = bean;
// 步骤3.为Messenger注入属性ServiceA
populateBean(beanName, mbd, instanceWrapper);
// 步骤12.对Messenger进行初始化和bean的前置和后置处理(代理增强),因为存在@Async注解故被AsyncAnnotationBeanPostProcessor后置处理器增强,返回代理对象
exposedObject = initializeBean(beanName, exposedObject, mbd);
//步骤13.判断下二级缓存中是否存在Messenger,此处存在。然后比较步骤1中创建的Messenger与步骤12代理增强后的Messenger是否相同,此处不相同且检查到Messager已经被注入到ServiceA中此处抛出异常。
-----------------------------------步骤13重点分析---------------------------------------------------
// 从缓存中获取Messenger,因为步骤7,所以此处取到的是二级缓存中的被AnnotationAwareAspectJAutoProxyCreator后置处理器增强的代理对象
Object earlySingletonReference = getSingleton(beanName, false);
if (exposedObject == bean) {
// 判断一下步骤12返回的对象有没有被代理增强过,如果没被增强此处应该等于步骤1创建的bean,此时将二级缓存中的代理类作为最终版本返回。(因为如果出现了循环依赖某类A在三级缓存升级为二级缓存是进行了AnnotationAwareAspectJAutoProxyCreator代理类增强,A类的后置处理中就不会再重复进行AnnotationAwareAspectJAutoProxyCreator代理增强了,而是在此处获取二级缓存中的代理,节约性能也保证了A最终版本和提前注入版本保持一致)
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
// 因为步骤12返回的是AsyncAnnotationBeanPostProcessor后置处理器增强的代理对象,且Messenger已经在步骤7时注入到了ServiceA中所以actualDependentBeans=1。此时步骤12返回的为MessengerProxy2,ServiceA中注入的是MessengerProxy1。
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
// Messenger已经在步骤7时注入到了ServiceA中所以actualDependentBeans=1,所以抛出此异常。
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 " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
return exposedObject;
}
至此异常产生的原因源码分析完毕。接下来真的几个问题在进行拓展分析。
因为先加载ServiceA时,ServiceA中的Messenger与Messenger正常初始化后的最终版本一致
先加载ServiceA时流程如下:
首先三级缓存不是spring解决循环依赖的必要条件,用二级缓存乃至一级缓存也能解决循环依赖, 只能说用三级缓存更加优雅,让程序更符合设计原则,更利于后续扩展。
首先明确循环依赖是要解决什么问题:保证bean提前暴露版本与bean后置处理完成后的最终版本一致。
改变下bean的创建顺序:由1.创建并提前暴露原对象、2.注入属性、3.初始化、4.后置处理(代理增强) ===>> 1.创建、2.后置处理(代理增强)并提前暴露代理对象、3.注入属性、4.初始化。
像这样创建后即刻进行代理增强并将代理增强后的版本提前暴露到一级缓存中,就可以保证bean提前暴露版本与后置处理完成后的最终版本一致了,只使用一级缓存解决了循环依赖问题。
但这样做的不好之处很多随便列举几个:
同理用二级缓存如果接受一级缓存中即包含完全初始化的bean又包含未完全初始化的bean或者接受将代理增强提前到注入和初始化之前也能解决循环依赖。但是在设计上始终不够优雅,不合理。
因为@Async相关的切面没有声明给spring管理,AnnotationAwareAspectJAutoProxyCreator在创建代理对象是无法获取
首先看下AnnotationAwareAspectJAutoProxyCreator是怎样创建代理对象的
AnnotationAwareAspectJAutoProxyCreator.wrapIfNecessary()
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
//
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 当前bean无切面,所以无需生成代理对象
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
//
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 获取当前bean相关的全部切面
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
// 当前bean无切面
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
只要getAdvicesAndAdvisorsForBean()能获取到对应切面就能处理对应的注解如@Transactional注解
AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors()
protected List<Advisor> findCandidateAdvisors() {
// 在spring容器中获取Advisor,如TransactionAttributeSourceAdvisor
List<Advisor> advisors = super.findCandidateAdvisors();
// 添加AspectJ类型的切面并转换为advisor如:用户使用@Aspect自定义的切面
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
所以重点是看下处理@Async相关的切面有没有注入到spring容器,这个地方我们对比@Transactional一起看源码。
@EnableTransactionManagement注解向容器中注入了TransactionManagementConfigurationSelector
TransactionManagementConfigurationSelector向容器中注入了ProxyTransactionManagementConfiguration
ProxyTransactionManagementConfiguration向容器中注入了处理@Transactional的切面BeanFactoryTransactionAttributeSourceAdvisor,所以AnnotationAwareAspectJAutoProxyCreator后置处理器产生的代理对象切面链中包涵BeanFactoryTransactionAttributeSourceAdvisor可以处理@Transactional注解。
@EnableTransactionManagement注解向容器中注入了AsyncConfigurationSelector
AsyncConfigurationSelector像容器中注入了ProxyAsyncConfiguration
ProxyAsyncConfiguration像容器中注入了AsyncAnnotationBeanPostProcessor后置处理器
但是处理@Async的Advisor是通过初始化的方式传入AsyncAnnotationBeanPostProcessor的,并没有将@Async的Advisor注入给spring管理,所以AnnotationAwareAspectJAutoProxyCreator在生成代理对象是无法获取@Async相关的切面AsyncAnnotationAdvisor即无法处理@Async注解