什么是循环依赖
在 Spring 中,bean 之间的依赖关系可以通过构造函数注入、Setter 注入、接口注入等方式实现。当两个或多个 bean 相互依赖时,就会形成循环依赖。比如,bean A 依赖于 bean B,而 bean B又依赖于 bean A,这就是循环依赖。
Spring 如何解决循环依赖
Spring使用“三级缓存”来解决循环依赖的问题。三级缓存指的是singletonObjects、earlySingletonObjects和singletonFactories三个Map。
在Spring创建对象时,会先检查 singletonObjects 中是否已经存在该对象的实例,如果存在,则直接返回该实例;如果不存在,则检查 earlySingletonObjects 中是否已经存在该对象的“提前曝光”的代理对象,如果存在,则返回该代理对象,否则就调用singletonFactories 中存储的工厂方法来创建该对象的实例,并将其放入 earlySingletonObjects 中,同时存储一个 Factory 对象到singletonFactories 中。
当对象创建完成之后,就会从 earlySingletonObjects中 移除该对象的代理对象,将完整的对象实例放入 singletonObjects 中,并清空 singletonFactories中的Factory 对象。这样,下次获取该对象的实例时,就可以直接从 singletonObjects 中获取了。
三级缓存是如何解决循环依赖
当出现循环依赖时,Spring 会将正在创建的对象提前曝光,也就是将一个代理对象放到 earlySingletonObjects 中,然后在创建对象时,将代理对象注入到另一个需要依赖该对象的 bean 中。这样,当需要使用该对象时,就可以从 earlySingletonObjects 中获取到代理对象,避免了死循环的出现。
缓存为什么是三级
三级缓存可以保证对象的单例性,同时也可以解决循环依赖的问题。而单例对象的创建和获取是很频繁的操作,所以使用三级缓存可以提高效率。
缓存的放置时间和删除时间
提前曝光来解决循环依赖(不推荐)
除了三级缓存之外,提前曝光是 Spring 解决循环依赖问题的重要手段之一。当 Spring 创建一个 bean 的实例时,如果检测到其依赖了另一个正在创建的 bean,则会将其提前曝光,即将一个代理对象放入 earlySingletonObjects 中,以便在后续创建依赖该 bean 的其他 bean 时,可以直接使用其代理对象,避免了死循环的出现。不过,提前曝光的方法需要手动配置,比较麻烦,所以一般情况下,我们都会使用 Spring 提供的三级缓存来解决循环依赖的问题。
END
总的来说,Spring 是一个非常优秀的 Java 框架,它不仅提供了依赖注入和 AOP 等常用功能,还能够很好地解决循环依赖的问题。而这些都离不开 Spring 框架底层的设计和实现。希望今天的分享能够帮助大家更好地理解 Spring 框架的原理和实现,也希望大家能够继续深入学习和研究 Java 技术,不断提升自己的能力。谢谢大家的阅读!
责任编辑:水告 来源:知其然亦知其所以然