在本周的项目中遇到如下报错。错误报告非常清楚。buildingService中使用了divisionService,divisionalservice中也使用了buildingService。执行构造函数时出现问题。@AutowiredpublicBuildingServiceImpl(BuildingRepositorybuildingRepository,DivisionalWorkServicedivisionalWorkService){this.buildingRepository=buildingRepository;this.divisionalWorkService=divisionalWorkService;如果我们要构造一个BuildingService,我们需要先构造一个divisionalWorkService,但是如果我们要构造一个divisionalWorkService,我们必须构造一个BuildingService。很明显,结果会卡住,相应的解决办法也很简单,就是让其中一个构造其中一个,不需要另一个,然后再构造另一个。具体方法如下:@AutowiredpublicDivisionalWorkServiceImpl(DivisionalWorkRepositorydivisionalWorkRepository,@LazyBuildingServicebuildingService){this.buildingService=buildingService;}将@Lazy注释添加到构造函数之一。这是我找到的解释:打破循环的一种简单方法是告诉Spring延迟初始化其中一个bean。因此,它不会完全初始化bean,而是创建一个代理将其注入到另一个bean中。注入的Bean只有在第一次需要时才会被完全创建。我们可以告诉spring延迟初始化其中一个bean,而不是完全初始化bean,spring会根据需要的bean创建一个代理,通过这个代理创建需要的bean。当创建所需的bean并使用另一个bean时,另一个bean将被完全初始化。此时一方已经完全创建完毕,可以直接创建了。大致流程:除了这个方法,spring还提供了很多其他的方法来避免循环依赖。其中,Spring官方文档推荐使用setter注入代替上述处理方式。也就是不在构造函数中注入,让Spring创建bean,只在我们使用的时候注入依赖。为此进行了单独的测试:@ServicepublicclassSeverA{privateSeverBseverB;Stringmessage="我使用服务器A,B使用";@AutowiredpublicvoidsetSeverB(SeverBseverB){System.out.println("InjectinAB");this.severB=severB;}publicvoiduseB(){System.out.println(severB.message);}}@ServicepublicclassSeverB{privateSeverAseverA;Stringmessage="我是服务器B,A用过";@AutowiredpublicvoidsetSeverA(SeverAseverA){System.out.println("InjectAintoB");this.severA=severA;}publicvoiduseA(){System.out.println(severA.message);但是在这种情况下,会触发另一个循环依赖错误。不鼓励依赖循环引用。默认情况下,循环引用是被禁止的。更新应用程序以消除bean之间的依赖循环。作为最后的手段,可以通过将spring.main.allow-circular-references设置为true来自动中断循环。也就是说,我们需要这样配置:然后在项目启动时尝试调用serverA使用severB。结果如下然后尝试去掉severA.useB(),发现还是进行了注入操作,这不符合我们的想象。以下是官方文档的解释:也就是说,官方文档并没有说明在使用对应的服务时会调用setter函数。原理可能和前面的方法一样,没有完全注入。但是官方文档并不推荐这种方式,所以我们还是尽量避免循环依赖的产生。
