问题描述
今天碰到一个很神奇的问题,程序循环依赖在本地跑起来完全没问题(因此没发现循环依赖了)。但是打成 jar 部署到服务器之后就报循环依赖
xxx with the 'allowEagerInit' flag turned off, for example
。
解决方法
根源在于在不同的操作系统或者环境下, bean 的加载顺序是不固定的。bean 加载顺序变化之后,就可能会导致循环依赖报错问题产生!因为,顺序变化之后,循环依赖的主体变了! bean 加载时,会先将所有的 BeanDefinition 扫描出来,扫描出来的顺序基本上就决定了 bean 的加载顺序。 扫描 BeanDefiniton 的方法是 ClassPathScanningCandidateComponentProvider#scanCandidateComponents(),这个方法在不同的环境下扫描出类的顺序是不固定的。它的底层走的是 java.lang.ClassLoader#getResources() ,这个方法没有承诺获取到资源文件的顺序!
报错代码在 AbstractAutowireCapableBeanFactory#doCreateBean 方法里面
原因是因为: 在 doCreateBean 方法中, 先 populateBean 填充属性, 这个时候会解决循环依赖。但是后面 exposedObject = initializeBean(beanName, exposedObject, mbd) 会创建代理对象, 这就导致代理对象跟已经注入到别的类里面原始对象不是同一个对象, springboot 当然不允许这样操作, 所以还是老老实实使用 @Lazy 处理循环依赖吧