前面已经写了关于三篇循环依赖的文章,这是一个总结篇
第一篇: 3.1 spring5源码系列--循环依赖 之 手写代码模拟spring循环依赖
第二篇: 3.2spring源码系列----循环依赖源码分析
第三篇: 3.3 Spring5源码---循环依赖过程中spring读取不完整bean的最终
现在总结循环依赖的思想
学了那么多,为什么说见多才能识广呢,知道别人是如何解决某一类问题的,也就是优秀代码的魅力. 这也是为什么要学习别人的代码的原因.
思想才是我们可以在工作中借鉴使用的
1. 循环依赖的三级缓存设计
2. 接口函数
一. 循环依赖的三级缓存设计
再循环依赖的过程中设计了三级缓存,他们的作用分别是
1. 一级缓存: 用来存放完整的bean
2. 二级缓存: 用来存放早期的,纯净的bean
3. 三级缓存: 用来存放接口函数.
@H_
404_34@
/** Cache of singleton objects: bean name to bean instance. */
/**
* 一级缓存 这个就是我们大名鼎鼎的缓存池,用于保存我们所有的实例bean
private final Map<String,Object>
singletonObjects =
new ConcurrentHashMap<>(
256);
* Cache of singleton factories: bean name to ObjectFactory. *
* 三级缓存 该map用户缓存key为beanName,value为objectFactory(包装为早期对象)
singletonFactories =
new HashMap<>(
16* Cache of early singleton objects: bean name to bean instance. *
* 二级缓存,用户缓存我们的key为beanName,value是我们的早期对象(此时对象属性还没有...)
earlySingletonObjects =
16);
细细想来,这三个缓存都非常有存在的必要.
1.1 引入一级缓存
刚开始,只有一级缓存,在整个bean创建完成以后,将其完整的bean放入到一级缓存中. 这样有什么问题?
1. bean创建一共有三大步骤,(实例化,属性赋值,初始化) 等到整个过程都创建完,在存入一级缓存,多线程怎么办? 第一个线程创建bean的过程中,又来了一个线程,他发现一级缓存这时候还没有,就回去再次创建. 那不就重复了么? ioc要求,bean是单例的.
2. 加锁,加锁能否解决这个问题? 能,但是效率超级低. 对一级缓存加锁,那么所有的对象创建过程中都要等待. 哪怕人家已经创建成功过. 效率太低,不能接受
3. 于是就引入了二级缓存.
1.2 引入二级缓存
二级缓存的引入,可以解决一级缓存创建bean链路过长的问题,他在bean一旦被创建,立刻就放入到二级缓存. 整个bean创建完成以后,在放入到一级缓存,删除二级缓存. 这样做可以解决多线程创建bean的问题. 缩短了整个链路. 同时,每次从缓存中先获取bean,如果一级缓存中已经有了,那么直接返回. 不用在执行后面的创建代码
那么,二级缓存有什么问题呢?
这就还需要知道一个问题,那就是动态代理创建bean. 什么时候,去使用动态代理创建bean? 通常我们说在初始化之后,调用bean的后置处理器创建bean. 这只是大多数bean创建动态代理的时候. 那如果有循环依赖呢? 有循环依赖,还在初始化之后创建就晚了. 这是需要在实例化之后创建. 这样,动态代理的代码就和创建bean耦合在一块了. 违背单一性原则.
于是,引入了三级缓存
1.3 引入三级缓存
三级缓存的引入是为了解决耦合问题. 让每一个方法只做一件事. 巧妙的使用了接口函数.
这个接口函数什么用呢? 就相当于js中的回调函数. 我在前面定义好,但是不执行. 直到满足条件了,才执行. 这个方法,可以大范围应用到实践工作中.
比如: 调用动态代理创建bean. 刚开始实例化完成以后,我就赋予你这个能力,你可以调用动态代理. 但是,到后面,你是否真的能够运用这个能力呢? 不一定,只有满足条件,才会运用这个能力.
在循环依赖源码中,两次使用到接口函数的方式.
第一个是创建bean的时候. 第二个是三级缓存
下面来看看源码,
第一次: 创建bean的时候,定义了一个钩子函数createBean()
@H_
404_34@sharedInstance =
getSingleton(beanName,
() -> {
try {
// 这里定义了一个钩子函数. 此时只是定义,并不执行. 在真正需要创建bean的地方才会执行
return createBean(beanName,mbd,args);
}
catch (BeansException ex) {
Explicitly remove instance from singleton cache: It might have been put there
eagerly by the creation process,to allow for circular reference resolution.
Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
实际上调用的时机是: 在getSingleton方法里面. 回调接口函数.
@H_
404_34@
public Object
getSingleton(String beanName,
ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName,"Bean name must not be null");
synchronized (this.singletonObjects) {
第一步: 从一级缓存中获取单例对象
Object singletonObject =
this.singletonObjects.
get(beanName);
if (singletonObject ==
null) {
if (
.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,1)">Singleton bean creation not allowed while singletons of this factory are in destruction " +
(Do not request a bean from a beanfactory in a destroy method implementation!));
}
if (logger.isDebugEnabled()) {
logger.debug(Creating shared instance of singleton bean '" + beanName +
' 第二步: 将bean添加到singletonsCurrentlyInCreation中,表示bean正在创建
beforeSingletonCreation(beanName);
boolean newSingleton =
false;
boolean recordSuppressedExceptions = (
this.suppressedExceptions ==
);
(recordSuppressedExceptions) {
this.suppressedExceptions =
new LinkedHashSet<>
();
}
{
// 第三步: 这里调用getObject()钩子方法,就会回调匿名函数,调用singletonFactory的createBean()
singletonObject = singletonFactory.getObject();
newSingleton =
true;
}
(IllegalStateException ex) {
Has the singleton object implicitly appeared in the meantime ->
if yes,proceed with it since the exception indicates that state.
singletonObject =
(beanName);
) {
throw ex;
}
}
(BeanCreationException ex) {
(recordSuppressedExceptions) {
for (Exception suppressedException :
.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
ex;
}
finally {
;
}
afterSingletonCreation(beanName);
}
(newSingleton) {
addSingleton(beanName,singletonObject);
}
}
singletonObject;
}
}
第二次调用: 是在三级缓存定义的时候
调用addSingletonFactory(...)定义了一个钩子函数. 这里仅仅是定义,并不执行
@H_
404_34@
把我们的早期对象包装成一个singletonFactory对象,该对象提供了getObject()方法,把静态的bean放到三级缓存中去了.
addSingletonFactory(beanName,() -> getEarlyBeanReference(beanName,bean));
然后进入到addSingletonFactory内部,只是把singletonFactory放入到了三级缓存中,这里只是定义,也并没有执行
@H_
404_34@
protected void addSingletonFactory(String beanName,ObjectFactory<?>
singletonFactory) {
Assert.notNull(singletonFactory,1)">Singleton factory must not be nullif (!
.singletonObjects.containsKey(beanName)) {
加入到三级缓存中,暴露早期对象用于解决循环依赖.
this.singletonFactories.put(beanName,singletonFactory);
从二级缓存中删除
.earlySingletonObjects.remove(beanName);
添加到已经注册的singleton实例.
.registeredSingletons.add(beanName);
}
}
}
什么时候执行的呢? 再从缓存中获取对象的时候.
@H_
404_34@
@Nullable
protected Object 从一级缓存中获取bean实例对象
Object singletonObject = (beanName);
*
* 如果在第一级的缓存中没有获取到对象,并且singletonsCurrentlyIncreation为true,也就是这个类正在创建.
* 标明当前是一个循环依赖.
*
* 这里有处理循环依赖的问题.-- 我们使用三级缓存解决循环依赖
*/
null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (.singletonObjects) {
*
* 从二级缓存中拿bean,二级缓存中的对象是一个早期对象
* 什么是早期对象?就是bean刚刚调用了构造方法,还没有给bean的属性进行赋值,和初始化,这就是早期对象
*/
singletonObject = this.earlySingletonObjects.(beanName);
allowEarlyReference) {
*
* 从三级缓存拿bean,singletonFactories是用来解决循环依赖的关键所在.
* 在ios后期的过程中,当bean调用了构造方法的时候,把早期对象包装成一个ObjectFactory对象,暴露在三级缓存中
*/
ObjectFactory<?> singletonFactory = this.singletonFactories.(beanName);
if (singletonFactory != ) {
/**
* 在这里通过暴露的ObjectFactory包装对象. 通过调用他的getObject()方法来获取对象
* 在这个环节中会调用getEarlyBeanReference()来进行后置处理
*/
singletonObject = singletonFactory.getObject();
把早期对象放置在二级缓存中
.earlySingletonObjects.put(beanName,singletonObject);
删除三级缓存
.singletonFactories.remove(beanName);
}
}
}
}
singletonObject;
}
在这里调用三级缓存, singletonObject = singletonFactory.getObject(); 回调钩子函数.