Spring 如何解决循环依赖

1.循环依赖发生在哪里

循环依赖发生在几个有依赖关系的实体类中。

2.循环依赖是什么

举个简单的栗子:

学生类中有班级类的外部属性,班级类中又有学生类的外部属性。

学生bean依赖于班级bean,班级bean依赖于学生bean。

当然,这是最简单的循环,只涉及到两个bean,也有较为复杂的依赖,3个bean、5个bean等等。

3.spring在加载时会发生什么

当项目启动时,创建bean的时候,因为有循环依赖,会报BeanCurrentlyInCreationException异常,如下:

 在注入这两个bean的时候,考虑到几种注入方式,下面演示注解@Autowired注入,并给出解决方案

Spring 如何解决循环依赖_第1张图片

Spring 如何解决循环依赖_第2张图片

会报异常:

4.解决方法

@Lazy)

有点懒加载的意思,就是在加载的时候不会完全初始化,而是创建一个代理,将其注入另一个bean,注入的bean只有在需要时才会创建。

只需要在beanA中加一个注解,

@lazy这个注解可以加载方法上也可以修饰在方法参数上

Spring 如何解决循环依赖_第3张图片

再去加载启动类就不会报错了。

注意:

以上的不报错是基于A、B都是单例的情况,非单例循环依赖spring无法处理。

底层:使用三级缓存处理单例模式下的循环依赖

缓存:

        一级缓存:singletonObjects :完成了初始化的单例对象map

        二级缓存,earlySingletonObjects:完成实例化未初始化的单例对象ma

        三级缓存,singletonFactories: 单例对象工厂map,单例对象实例化完成之后会加入singletonFactories

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                ObjectFactory singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

简单理解就是:对于有依赖关系的bean,spring加载起来之后,调用createBeanInstance,进行bean的实例化,然后在调用addSingletonFactory,把对象放在工厂中。有循环依赖的bean,相当于还没加载完成,但可以被其他依赖这个bean的bean加载,等所有的都放在工厂之后,在根据依赖关系加载所有的依赖bean,形成一个闭环。

 

你可能感兴趣的:(spring,java,后端)