一、首先我们要了解 什么是循环依赖:
1. 什么是循环依赖?
所谓的循环依赖是指,A 依赖 B,B 又依赖 A,它们之间形成了循环依赖。
它们之间的依赖关系如下:
报错显示:
***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
jwPgPzServiceImpl defined in file [D:\新建文件夹\ELXY\smart_campus\jwpx\target\classes\com\sinosoft\springbootplus\assess\application\service\impl\JwPgPzServiceImpl.class]
↓
pgMbBaseinfoServiceImpl defined in file [D:\新建文件夹\ELXY\smart_campus\pgwj\target\classes\com\sinosoft\springbootplus\evaluate\application\service\impl\PgMbBaseinfoServiceImpl.class]
┌─────┐
| jwXyStudentServiceImpl defined in file [D:\新建文件夹\ELXY\smart_campus\jwpx\target\classes\com\sinosoft\springbootplus\student\application\service\impl\JwXyStudentServiceImpl.class]
↑ ↓
| hqKfStudentServiceImpl defined in file [D:\新建文件夹\ELXY\smart_campus\hqfw\target\classes\com\sinosoft\springbootplus\dorm\application\service\impl\HqKfStudentServiceImpl.class]
└─────┘
看到错可得知jwXyStudentServiceImpl和hqKfStudentServiceImpl 造成的循环依赖问题.
二、三种循环依赖
在Spring中一共有三种循环依赖,构造器循环依赖,Setter循环依赖,和Prototype作用域的循环依赖,对于这三种循环依赖,Spring并不是都解决的.
通过表格来了解下:
名称 | 是否可解决循环依赖 |
构造器循环依赖 | 否 |
Setter循环依赖 | 是 |
Prototype作用域的循环依赖 | 否 |
三、解决构造函数相互注入造成的循环依赖:
前面说Spring可以自动解决单例模式下通过setter()方法进行依赖注入产生的循环依赖问题。而对于通过构造方法进行依赖注入时产生的循环依赖问题没办法自动解决,那针对这种情况,我们可以使用@Lazy注解来解决。
也就是说,对于类A和类B都是通过构造器注入的情况,可以在A或者B的构造函数的形参上加个@Lazy注解实现延迟加载。@Lazy实现原理是,当实例化对象时,如果发现参数或者属性有@Lazy注解修饰,那么就不直接创建所依赖的对象了,而是使用动态代理创建一个代理类。
比如,类A的创建:A a=new A(B),需要依赖对象B,发现构造函数的形参上有@Lazy注解,那么就不直接创建B了,而是使用动态代理创建了一个代理类B1,此时A跟B就不是相互依赖了,变成了A依赖一个代理类B1,B依赖A。但因为在注入依赖时,类A并没有完全的初始化完,实际上注入的是一个代理对象,只有当他首次被使用的时候才会被完全的初始化。
当写上@Lazy注解就不会出现循环以来的问题了,完美解决.
@Lazy
@Autowired
private HqKfStudentApiService hqKfStudentApiService;
@Lazy
@Autowired
private StudentDorm studentDorm;
网上找到的循环依赖问题全景图,大家可以看一下: