栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring使用三级缓存解决循环依赖

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring使用三级缓存解决循环依赖

循环依赖:

@Service
public class TestService1 {
 
    @Autowired
    private TestService2 testService2;
 
    public void test1() {
    }
}

@Service
public class TestService2 {
 
    @Autowired
    private TestService1 testService1;
 
    public void test2() {
    }
}

在对象TestService1创建过程中,需要注入TestService2,因为容器中没有TestService2,则去创建TestService2,TestService2创建过程中又需要注入TestService1,而TestService1在等待TestService2的创建,TestService2在等待TestService1的创建,导致两者都无法创建成功,无法加入到单例池供用户使用。

Spring则通过三级缓存来解决循环依赖的问题,另外如果对象的作用范围是Prototype,则无法通过三级缓存解决循环依赖,会抛出BeanCurrentlyInCreationException异常,构造注入的方式,也无法解决循环依赖,只有set注入可以解决。

  • 一级缓存存放实例化对象 。
  • 二级缓存存放已经在内存空间创建好但是还没有给属性赋值的对象。
  • 三级缓存存放对象工厂,用来创建提前暴露到bean的对象。

一级缓存-singletonObjects是用来存放就绪状态的Bean。保存在该缓存中的Bean所实现Aware子接口的方法已经回调完毕,自定义初始化方法已经执行完毕,也经过BeanPostProcessor实现类的postProcessorBeforeInitialization、postProcessorAfterInitialization方法处理;

二级缓存-earlySingletonObjects是用来存放早期曝光的Bean,一般只有处于循环引用状态的Bean才会被保存在该缓存中。保存在该缓存中的Bean所实现Aware子接口的方法还未回调,自定义初始化方法未执行,也未经过BeanPostProcessor实现类的postProcessorBeforeInitialization、postProcessorAfterInitialization方法处理。如果启用了Spring AOP,并且处于切点表达式处理范围之内,那么会被增强,即创建其代理对象。

这里额外提一点,普通Bean被增强(JDK动态代理或CGLIB)的时机是在AbstractAutoProxyCreator实现的BeanPostProcessor的postProcessorAfterInitialization方法中,而处于循环引用状态的Bean被增强的时机是在AbstractAutoProxyCreator实现的SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference方法中。

三级缓存-singletonFactories是用来存放创建用于获取Bean的工厂类-ObjectFactory实例。在IoC容器中,所有刚被创建出来的Bean,默认都会保存到该缓存中。


testService1先去一级缓存看有没有实例,发现没有,继续去二级缓存查看,发现没有,去三级缓存查看,发现没有实例就创建实例,在创建的过程中,提前暴露,添加到三级缓存里。

这个时候进行属性赋值,发现还有一个testService2,它没有赋值,是一个空的,就从一级缓存中去看testSerivce2有没有实例,发现没有,去二级查看发现没有,去三级缓存查看,发现没有,就创建实例,也提前暴露,添加到三级缓存里面。

这个时候testSerivce2对象里面发现testService1里面没有赋值,然后对testService1进行赋值,从一级缓存去查看,发现没有,去二级查看,发现没有,去三级查看,发现有,就把实例testService1从三级缓存添加到二级缓存里面,把实例testService1三级缓存的实例删除,这个时候,testService2里面有实例对象,对象里面的testService1也有值了,就是一个可以使用的实例对象了,就把这个对象移动到一级缓存里面,把三级缓存里面的testService2删除。

这个时候testService1里面的testService2属性就可以从一级缓存里面获取这个testService2实例了,把它进行赋值填充,testService1也完成了实例化,把testService1从二级缓存移动到一级缓存里面,把testService1在二级缓存的实例也删除。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/876954.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号