Spring循环依赖检测、解决方法

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方法注入。

  1. Spring只会解决setter方法注入的循环依赖,构造器注入的循环依赖会抛BeanCurrentlyInCreationException异常。
  2. Spring不会解决prototype作用域的bean,因为Spring容器不进行缓存”prototype”作用域的bean,因此无法提前暴露一个创建中的bean。如果有循环依赖会抛BeanCurrentlyInCreationException异常。

Spring常见依赖注入方式:
1.接口注入
2.Setter方法注入
3.构造方法注入

(完)

发表评论

邮箱地址不会被公开。 必填项已用*标注