三级缓存的概念是针对单例bean来说的,原型的bean是每次直接创建新的bean对象,
IoC容器中,同一个bean或者其代理对象只能存在一个,不能同时存在
一级缓存
存放完整的bean(实例化和初始化都已完成)
二级缓存
提前曝光的不完整的bean(可能是bean,也可能是bean的AOP代理,未进行初始化)
作用:防止创建出多个相同的bean(或者AOP代理)
三级缓存
存放ObjectFactory,这是一个Lambda表达式,执行这个表达式会拿到bean或者bean的代理
作用:解决AOP问题,因为这个表达式返回的是bean本身或者AOP代理过的bean
Spring容器启动,扫描代码,拿到很多需要单例的bean,严格根据字母顺序进行实例化
bean在实例化以后都会把自己的lambda接口放入三级缓存,这个lambda的作用是返回bean本身或者返回bean的代理,这个lambda不一定会被执行,仅在解决循环依赖的时候才会被执行
正常情况下,Spring是根据bean的生命周期来创建bean并放入IoC,但是遇到循环依赖的话,会通过三级缓存、提前曝光、提前进行AOP代理 来解决循环依赖(就不是严格按照bean的生命周期了,因为循环依赖的情况很少)
这里最好回顾一下bean的生命周期
根据需要从三级缓存取出来的ObjectFactory执行以后会得到的不完整的(可能是AOP代理)bean会放到二级缓存,并移除在三级缓存中的内容
如果没有AOP代理的话,不完整的bean直接放入二级缓存,完整的bean放入一级缓存
以下举个循环依赖的初始化例子
这里假设有2个bean,A、B, AB相互依赖 1. Spring容器启动,扫描代码,先找到一个需要变成单例的A 2. bean A的生命周期开始 3. 进行实例化A, 把A放到三级缓存,key是A的name,value是一个lamba(ObjectFactory) 4. 设置属性,发现依赖B,依次从一级、二级、三级缓存去找B,没找到,进入B的生命周期 5. bean B的生命周期开始 6. 进行实例化B, 把B放到三级缓存(同上) 7. 设置属性,发现依赖A,依次从一级、二级、三级缓存去找A,找到了,执行A的lambda得到不完整的bean A(可能是AOP代理),把bean A放入二级缓存,并在三级缓存中移除 8. 执行B的剩余生命周期 9. A继续设置属性B,执行A的剩余生命周期 10. 继续扫描初始化需要的单例
构造环境:
Test1和Test2这2个bean循环依赖
加上Transaction注解,就会让Spring给这两个bean加上代理
properties里面打开允许循环依赖的开关
当需要设置属性是某个bean的时候就会去调用getSingleton方法,
这个方法是依次从一级缓存、二级缓存、三级缓存中找这个bean
执行ObjectFactory的getObject就是调用了getEarlyBeanReference,
里面又调用了wrapIfNecessary,得到了bean本身或者bean的代理
参考
https://blog.csdn.net/mweibiao/article/details/126133411
标签:缓存,Spring,代理,bean,生命周期,AOP,三级 From: https://www.cnblogs.com/huainanyin/p/18085247