IOC控制反转和DI依赖注入
看过主包上篇的内容应该就很好理解这两个Spring特性功能了,现在就再来总结一下,IOC就是从以前我们自己手动new一个Bean变成了由Spring容器管理Bean的生命周期,也就是Bean的生死基本上不用我们管了,而这个DI依赖注入就是把Spring容器管理的Bean的对象的地址引用赋值给需要使用的类的变量中,让这个Bean可复用,这样来看是不是就很简单了。
循环依赖
循环依赖是指两个或多个Bean相互依赖形成的环形引用链,导致容器无法完成依赖注入。
这个应该很好理解吧,就和主包之前JVM系列中引用计数法一样,是一个矛盾的问题,解决的办法也很多,但是Spring在进行Bean的加载的时候使用的就是三级缓存的技术,什么是三级缓存呢?就是把Bean分成三个池子,大池子就是完成好的Bean对象,二级就是半成品的Bean对象,三角呢就是刚刚实例化的Bean对象,他们三个都是map结构,然后我们来说一下他们的区别。
一级缓存:singletonObjects
- 存储内容:完全初始化好的单例Bean
- 数据结构:ConcurrentHashMap<String, Object>
- 特点:
- 存储的是成品Bean
- 所有属性已注入
- 初始化方法已执行
- 可以被直接使用
二级缓存:earlySingletonObjects
- 存储内容:提前暴露的Bean早期引用
- 数据结构:HashMap<String, Object>
- 特点:
- 存储的是半成品Bean
- 已实例化但未完成属性注入
- 用于解决循环依赖
- 可能被AOP代理包装
- 生命周期:
- Bean实例化后放入
- Bean完全初始化后移除
三级缓存:singletonFactories
- 存储内容:Bean的ObjectFactory
- 数据结构:HashMap<String, ObjectFactory<?>>
- 特点:
- 存储的是Bean工厂
- 可以生成早期引用
- 支持AOP代理的延迟生成
- 在第一次解决循环依赖后移除
- 核心价值:
- 解决AOP代理与循环依赖的冲突
- 延迟代理对象的生成时机
其实从简单层面来讲使用二级缓存就可以解决这个循环依赖的问题了,但是我们Spring是有扩展机制的,还记不记得上一篇说Bean的生命周期的时候,有说到过属性注入后、Aware接口回调后有过BeanPostProcessor方法,这个里面会调用一个InitializingBean方法这个就是扩展Bean的方法,他会检查当前这个Bean是否生成了代理对象,如果有又做了哪些操作也就是AOP。
假如我们使用二级缓存,我们以下面的图为例,A放在二级缓存、然后到B调用A,B从二级缓存拿到了A,然后B放入一级缓存,回到A这个时候调用C,那么A还是个半成品会放到二级缓存中,然而在Map中Key是无法相同存在的,那么C完成后,A怎么知道自己是否执行了AOP呢?就算有那C怎么知道拿那个map呢?所以三件缓存就是为了解决代理的问题的。
这个是大概的一个流程,这个部分可能很绕,然后不理理解的小伙伴建议还是上B站看视频吧,文章没办法这么清楚的表达思路。
总结
本篇主要说了循环依赖的问题和解决循环依赖的办法——三级缓存,AOP与动态代理下一期再说吧,主包周末水一下。
评论前必须登录!
注册