我来故意制造这么一个程序异常报错,创建三个对象 [ A调用B, B调用C, C调用A ] 这么一个闭环。然后,用三级缓存解决单列bean实例化的依赖闭环。
// The three-level cache to solve the single instance of circular dependency.
// Bean A → Bean B → Bean C→ Bean A
// StudentA
public class StudentA {
private StudentB studentB ;
public void setStudentB(StudentB studentB) {
this.studentB = studentB;
}
public StudentA() {
}
public StudentA(StudentB studentB) {
this.studentB = studentB;
}
}
// StudentB
public class StudentB {
private StudentC studentC ;
public void setStudentC(StudentC studentC) {
this.studentC = studentC;
}
public StudentB() {
}
public StudentB(StudentC studentC) {
this.studentC = studentC;
}
}
// StudentC
public class StudentC {
private StudentA studentA ;
public void setStudentA(StudentA studentA) {
this.studentA = studentA;
}
public StudentC() {
}
public StudentC(StudentA studentA) {
this.studentA = studentA;
}
}
xml 配置 [ 错误示范代码, 用constructor构造器构建bean ]
<bean id="a" class="com.student.StudentA">
<constructor-arg index="0" ref="b"></constructor-arg>
</bean>
<bean id="b" class="com.student.StudentB">
<constructor-arg index="0" ref="c"></constructor-arg>
</bean>
<bean id="c" class="com.student.StudentC">
<constructor-arg index="0" ref="a"></constructor-arg>
</bean>
那来运行下
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//System.out.println(context.getBean("a", StudentA.class));
}
}
Error 报错
caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
看我上方这段代码,这是一个示范性的错误代码,用构造方法是没有办法解决循环依赖的问题, 因此异常报错 🔴 ⚡️⚡️
思考下
如何解决这种循环依赖 ?🌟
🌈✍🏻用三级缓存处理依赖闭环 { singletonObjects一级缓存 、earlySingletonObjects二级缓存 、singletonFactories三级缓存 }** 用构造器创建的bean是没有办法解决依赖闭环的问题,把实例化和初始化分开处理,再set 注入属性成品完整的bean对象。
为什么是三级缓存处理 ?为什么不是只使用一级缓存或者是二级缓存就能解决它,非得用三级缓存?🌟
🌈✍🏻 因为在一级缓存中放的是成品对象, 二级缓存放半成品, 这种半成品是并没有applyPropertyValues的bean对象进行属性填充, 对象的实例化和初始化分开处理[ 其间过程给对象赋值时,并不是一个完整的对象,而是把半成品对象赋值过去了 ],一级缓存放成品对象,二级缓存放半成品对象 [ 通过AOP代理生成的对象 ],三级缓存放lambda表达式,用ObjectFactory仅有的一个方法,可传lambda表达式, 可传匿名内部类, 通过 getObject () 执行的逻辑, 会对前期的半成品对象进行覆盖操作。
.xml 配置 [ 正确示范用, 用set注入property属性构建bean ]
// Setter injection (single example)
<!--scope="singleton" 默认是采用singleton->
<bean id="a" class="com.student.StudentA" scope="singleton">
<property name="studentB" ref="b"></property>
</bean>
<bean id="b" class="com.student.StudentB" scope="singleton">
<property name="studentC" ref="c"></property>
</bean>
<bean id="c" class="com.student.StudentC" scope="singleton">
<property name="studentA" ref="a"></property>
</bean>
一级缓存源码 [ 存已创建的bean对象 ]
// maintains all created Bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
二级缓存源码[ 存对外暴露的bean对象,仅仅是未属性注入的实例化对象,已实例化但未完成初始化的半成品 ]
// maintaining early exposed Bean(Only instantiation, no attribute injection)
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
三级缓存源码[ 保存ObjectFactory ]
// maintaining and creating Bean Of ObjectFactory(Key to solve circular dependency)
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
ObjectFactory 函数式接口, 三级缓存中传参以lambda表达式覆盖前期的半成品
public Object getObjectInstance(Object obj, Name name, Context nameCtx,
Hashtable<?,?> environment)
throws Exception;
}
1 reflesh() > 2 finishBeanFactoryInitialization(beanFactory); & beanFactory.perInstantiateSingletons(); > 3 开始完成bean的构建 > 4 getBean () > 5 doGetBean () > 6 getSingleton () > 7 createBean () > 8 doCreateBean ()
实例化和初始化是分开处理的,这一级缓存singletonObjects实例化对象,二级缓存earlySingletonObjects就犹如下方这盘半成品的菜, 通过AOP代理对象, 未加工入锅制熟的半成品利用三级缓存的ObjectFactory,在IOC容器中找到原始对应的那个半成品对象注入属性,就是一个完成的成品。从而完美的解决这种依赖的闭环。