提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 循环依赖
- N个Bean互相引用对方,最终形成闭环。
- 前提保证:
- 创造的所有对象都是==单例对象==.
- 循环依赖的问题:
- 如果是通过==构造器==的方式, 那么没办法解决.
- 如果是通过==set==的方式, 那么可以使用==三级缓存==解决此问题
- 案例:
- ==ref元素==是将目标Bean定义的==实例==注入到属性或构造函数中
- 1.通过==构造函数==进行对象的创建
- 2.通过==set方式==进行对象的创建
- bean的生命周期
- 三级缓存 ==DefaultSingletonBeanRegistry==
- DefaultSingletonBeanRegistry类:
- 一级缓存: singletonObjects
- 用于存放==完全初始化好的 bean对象==,从该缓存中取出的 bean 可以直接使用
- 二级缓存: earlySingletonObjects
- 提前曝光的单例对象的cache,存放==完成实例化但未初始化 bean 对象==(尚未填充属性),用于解决循环依赖
- 三级缓存:singletonFactories:
- 单例对象工厂的cache,存放 ==bean 工厂对象(lambda表达式)==,用于解决循环依赖
- 三级缓存读取顺序:
- Spring解决循环依赖的诀窍:就在于==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的中方法 ![在这里插入图片描述](https://s2.51cto.com/images/blog/202410/04143949_66ff8db5765a031119.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
- DefaultSingletonBeanRegistry
- ==一级缓存 : singletonObjects==
- 一路返回 到AbstractBeanFactory
- AbstractBeanFactory
- 还是==DefaultSingletonBeanRegistry==中 getSingleton方法 只是形参不一样
- getSingleton方法参数之一是==ObjectFactory实例==
- 实例就必须重写抽象的getObject方法 ,spring是用lambda表达式的形式
- lambda表达式![在这里插入图片描述](https://s2.51cto.com/images/blog/202410/04143952_66ff8db89b8e957545.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
- DefaultSingletonBeanRegistry
- 此时一级缓存里还没有a对象
- AbstractAutowireCapableBeanFactory
- ==createBeanInstance(beanName, mbd, args)==; 方法
- 这个方法里面是利用反射创建好 ==空属性 或者默认属性的a对象==
- ==addSingletonFactory(String , ObjectFactory<?> ) {}==
- DefaultSingletonBeanRegistry里面的方法
- 如果一级缓存没有对象![在这里插入图片描述](https://s2.51cto.com/images/blog/202410/04143956_66ff8dbcd9a9e20502.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
- 清空二级缓存![在这里插入图片描述](https://s2.51cto.com/images/blog/202410/04143957_66ff8dbd3034e38345.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
- set集合添加bean对象的名字![在这里插入图片描述](https://s2.51cto.com/images/blog/202410/04143957_66ff8dbd5f69b5833.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
- 一组已注册的单例,按注册顺序包含bean名称的==set集合==![在这里插入图片描述](https://s2.51cto.com/images/blog/202410/04143957_66ff8dbd8acd714821.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
- ==此时三级缓存里 放的是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表达式的实例 }![在这里插入图片描述](https://s2.51cto.com/images/blog/202410/04144011_66ff8dcb10ea162619.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
- 获取ObjectFactory<?> 类型的 lambda表达式实例,然后调用getObject()方法
- ==往二级缓存map添加元素== ,
- (key =beanName ,value =a对象 (此时a对象只实例化 未初始化)}
- ==从三级缓存map里清除, key=a 的元素== ,
- ==三级缓存读取的顺序==
- 此时
- 一路返回
- 一路返回
- 一路返回
- ==往一级缓存添加 实例完且初始化完的 完整状态的b对象==
- 此时
- ==此时b对象是完整转态的b对象,(实例化且初始化完成)==![在这里插入图片描述](https://s2.51cto.com/images/blog/202410/04144017_66ff8dd1c6cca79377.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
- 一路返回
- 一路返回![在这里插入图片描述](https://s2.51cto.com/images/blog/202410/04144019_66ff8dd355fc242149.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
- 一路返回
- 一路返回
- 一路返回
- 此时 ![在这里插入图片描述](https://s2.51cto.com/images/blog/202410/04144021_66ff8dd5dc33943052.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
- 一路返回
- 开始循环 2
- ==此时 a,b 对象 都已创建成功==
- 总结:
- 解决循环依赖的关键
- 1.==singletonFactories这个三级缓存这个Cache里面都是ObjectFactory实例,它是解决问题的关键==
- 2.==经过ObjectFactory.getObject() 获取一个半成品对象==,此时放进了二级缓存earlySingletonObjects内。这个时候==对象已经实例化了但未初始化==,(尚未填充属性)虽然还不完美,但是==对象的引用==已经可以被其它引用了。
循环依赖
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。其实也就是从三级缓存移动(是剪切、不是复制哦~)到了二级缓存.然后再返回获取到的这个对象
此时
- 一级缓存
- 二级缓存
- 三级缓存
一路返回
一路返回
一路返回
往一级缓存添加 实例完且初始化完的 完整状态的b对象
此时
此时b对象是完整转态的b对象,(实例化且初始化完成)
一路返回
一路返回
一路返回
一路返回
一路返回
此时
一路返回
开始循环 2
此时 a,b 对象 都已创建成功
总结:
解决循环依赖的关键
1.singletonFactories这个三级缓存这个Cache里面都是ObjectFactory实例,它是解决问题的关键
2.经过ObjectFactory.getObject() 获取一个半成品对象,此时放进了二级缓存earlySingletonObjects内。这个时候对象已经实例化了但未初始化,(尚未填充属性)虽然还不完美,但是对象的引用已经可以被其它引用了。