Spring循环依赖

Spring循环依赖_第1张图片

 代码

public class A{
    B b;
}

public class B{
    A a;
}

public class BeanTest{
    public static void main(String[] args){
        A a = new A();
        B b = new B();
        a.b=b;
        b.a=a;
    }
}

上述代码如果交给Spring IOC就会很复杂,面临两个问题,死循环创建和AOP代理

Spring循环依赖_第2张图片

一、Bean的创建与管理

Spring循环依赖_第3张图片 

 获取Bean会通过bean工厂进行获取,bean工厂会先去bean仓库进行检查,判断仓库有没有,如果有直接返回,如果没有就会创建一个。结论:获取Bean时先先从单例池获取,如果没有则创建添加至单例池

1、获取bean

Spring循环依赖_第4张图片

 获取bean要通过bean工厂,bean工厂要通过两次来获取,第一次要从仓库获取,通过BeanName(理解成清单)获取,如果没有返回;进行第二次获取,不仅要拿BeanName清单还要带上factory(理解成采购人员),采购人员去现场采购我们清单需要的东西,添加到仓库。会出现一个问题,可能线程1和线程2在getbean时,线程1获取发现没有去采购的同时,线程2 获取也发现没有也去采购,出现重复采购的问题,为避免这个问题,线程1去采购时需要先给仓库加上一把,其他线程要排队。

Spring循环依赖_第5张图片

 2、创建bean

 Spring循环依赖_第6张图片

 Spring循环依赖_第7张图片

 Spring循环依赖_第8张图片

 二、发生循环依赖

Spring循环依赖_第9张图片

 解决办法:a一旦被实例化,就添加到半成品池。通过半成品池可以解决死循环创建的问题,二级缓存可以解决死循环创建但是无法解决AOP代理的问题

Spring循环依赖_第10张图片

 三、AOP代理

不再是单纯的对象a、b,而是在此基础上包装了一层proxy$a、proxy$b,之间的引用也改变了,不再是a、b对象本身,而是引用他们各自的代理对象。半成品池所存放的是对象本身,二级缓存解决不了这个问题,延伸出了三级缓存

Spring循环依赖_第11张图片

 那么AOP代理是怎么创建代理对象的???

是在初始化的时候,执行bean的后置处理,在那里去执行构造出了AOP的代理对象。

Spring循环依赖_第12张图片

 在bean处理器里有一个AOP处理器,AOP处理器会创建动态代理,它有两个入口,一个是后置处理,一个是提前处理

Spring循环依赖_第13张图片

 然后从半成品池填充到b里面去,b填充完属性,执行初始化,然后执行后置处理,后置处理会创建一个动态代理的b放到单例池里。

Spring循环依赖_第14张图片

 接下来再回到a,a要填充b,单例池中已经有b了,所以直接使用,之后执行初始化,再去执行后置处理创建动态代理,但还有必要创建动态代理嘛?半成品池里已经有了动态代理的a了,就没有必要再去创建,而是直接把半成品池中的a挪到单例池里,同时把工厂池里的factory(a)删掉

Spring循环依赖_第15张图片

 

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