本文共 1578 字,大约阅读时间需要 5 分钟。
属性暂时没有值的对象称之为不完整的Bean对象。
第一级缓存:单例池
singletonObjects ConcurrentHasnMsp<beanName,bean对象> 作用:保证一个beanName对应唯一的Bean完整对象第二级缓存
earlySingletonObjects HashMap<beanName,bean对象> 作用:保证一个beanName对应唯一的Bean不完整对象第三级缓存
singletonFactory HashMap<beanName,ObjectFactory(lambda表达式)> 作用:做一些预备工作。创建bean的时候先存到三级缓存,并不知道后面逻辑会不会用,会不会出现循环依赖等,防止出现循环依赖且AOP等场景@Component("aService")public class AService(){ @Autowired private BService bService; public void xxx(){ }}
@Component("bService")public class BService(){ @Autowired private AService aService; public void xxx(){ }}
加了三级缓存之后,生命周期如下:
0. creatingSet实例化…AService不完整对象(new AService())即原始对象—>第三级缓存<‘aSerivce’,lambda(AService原始对象,beanName,Beanefinition)>
填充bService属性—>从单例池中找bService—>找不到—>创建bService
bService的生命周期
2.1 实例化…BService对象(new BService()) 2.2 填充aService属性—>从单例池中找aService—>找不到—>aService正在创建中—>aService出现了循环依赖—>第二级缓存—>第三级缓存—>执行lambda—>提前AOP—>得到代理对象—>放入第二级缓存<‘aSerivce’,AService代理对象> 2.3 填充他属性 2.4 做其他事情 2.5 放入单例池填充他属性
做其他事情
从二级缓存中取出AService对象
放入单例池
creatingSet.remove(“aService”)
从上述定义,可看出:一级缓存(单例池)使用的是ConcurrentHashMap,二级缓存和三级缓存都是用的HashMap
为什么二级缓存和三级缓存用HashMap而不是使用ConcurrentHashMap呢?难道就不考虑线程安全的问题吗?
由于三级缓存中存的是lambda表达式且是一次性的,只要执行过一次就会被移除。二级缓存中存的是三级缓存lambda执行的结果。 也就是说同一个bean的名字,在三级缓存中如果存在一个lambda表达式,那么就表示在二级缓存中beanName对应的就没有值。同样的,反过来,在二级缓存里面beanName有值,那么在三级缓存中就没有对应的表达式。相当于是原子性的。 从第二段代码中可以看出,在往二级缓存push的时候,会把三级缓存的数据清除掉,那么就必须保证操作的原子性。很显然,二级缓存和三级缓存定义为ConcurrentHashMap并不能保证操作的原子性。只能添加synchronize加锁控制。 结合第二三段代码,可以看到,两个map的操作总是在一起的,添加到一个里面就从另一个中移除,同时加锁控制,已经保证了并发的操作安全,所以就没有必要设置为ConcurrentHashMap,在这种前提下,考虑性能,选择了HashMap转载地址:http://oayai.baihongyu.com/