1.为什么学习Spring?
Spring技术是JavaEE开发必备技能,企业开发技术选型命中率>90% 专业角度 简化开发,降低企业级开发的复杂性 框架整合,高效整合其他技术,提高企业级应用开发与运行效率.
学习Spring框架设计思想 学习基础操作,思考操作与思想间的联系 学习案例,熟练应用操作的同时,体会思想.
2.什么是bean?
bean就是spring中被spring容器管理的,或者实例化组装起来的对象。在实际的项目中,对象之间经常是依赖关系,比如A依赖B,那么A要等到B一切工作完成之后,才可以开始自己的工作。
Bean的生命周期:
1.实例化(Instantiation)
2.属性赋值(Populate)
3.初始化(Initialization)
4.销毁(Destruction)
3.什么是循环依赖?
public class A {
@Autowired
private B b;
}
public class B {
@Autowired
private A a;
}
A 里面注入 B,B 里面又注入 A。此时,就发生了“循环依赖”。
4.解决单例模式下的属性循环依赖--使用三级缓存技术
对于多例 Bean 和 Prototype 作用域的 Bean的循环依赖问题,并不能使用三级缓存设计解决
Spring 中,单例 Bean 在创建后会被放入 IoC 容器的缓存池中,并触发 Spring 对该 Bean 的生命周期管理。
保存单例模式的Bean的缓存池中,采用三级缓存技术:(代码如下所示)
/** Cache of singleton objects: bean name --> bean instance */
/** 一级缓存:用于存放完全初始化好的 bean **/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
/** Cache of early singleton objects: bean name --> bean instance */
/** 二级缓存:存放原始的 bean 对象(尚未填充属性),用于解决循环依赖 */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
/** Cache of singleton factories: bean name --> ObjectFactory */
/** 三级缓存:存放 bean 工厂对象,用于解决循环依赖 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
其中,二级缓存和三级缓存都用于解决循环依赖,单例循环的依赖冲突问题可以从bean的生命周期来看,
1.实例化(Instantiation)
2.属性赋值(Populate)
当A要进行到第二步,属性赋值的时候,发现需要依赖B,但是B此时还处在未实例化的阶段。B要实例化,属性赋值的时候,又开始依赖A,但是A也没有完成属性赋值,,缓存中根本找不到完整的初始化对象。因此产生冲突,谁都初始化不了。
缓存层级 | 名称 | 描述 |
第一层缓存 | singletonObjects | 单例对象缓存池,存放的 Bean 已经实例化、属性赋值、完全初始化好(成品) |
第二层缓存 | earlySingletonObjects | 早期单例对象缓存池,存放的 Bean 已经实例化但尚未属性赋值、未执行 init 方法(半成品) |
第三层缓存 | singletonFactories | 单例工厂的缓存 |
5.getSingleton方法中三级缓存的使用
(1)Spring首先从singletonObjects(一级缓存)中尝试获取。
(2)若是获取不到而且对象在建立中,则尝试从earlySingletonObjects(二级缓存)中获取。
(3)若是仍是获取不到而且允许从singletonFactories经过getObject获取,则经过singletonFactory.getObject()(三级缓存)获取。
(4)若是获取到了则将singletonObject放入到earlySingletonObjects,也就是将三级缓存提高到二级缓存中。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Spring首先从singletonObjects(一级缓存)中尝试获取
Object singletonObject = this.singletonObjects.get(beanName);
// 若是获取不到而且对象在建立中,则尝试从earlySingletonObjects(二级缓存)中获取
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//若是仍是获取不到而且允许从singletonFactories经过getObject获取,则经过singletonFactory.getObject()(三级缓存)获取
singletonObject = singletonFactory.getObject();
//若是获取到了则将singletonObject放入到earlySingletonObjects,也就是将三级缓存提高到二级缓存中
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
isSingletonCurrentlyInCreation() 方法用于判断当前单例 Bean 是否正在创建中,即“还没有执行初始化方法”。
比如,A 的构造器依赖了 B 对象因此要先去创建 B 对象,或者在 A 的属性装配过程中依赖了 B 对象因此要先创建 B 对象,这时 A 就是处于创建中的状态。
allowEarlyReference 变量表示是否允许从三级缓存 singletonFactories 中经过 singletonFactory 的 getObject() 方法获取 Bean 对象。
6解决单例Bean属性循环依赖的核心方法
将实例化的A使用下述方法,实例化过后直接放进第三级单例工厂缓存中去(此时,A属于直接越过属性赋值和初始化)
public interface ObjectFactory<T> {
T getObject() throws BeansException;
}
//三级缓存工厂提供了一个接口
创建bean时,有两处比较重要的匿名内部类实现了该接口。一处是 Spring 利用其建立 Bean 的时候,另外一处就是在 addSingletonFactory 方法中,如下代码所示。
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
这段代码发生在 createBeanInstance 以后,单例 Bean 对象A已经实例化(可以通过对象引用定位到堆中的对象),但尚未属性赋值和初始化。
文字描述:
- 创建对象 A,完成生命周期的第一步,即实例化(Instantiation),在调用 createBeanInstance 方法后,会调用 addSingletonFactory 方法,将已实例化但未属性赋值未初始化的对象 A 放入三级缓存 singletonFactories 中。即将对象 A 提早曝光给 IoC 容器。
- 继续,执行对象 A 生命周期的第二步,即属性赋值(Populate)。此时,发现对象 A 依赖对象,所以就会尝试去获取对象 B。
- 继续,发现 B 尚未创建,所以会执行创建对象 B 的过程。
- 在创建对象 B 的过程中,执行实例化(Instantiation)和属性赋值(Populate)操作。此时发现,对象 B 依赖对象 A。
- 继续,尝试在缓存中查找对象 A。先查找一级缓存,发现一级缓存中没有对象 A(因为对象 A 还未初始化完成);转而查找二级缓存,二级缓存中也没有对象 A(因为对象 A 还未属性赋值);转而查找三级缓存 singletonFactories,对象 B 可以通过 ObjectFactory.getObject 拿到对象 A。
- 继续,对象 B 在获取到对象 A 后,继续执行属性赋值(Populate)和初始化(Initialization)操作。对象 B 完成初始化操作后,会被存放到一级缓存中。
- 继续,转到「对象 A 执行属性赋值过程并发现依赖了对象 B」的场景。此时,对象 A 可以从一级缓存中获取到对象 B,所以可以顺利执行属性赋值操作。
- 继续,对象 A 执行初始化(Initialization)操作,完成后,会被存放到一级缓存中。