Spring使用@Async出现循环依赖(circular reference)的解决方案

错误信息:

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."); 
         } 
      } 
   } 
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值