spring的三级缓存和循环依赖

关于spring的三级缓存

首先大概说一下spring的加载bean的概念(注意,这里是大概,其中应该还包括加载配置文件和封装成beanDefinition等等的一些操作,这些请仔细查看其它的文献)

spring严格按照如下顺序:

  1. 实例化
  2. 设置属性
  3. 初始化(包括执行init方法和静态加载的一些东西)
  4. 如果该bean需要代理则生成aop代理对象

什么是三级缓存
是spirng中维护的三个map:

/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);


/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
缓存说明
singletonObjects第一级缓存,存放可用的成品Bean。
earlySingletonObjects第二级缓存,存放半成品的Bean,半成品的Bean是已创建对象,但是未注入属性和初始化。用以解决循环依赖。
singletonFactories第三级缓存,存的是Bean工厂对象,用来生成半成品的Bean并放入到二级缓存中。用以解决循环依赖。

循环依赖

所谓的循环依赖,就是两个或则两个以上的bean互相依赖对方,最终形成闭环。比如“A对象依赖B对象,而B对象也依赖A对象”,或者“A对象依赖B对象,B对象依赖C对象,C对象依赖A对象”;类似以下代码:

public class A {
    private B b;
}

public class B {
    private A a;
}

为什么要有三级缓存

为了解决在aop代理条件下的循环依赖

加载流程如下:

  1. 调用getBean,缓存中没有则去加载实例化A
  2. 将A封装成objectFactory放入到三级缓存,此时该对象是半成品,还没有加载完
  3. 设置A的属性
  4. 发现A需要B的依赖,然后去实例化B, 并且将B加入到三级缓存
  5. 设置B的属性,在B中发现需要A的依赖,则调用getBean
  6. 这次在三级缓存中获取到了A,注意三级缓存中存放的是封装成了objectFactory的对象,获取的具体方法是调用了objectFactory的getObject(该方法的作用是,如果Bean是需要代理的对象则创建一个代理对象并返回,如果不是代理对象则直接返回该对象本身), 并且放入到了二级缓存
  7. B拿到了A这个半成品的代理引用
  8. B完成了初始化
  9. A完成初始化

注意在第三级缓存的作用完全就是从第三级缓存中的objectFactory调用getObject 获取的Bean 放入到二级缓存中 (objectFactory.getObject 方法作用参考上面的第六步, 获取的Bean 可以是代理对象也可以是代理本身)

为什么不是二级缓存

因为如果只有二级缓存,完全可以解决循环依赖,但是如果考虑到aop,情况就完全不一样,如果是在aop的情况下,那么就只能在A实例化完 (注意只是实例化阶段)之后生成代理对象放入到二级缓存, 因为spring在实例化阶段是不会知道这个是否有循环依赖(只有在设置bean属性的时候知道),这个时候二级缓存直接就是代理对象,虽然可以解决循环依赖,但是完全是违背了spring的设计原则

spring的设计原则是初始化阶段完毕后再给Bean生成代理对象

这样子在没有循环依赖的时候,spring在实例化阶段就给生成了代理对象, 而不是在 spirng设计原则中 初始化完毕后生成代理对象

而且如果是在有三级缓存并且是循环依赖情况下,代理对象还能延迟加载, 就是在获取三级缓存调用getObject的时候创建代理对象

参考文献

https://segmentfault.com/a/1190000023647227

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值