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

我来故意制造这么一个程序异常报错,创建三个对象 [ 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
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,036评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,046评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,411评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,622评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,661评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,521评论 1 304
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,288评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,200评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,644评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,837评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,953评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,673评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,281评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,889评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,011评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,119评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,901评论 2 355

推荐阅读更多精彩内容