什么是循环依赖?
循环依赖就是spring在初始化bean时两个不同的bean你依赖我,我依赖你的情况
例如a依赖b,b依赖a,当ioc容器初始化a时,发现它依赖于b,然后去创建b,创建b的时候又发现b依赖于a,而容器中不存在a,如果不想办法解决,这就会陷入死循环
例如下面这个代码,就是典型的循环依赖
// spring 配置类,启用组件扫描
@configuration
@componentscan
class appconfig {
}
// author 服务类,依赖 bookservice
@service
class authorservice {
@autowired
bookservice bookservice;
}
// book 服务类,依赖 authorservice
@service
class bookservice {
@autowired
authorservice authorservice;
}
// 程序入口类,测试循环依赖注入
public class springcirculardependencysingleclass {
public static void main(string[] args) {
applicationcontext annotationconfigapplicationcontext = new annotationconfigapplicationcontext(appconfig.class);
bookservice bookservice = (bookservice) annotationconfigapplicationcontext.getbean("bookservice");
system.out.println(bookservice.authorservice);
authorservice authorservice = (authorservice) annotationconfigapplicationcontext.getbean("authorservice");
system.out.println(authorservice.bookservice);
}
} 运行这个项目,会发现它是正常运行的,这就表示spring在背后做了一些工作解决了循环依赖的问题
如何解决?
spring是使用三级缓存的模式来解决循环依赖问题的,其实两级缓存也是能够解决一般的循环依赖问题的,三级缓存主要是为了更好的解决带有aop的bean的循环依赖情况
这里先用两级缓存结构来初步阐述思想
采用两级缓存解决
spring解决循环依赖的关键在于巧妙利用缓存机制。在spring的实现中,主要涉及两个重要的map:
- singletonobjects:这是一个单例池,存放的是经历了完整spring生命周期的bean实例。这些bean的所有依赖都已成功填充,处于完全可用状态。
- earlysingletonobjects:该map用于存放提前暴露出来的bean对象。这些bean刚刚创建完成,但尚未经历完整的spring生命周期,其依赖尚未填充完毕。
假设此时有两个bean分别叫a、b,它们互相依赖
解决循环依赖的具体步骤如下:
- 1.先创建a的实例对象,在a的依赖注入之前,将a的早期对象放入earlysingletonobjects中去,然后开始给a注入依赖,发现依赖于b(此时两级缓存中都没有b),于是转去创建b
- 2.创建b的实例对象,将b的早期对象放入earlysingletonobjects,然后给b注入依赖,发现b依赖于a,于是去缓存中查找符合条件的bean
- 3.先从singletonobjects中查找,发现没有,然后去earlysingletonobjects查找,发现存在a的早期对象,于是返回这个早期对象
- 4.将a注入到b中,然后将b放入singletonobjects中去
- 5.这个时候a可以从singletonobjects中获取b的实例,然后将完整的a放入singletonobjects中,循环依赖问题得以解决
需要aop的bean的循环依赖问题?
当一个bean需要使用增强时,我们需要的是它的代理对象而不是它的原型对象,这个时候简单的两级缓存结构并不能很好的解决这个问题,所以spring选择了三级缓存结构来解决
(两级缓存的解决思路是,在将早期对象放入earlysingletonobjects中前,先判断一下该对象是否需要aop,如果需要的话生成该对象的代理对象放入earlysingletonobjects中
但是!spring的理念是尽量的把aop的部分放到构造bean的后期解决,而不是上来就直接生成一个代理对象,而且过早的生成代理对象也会额外造成空间和时间的消耗)
三级缓存解决
spring引入了一个新的map singletonfactories 来解决这个问题。
singletonfactories 存放的是 objectfactory 类型的工厂方法。
当创建完对象后,并不立即进行aop增强,而是将获取该对象的工厂方法放入 singletonfactories 。
当发生循环依赖需要获取对象时,如果从 earlysingletonobjects 中无法获取到合适的对象,就从 singletonfactories 中取出工厂方法并执行,从而获取经过aop增强后的对象。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论