事情起因
- 很久没有遇见循环依赖的问题了,起早上班启动准备和前端联调就报这个问题,大概率是昨天同事写的代码没有启动测试(所以啊,在提交代码前还是得自己启动下测试过才提交,避免影响他人)
问题出现
- 启动报错:The dependencies of some of the beans in the application context form a cycle
***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
memberCenterController (field private SysUserService MemberCenterController.userService)
┌─────┐
| sysUserServiceImpl defined in file [SysUserServiceImpl.class]
↑ ↓
| distributionRegisteredServiceImpl (field private DistributeMemberService DistributionRegisteredServiceImpl.memberService)
↑ ↓
| distributeMemberService (field private DistributeMemberTagServiceImpl DistributeMemberService.memberTagService)
↑ ↓
| distributeMemberTagServiceImpl (field private SysUserServiceImpl DistributeMemberTagServiceImpl.userService)
└─────┘
Process finished with exit code 1
问题分析
这是一个十分常见的循环依赖问题,就算没有遇见过看着箭头指来指去的,也会往循环依赖问题靠一靠。
我看到产生循环依赖的类是从SysUserServiceImpl开始的 我就去看了下SysUserServiceImpl类用的构造方法注入
循环依赖实质:
- 类A需要通过构造函数注入的类B的实例(或者B中声明的Bean),而类B需要通过构造函数注入的类A的实例(或者A中声明的Bean)。如果将类A和类B的bean配置为相互注入,则Spring IoC容器会在运行时检测到此循环引用,并引发一个BeanCurrentlyInCreationException。与典型情况(没有循环依赖)不同,bean A和bean B之间的循环依赖关系迫使其中一个bean在被完全初始化之前被注入到另一个bean中。Spring也解决不了到底是先有鸡还是先有蛋的问题了。
解决方案
方法一:
- 不使用基于构造函数的依赖注入
- 在字段上使用@Autowired注解,让Spring决定在合适的时机注入。【推荐】
- 用基于setter方法的依赖注射取代基于构造函数的依赖注入来解决循环依赖。
- 在@Autowired注解上方加上@Lazy注解(延迟加载)
@Lazy
@Autowired
private SysUserServiceImpl userService;
方法二:
- 使用SpringContextHolder获取已经存在的bean
SysUserServiceImpl userService= SpringContextHolder.getBean(SysUserServiceImpl .class)
如有其他解决方式或者见解欢迎留言交流!