Spring循环依赖检测、解决方法
最近看了一片讨论spring 循环依赖的文章,循环依赖的问题,其实没怎么深入了解的。我之前也自己动手写过一个IoC容器,这个容器实现并解决了:bean的实例化和注入。但是循环依赖的这个问题,当时并没有考虑,因此没有处理循环依赖的问题。现在回想,处理循环依赖其实是一个很有实际意义的。因此,花时间思考和整理IoC的循环依赖。
一个拓展:除了Spring,其他的IoC框架(比如:Guice)应该也是有对应的处理机制的。
1.循环依赖发生的时机
循环依赖发生的时机:实例化与填充属性/方法的过程中
- 构造器注入:(启动失败)
@Service
public class RootService {
private LeafService leafService;
@Autowired
public RootService(LeafService leafService) {
this.leafService = leafService;
}
}
@Service
public class LeafService {
private RootService rootService;
@Autowired
public LeafService(RootService rootService) {
this.rootService = rootService;
}
}
- Field 注入的方式:(能启动成功)
@Service
public class RootService {
@Autowired
private LeafService leafService;
}
@Service
public class LeafService {
@Autowired
private RootService rootService;
}
- Setter 注入与Field注入类似
(略)
2.检测循环依赖的过程如下:
检测循环依赖的本质就是一个检测图是否有环的问题。
检测是否有环有多种实现,一种常见的方法是利用HashMap作为辅助,(还有其他方法:如,快慢指针)
检测环的示例代码:
public static boolean hasLoop(Node head) {
Node temp = head;
HashMap<Node, Node> hashMap = new HashMap<>();
while (temp != null) {
if (hashMap.get(temp) != null) {
return true;
} else {
hashMap.put(temp, temp);
}
temp = temp.next;
if (temp == null) {
return false;
}
}
return true;
}
private class Node<T> {
private T data;
private Node next;
}
3.spring的解决办法:
单例bean的依赖注入分为构造器注入和setter方法注入。
- Spring只会解决setter方法注入的循环依赖,构造器注入的循环依赖会抛BeanCurrentlyInCreationException异常。
- Spring不会解决prototype作用域的bean,因为Spring容器不进行缓存”prototype”作用域的bean,因此无法提前暴露一个创建中的bean。如果有循环依赖会抛BeanCurrentlyInCreationException异常。
Spring常见依赖注入方式:
1.接口注入
2.Setter方法注入
3.构造方法注入
(完)