关于java:Spring的3级缓存和循环引用的理解

21次阅读

共计 2415 个字符,预计需要花费 7 分钟才能阅读完成。

此处是我本人的一个了解,避免当前遗记,如若那个中央了解不对,欢送指出。

一、背景

在咱们写代码的过程中个别会应用 @Autowired 来注入另外的一个对象,但有些时候产生了 循环依赖,然而咱们的代码没有报错,这个是什么起因呢?

二、前置常识

1、思考循环依赖的类型

此处咱们思考 单例 + @Autowired 的循环依赖,不思考应用 结构器注入 原型作用域的 Bean的注入。

2、代理对象何时创立


留神:
失常状况下,即没有产生 循环依赖的时候,aop 加强 是在 bean 初始化实现之后的 BeanPostProcessor#postProcessAfterInitialization办法中,然而如果有循环依赖产生的话,就须要提前,在 getEarlyBeanReference中提前创立代理对象。

3、3 级缓存中保留的是什么对象

缓存字段名 缓存级别 数据类型 解释
singletonObjects 1 Map<String, Object> 保留的是残缺的 Bean,即能够应用的 Bean
earlySingletonObjects 2 Map<String, Object> 保留的是半成品的 Bean, 即属性还没有设置,没有实现初始化工作
singletonFactories 3 Map<String, ObjectFactory<?>> 次要是生成 Bean,而后放到二级缓存中

留神:
ObjectFactory#getObject() 每调用一次,都会产生一个新的对象或返回旧对象,取决于是否存在代理等等。

4、从 3 级缓存中获取对象

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)

5 Spring Bean 的简化创立过程

1、实例化一个 bean

Object bean = instanceWrapper.getWrappedInstance();

实例化 Bean 即 new Bean()

2、退出到三级缓存中

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

退出到三级缓存中是有一些条件判断的,个别都会是成立的,此处认为须要退出到三级缓存。

3、设置 bean 的属性

populateBean(beanName, mbd, instanceWrapper);

第一步实例化了 bean,然而此时是没有填充须要注入的属性的,通过这一步进行属性的填充。

4、初始化 bean

Object exposedObject = initializeBean(beanName, exposedObject, mbd);

初始化 Bean,执行初始化办法、Aware 回调、执行 BeanPostProcessor#postProcessAfterInitialization 办法 (aop 的加强 是在这个外面实现的)

如果有 循环援用 的话,则 aop 的加强须要提前。

5、退出到一级缓存中

addSingleton(......)

三、了解

@Component
class A {
    @Autowired
    private B b;
}

@Transaction (存在代理)
@Component
class B{
    @Autowired
    private A a;
}

1、假如只有 singletonObjects 和 earlySingletonObjects 可否实现循环依赖

缓存字段名 缓存级别 数据类型 解释
singletonObjects 1 Map<String, Object> 保留的是残缺的 Bean,即能够应用的 Bean
earlySingletonObjects 2 Map<String, Object> 保留的是半成品的 Bean, 即属性还没有设置,没有实现初始化工作

此时须要获取 B的实例,即 getBean("b"),由上方理解到的 Bean 的简化流程可知


由上图可知,对象存在代理时 ,2 级缓存无奈解决问题。因为代理对象是通过BeanPostProcessor 来实现,是在设置属性之后才产生的代理对象

此时可能有人会说,那如果我在构建完 B 的实例后,就立马进行 Aop 代理,这样不就解决问题了吗?那假如 A 和 B 之间没有产生循环依赖,这样设计会不会不优雅?

2、假如只有 singletonObjects 和 singletonFactories 可否实现循环依赖


由图中可知也是不能够实现的。

3、3 级缓存如何实现

1、解决代理问题

因为默认状况下,代理是通过 BeanPostProcessor 来实现,为了解决代理,就须要提前创立代理,那么这个代理的创立就放到 3 级缓存中来进行创立。

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

getEarlyBeanReference 此办法会返回代理 bean

2、解决单例通过第 3 级缓存屡次获取的值不统一


从上图中可知,对象是先从 一级 -> 二级 -> 三级缓存 这样查找,当三级缓存产生了对象后就放入二级缓存中缓存起来,同时删除三级缓存。

3、流程图

四、总结

1、一级缓存 singletonObjects 寄存能够应用的单例。
2、二级缓存 earlySingletonObjects 寄存的是晚期的 Bean,即是半成品,此时还是不可用的。
3、三级缓存singletonFactories 是一个对象工厂,用于创建对象,而后放入到二级缓存中。同时对象如果有 Aop 代理的话,这个对对象工厂返回的就是代理对象。

那能够在 earlySingletonObjects 中间接寄存创立后的代理对象吗?这样是能够解决问题,然而设计可能就不合理了。因为在 Spring 中 Aop的代理是在对象实现之后创立的。而且如果没有产生循环依赖的话,有必要提前创立代理对象吗?分成三级缓存,代码构造更分明,更正当。

正文完
 0