spring神奇的循环依赖

故事

在开发中,本地代码稳定运行,测试环境也没问题,而生产环境发生了循环依赖,发布失败了。糟糕,生产发布失败可是大事情。开始着手解决。

现象

看看错误先
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name ‘customizeThreadServiceImpl’: Bean with name ‘customizeThreadServiceImpl’ has been injected into other beans [testStepServiceImpl,agileTestDetailServiceHelper,agileDemandServiceHelper,agileTaskOperationLogic,agileDemandRelationServiceHelper,agileTestPlanServiceHelper,agileStoryOperationLogic,issueViewServiceImpl] 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.

分析

看上面的报错,很明显原因是customizeThreadServiceImpl注入其他类的时候,发生了循环依赖,注入失败了

解决办法

  1. 使用@Lazy的注解,注解到发生循环依赖的类引入上(最简单)
	@Lazy
    @Resource
    private CustomizeThreadService threadService;
  1. 去除循环依赖,改造代码(困难但必要)
    因为发生循环依赖的根源还是代码设计不合理,产生的循环依赖,要从根源上解决,就是从设计程序的基础上就应该规划好,及早预防
  2. InitializingBean时,从context中获取(不推荐)
  3. @PostConstruct去设置bean依赖(不推荐)

到这里还是没搞明白为什么本地不会循环依赖,测试环境也不会,为什么生产就会呢

真正的原因

在不同的操作系统或者环境下,bean的加载顺序是不固定的。bean加载顺序变化之后,就可能导致循环依赖的产生。因为顺序变化之后,循环依赖的主体发生变化。

bean加载时,会先将所有的BeanDefinition扫描出来,扫描出来的顺序基本上决定了bean的加载顺序。

扫描BeanDefinition的方法是ClassPathScanningCandidateComponentProvider#scanCandidateComponents(),这个方法在不同的环境下扫描出类的顺序是不固定的,它底层走的是java.lang.ClassLoader#getResources,这个方法没有承诺获取到资源文件的顺序

总结

遇到这种循环依赖,不要心存侥幸,还是要着手解决为妙

遇事总结,分享工作趣事,祝我们都工作顺利。

你可能感兴趣的:(遇到的问题分享,java,spring,java,后端)