三级缓存解决循环依赖,跳出依赖地狱

我来故意制造这么一个程序异常报错,创建三个对象 [ 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容器中找到原始对应的那个半成品对象注入属性,就是一个完成的成品。从而完美的解决这种依赖的闭环。

image.png
image.png
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容