循环依赖的场景:
service中的类A和类B,类A中需要DI类B,而类B中又需要DI类A。但环并不一定会出现,跟DI的方式有关。
Spring中的循环依赖有:
- 构造器循环依赖(会出现环的情况,项目无法启动)
- Filed属性注入依赖(类AB的Scope不同时,有不同的情况。)
代码用例:
构造器循环依赖: 将陷入环,项目启动失败。
@Service
public class LoopA {
LoopB loopB;
public LoopA(LoopB loopB) {
this.loopB = loopB;
}
public String sout() {
return loopB.sout();
}
}
-----------------------------------
@Service
public class LoopB {
LoopA loopA;
public LoopB(LoopA loopA) {
this.loopA = loopA;
}
public String sout() {
return "this is class loop b";
}
}
先构造器(LoopA )的循环注入:: 将陷入环,项目启动失败。
@Service
public class LoopA {
public LoopA(LoopB loopB) {
}
}
----------------------------
@Service
public class LoopB {
@Autowired
LoopA loopA;
public LoopB() {
}
}
Filed都为多例的类的注入:将陷入环,项目启动失败。
@Service
@Scope("prototype")
public class LoopA {
@Autowired
LoopB loopB;
public String sout() {
return loopB.sout();
}
}
-----------------------------------------------------
@Service
@Scope("prototype")
public class LoopB {
@Autowired
LoopA loopA;
public String sout() {
return "this is class loop b";
}
}
在多例类(先初始化)中注入单例类(后初始化):将陷入环
//先被controller调用该类
@Service
@Scope("prototype")
public class LoopA {
@Autowired
LoopB loopB;
public String sout() {
return loopB.sout();
}
}
----------------------------------
@Service
public class LoopB {
@Autowired
LoopA loopA;
public String sout() {
return "this is class loop b";
}
}
环的陷入,是因为创建LoopA类需要LoopB类,LoopB类又需要LoopA类,在获取LoopA类时,发现LoopA类被存在一个未创建完成的HashSet中,于是抛出陷入循环的异常。
Filed都为单例的类的注入:不会陷入环,会使用到spring单例的三级缓存。
@Service
public class LoopA {
@Autowired
LoopB loopB;
public String sout() {
return loopB.sout();
}
}
------------------------------------
@Service
public class LoopB {
@Autowired
LoopA loopA;
public String sout() {
return "this is class loop b";
}
}
在单例类(先初始化)中注入多例类(后初始化):不会陷入环
@Service
public class LoopA {
@Autowired
LoopB loopB;
public LoopA() {
}
public String sout() {
return loopB.sout();
}
}
--------------------------------------------------、
@Service
@Scope("prototype")
public class LoopB {
@Autowired
LoopA loopA;
public LoopB() {
}
public String sout() {
return "this is class loop b";
}
}
从日志中也可以看到,当对单例类(LoopA类)进行初始化时,还未执行构造函数,类就已经被实例化出来了,并存放于第三级缓存 singletonFactories 的HashMap中,再注入单例类(LoopA类)中的属性,当其他的类(单例或多例)在循环注入单例类(LoopA类)时,就可以获取到单例类(LoopA类),此时便跳出了循环
有兴趣的同学可以看看另外一篇博客, Spring 循环依赖的源码解毒与灵魂拷问:https://blog.csdn.net/BigBug_500/article/details/109050337