Spring源码--02--三级缓存 解决 循环依赖
Posted 高高for 循环
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring源码--02--三级缓存 解决 循环依赖相关的知识,希望对你有一定的参考价值。
循环依赖
N个Bean互相引用对方,最终形成闭环。
前提保证:
创造的所有对象都是单例对象.
循环依赖的问题:
如果是通过构造器的方式, 那么没办法解决.
如果是通过set的方式, 那么可以使用三级缓存解决此问题
案例:
class A
package springdemo.cy.bean;
public class A {
private B b;
public A(B b) {
this.b = b;
}
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
}
class B
package springdemo.cy.bean;
public class B {
private A a;
public B(A a) {
this.a =a;
}
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
public void show(){
System.out.println("B.....show");
}
}
test.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="a" class="springdemo.cy.bean.A">
<property name="b" ref="b" ></property>
</bean>
<bean id="b" class="springdemo.cy.bean.B">
<property name="a" ref="a"></property>
</bean>
</beans>
ref元素是将目标Bean定义的实例注入到属性或构造函数中
1.通过构造函数进行对象的创建
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springdemo.cy.bean.B;
public class test {
public static void main(String[] args) throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
B bean = context.getBean(B.class);
bean.show();
System.out.println(bean);
}
}
2.通过set方式进行对象的创建
bean的生命周期
三级缓存 DefaultSingletonBeanRegistry
DefaultSingletonBeanRegistry类:
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
...
// 从上至下 分表代表这“三级缓存”
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); //一级缓存
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); // 二级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 三级缓存
...
/** Names of beans that are currently in creation. */
// 这个缓存也十分重要:它表示bean创建过程中都会在里面呆着~
// 它在Bean开始创建时放值,创建完成时会将其移出~
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
/** Names of beans that have already been created at least once. */
// 当这个Bean被创建完成后,会标记为这个 注意:这里是set集合 不会重复
// 至少被创建了一次的 都会放进这里~~~~
private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));
}
一级缓存: singletonObjects
用于存放完全初始化好的 bean对象,从该缓存中取出的 bean 可以直接使用
二级缓存: earlySingletonObjects
提前曝光的单例对象的cache,存放完成实例化但未初始化 bean 对象(尚未填充属性),用于解决循环依赖
三级缓存:singletonFactories:
单例对象工厂的cache,存放 bean 工厂对象(lambda表达式),用于解决循环依赖
三级缓存读取顺序:
/**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//从一级缓存获取
Object singletonObject = this.singletonObjects.get(beanName);
//如果一级缓存中没有,并且已标记这个bean正在被定义
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//从二级缓存获取bean
singletonObject = this.earlySingletonObjects.get(beanName);
//如果二级缓存也拿不到 去三级缓存拿
if (singletonObject == null && allowEarlyReference) {
//从三级缓存取值
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
//如果三级缓存存在值,将三级缓存中的缓存移除,加入二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
- 先从一级缓存singletonObjects中去获取。(如果获取到就直接return)
- 如果获取不到或者对象正在创建中(isSingletonCurrentlyInCreation()),那就再从二级缓存earlySingletonObjects中获取。(如果获取到就直接return)
- 如果还是获取不到,且允许singletonFactories(allowEarlyReference=true)通过getObject()获取。就从三级缓存singletonFactory.getObject()获取。获取不到 return null
- 如果获取到了就从singletonFactories中移除,并且放进二级缓存earlySingletonObjects。其实也就是从三级缓存移动(是剪切、不是复制哦~)到了二级缓存.然后再返回获取到的这个对象
Spring解决循环依赖的诀窍:就在于singletonFactories这个三级缓存。
前提:
- 加入singletonFactories三级缓存的前提是执行了构造器,所以构造器的循环依赖没法解决
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
1.singletonFactories这个三级缓存这个Cache里面都是ObjectFactory实例,它是解决问题的关键
2.经过ObjectFactory.getObject()获取对象后,此时放进了二级缓存earlySingletonObjects内。这个时候对象已经实例化了但未初始化,(尚未填充属性)虽然还不完美,但是对象的引用已经可以被其它引用了。
debug 源码
ClassPathXmlApplicationContext
AbstractApplicationContext
DefaultListableBeanFactory
DefaultListableBeanFactory 继承 DefaultSingletonBeanRegistry
此过程中先创建A对象
AbstractBeanFactory
进入 getSingleton(beanName) 方法;
父类DefaultSingletonBeanRegistry的中方法
DefaultSingletonBeanRegistry
一级缓存 : singletonObjects
一路返回 到AbstractBeanFactory
AbstractBeanFactory
还是DefaultSingletonBeanRegistry中 getSingleton方法 只是形参不一样
getSingleton方法参数之一是ObjectFactory实例
实例就必须重写抽象的getObject方法 ,spring是用lambda表达式的形式
lambda表达式
DefaultSingletonBeanRegistry
此时一级缓存里还没有a对象
AbstractAutowireCapableBeanFactory
createBeanInstance(beanName, mbd, args); 方法
这个方法里面是利用反射创建好 空属性 或者默认属性的a对象
addSingletonFactory(String , ObjectFactory<?> ) {}
DefaultSingletonBeanRegistry里面的方法
如果一级缓存没有对象
清空二级缓存
set集合添加bean对象的名字
一组已注册的单例,按注册顺序包含bean名称的set集合
此时三级缓存里 放的是lambda表达式的实例
进入 populate()方法 做属性填充
AbstractAutowireCapableBeanFactory
BeanDefinitionValueResolver
因为a对象的属性b,是一个对象,
所以此时要从beanFactory.getBean(String name)获取b对象
开始循环
开始循环 1
AbstractBeanFactory
此时a,b两个对象都已实例化完成,但都还未初始化
往三级缓存map 添加元素
进入 populateBean(beanName, mbd, instanceWrapper);
给b对象填充属性
此时a,b对象都已实例化,但都未初始化 属于创建过程中
显然此时二级缓存是获取不到a的,所以singletonObject == null
此时三级缓存map存放着 {key = a ,value= lambda表达式的实例 }
获取ObjectFactory<?> 类型的 lambda表达式实例,然后调用getObject()方法
往二级缓存map添加元素 ,
(key =beanName ,value =a对象 (此时a对象只实例化 未初始化)}
从三级缓存map里清除, key=a 的元素 ,
三级缓存读取的顺序
- 先从一级缓存singletonObjects中去获取。(如果获取到就直接return)
- 如果获取不到或者对象正在创建中(isSingletonCurrentlyInCreation()),那就再从二级缓存earlySingletonObjects中获取。(如果获取到就直接return)
- 如果还是获取不到,且允许singletonFactories(allowEarlyReference=true)通过getObject()获取。就从三级缓存singletonFactory.getObject()获取。获取不到
return null- 如果获取到了就从singletonFactories中移除,并且放进二级缓存earlySingletonObjects。其实也就是从三级缓存移动(是剪切、不是复制哦~)到了二级缓存.然后再返回获取到的这个对象
此时
- 一级缓存
- 二级缓存
- 三级缓存
一路返回
一路返回
一路返回
Spring源码解析-三级缓存与循环依赖
人人都能看懂的Spring源码解析,Spring如何解决循环依赖
0源码基础学习Spring源码系列——Spring如何解决循环依赖