网站运营优化培训,线上运营推广,上海营业执照注册,wordpress博客小工具标签Spring三级缓存解决循环依赖
一 Spring bean对象的生命周期 二 三级缓存解决循环依赖
实现原理解析 spring利用singletonObjects, earlySingletonObjects, singletonFactories三级缓存去解决的#xff0c;所说的缓存其实也就是三个Map 先实例化的bean会通过ObjectFactory半…Spring三级缓存解决循环依赖
一 Spring bean对象的生命周期 二 三级缓存解决循环依赖
实现原理解析 spring利用singletonObjects, earlySingletonObjects, singletonFactories三级缓存去解决的所说的缓存其实也就是三个Map 先实例化的bean会通过ObjectFactory半成品提前暴露在三级缓存中 我们假设现在有这样的场景AService依赖BServiceBService依赖AService
1 AService首先实例化实例化通过ObjectFactory半成品暴露在三级缓存中
2填充属性BService发现BService还未进行过加载就会先去加载BService
3再加载BService的过程中实例化也通过ObjectFactory半成品暴露在三级缓存
4填充属性AService的时候这时候能够从三级缓存中拿到半成品的ObjectFactory 拿到ObjectFactory对象后调用ObjectFactory.getObject()方法最终会调用getEarlyBeanReference()方法getEarlyBeanReference这个方法主要逻辑大概描述下如果bean被AOP切面代理则返回的是beanProxy对象如果未被代理则返回的是原bean实例。
这时我们会发现能够拿到bean实例(属性未填充)然后从三级缓存移除放到二级缓存earlySingletonObjects中而此时B注入的是一个半成品的实例A对象不过随着B初始化完成后A会继续进行后续的初始化操作最终B会注入的是一个完整的A实例因为在内存中它们是同一个对象。
如果这个bean被AOP进行了切面代理singleFactory.getObject()方法每次执行都会是一个新的代理对象假设这里只有一级和三级缓存的话我每次从三级缓存中拿到singleFactory对象执行getObject()方法又会产生新的代理对象这是不行的因为AService是单例的所有这里我们要借助二级缓存来解决这个问题将执行了singleFactory.getObject()产生的对象放到二级缓存中去后面去二级缓存中拿没必要再执行一遍singletonFactory.getObject()方法再产生一个新的代理对象保证始终只有一个代理对象。
总结 为了解决循环依赖问题Spring采用三级缓存Three-Level Cache的机制。具体步骤如下
1 创建对象并放入singletonObjects缓存当创建一个Bean时Spring会先尝试从singletonObjects缓存中获取该Bean实例如果找到则直接返回。如果没有找到则进入下一步。
2提前暴露对象在创建Bean的过程中当Spring发现存在循环依赖时会先提前暴露正在创建的Bean并将其放入earlySingletonObjects缓存中。这样可以避免后续循环依赖时的死锁情况。
3创建对象并完成依赖注入Spring会继续创建当前Bean并进行依赖注入。如果依赖中仍然存在循环依赖Spring会使用ObjectFactory或Provider延迟注入依赖。这样可以确保所有的依赖都已经创建完成。
4添加到singletonObjects缓存当Bean创建完成后会将其放入singletonObjects缓存中以供后续的依赖注入使用。
解决办法 在Spring中如果出现循环依赖问题可以采取以下几种方式来解决
1构造函数注入使用构造函数注入代替字段注入或setter注入。通过将依赖关系作为构造函数的参数传递而不是直接在类中定义成员变量并确保依赖关系的顺序正确可以避免循环依赖的问题。
2使用Lazy注解使用Lazy注解延迟加载Bean。通过在循环依赖的其中一个Bean上添加Lazy注解使其延迟初始化从而打破循环依赖的死锁情况。
3使用代理模式当出现循环依赖时可以通过使用代理模式来解决。Spring提供了两种类型的代理JDK动态代理和CGLIB代理。可以根据具体情况选择合适的代理方式。
4使用Setter注入将字段注入改为使用setter注入。通过在setter方法上使用Autowired注解显式地控制依赖关系的注入顺序以避免循环依赖。
5重新设计代码结构有时循环依赖问题可能是由于类之间的紧密耦合导致的。在这种情况下重新审视代码结构将相关的功能进行合理划分减少或消除循环依赖。