溧水做网站,网站布局模板,建网站做点什么好,中建国际建设公司网站一、概述 循环依赖是指多个bean之间相互依赖#xff0c;形成了一个闭环。比如A依赖于B、B依赖于C、C依赖于A#xff0c;形成了一个圈#xff0c;如#xff1a; 二、循环依赖案例
2.1、构造方法注入产生循环依赖案例
2.1.1、ServiceA
/*** Author : 一叶浮萍归大海* Date…一、概述 循环依赖是指多个bean之间相互依赖形成了一个闭环。比如A依赖于B、B依赖于C、C依赖于A形成了一个圈如 二、循环依赖案例
2.1、构造方法注入产生循环依赖案例
2.1.1、ServiceA
/*** Author : 一叶浮萍归大海* Date: 2023/11/27 9:14* Description:*/
Service
public class ServiceA {private ServiceB serviceB;public ServiceA(ServiceB serviceB) {this.serviceB serviceB;}
}
2.1.2、ServiceB
/*** Author : 一叶浮萍归大海* Date: 2023/11/27 9:14* Description:*/
Service
public class ServiceB {private ServiceA serviceA;public ServiceB(ServiceA serviceA) {this.serviceA serviceA;}
}
2.1.3、MySpringConfig
/*** Author : 一叶浮萍归大海* Date: 2023/11/23 15:29* Description:*/
Configuration
ComponentScan(basePackages {org.star})
public class MySpringConfig {}
2.1.4、AopFullAnnotationMainApp
/*** Author : 一叶浮萍归大海* Date: 2023/11/23 15:14* Description:*/
Slf4j
public class AopFullAnnotationMainApp {public static void main(String[] args) {AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(MySpringConfig.class);ServiceA serviceA context.getBean(serviceA, ServiceA.class);log.info(serviceA:{}, serviceA);}
} 2.1.5、结论 使用构造方法注入属性会产生循环依赖问题。 2.2、set方法注入不会产生循环依赖案例
2.2.1、ServiceAA
/*** Author : 一叶浮萍归大海* Date: 2023/11/27 9:27* Description:*/
Service
public class ServiceAA {Resourceprivate ServiceBB serviceBB;}
2.2.2、ServiceBB
/*** Author : 一叶浮萍归大海* Date: 2023/11/27 9:27* Description:*/
Service
public class ServiceBB {Resourceprivate ServiceAA serviceAA;}
2.2.3、MySpringConfig同上
2.2.4、AopFullAnnotationMainApp
/*** Author : 一叶浮萍归大海* Date: 2023/11/23 15:14* Description:*/
Slf4j
public class AopFullAnnotationMainApp {public static void main(String[] args) {AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(MySpringConfig.class);ServiceAA serviceAA context.getBean(ServiceAA.class);log.info(serviceAA:{}, serviceAA);}
} 2.2.5、结论 使用set方法注入属性不会产生循环依赖问题。 2.2.6、注意事项 默认情况下使用set方法注入属性可以解决循环依赖问题但是有一个前提bean是单例的当把bean设置为多例后再使用set注入时依然会产生循环依赖问题。 三、Spring解决循环依赖的方法
3.1、三级缓存 所谓Spring的三级缓存是指Spring内部解决循环依赖问题的三个Map即 DefaultSingletonBeanRegistry 中定义的三个Map。部分源码如下 3.2、A、B对象在三级缓存中的迁移过程 第一步A创建过程中需要B于是A将自己放到三级缓存里面去实例化B 第二步B实例化的时候发现需要A于是B先查找一级缓存没有再查二级缓存还是没有再查三级缓存于是找到A然后把三级缓存里面的这个A放到二级缓存里面并删除三级缓存里面的A 第三步B顺利完成初始化并将自己放到一级缓存里面注意此时B里面的A依然是创建中的状态然后接着回来创建A此时B已经创建结束直接从一级缓存里面拿到B然后完成创建并将A自己放到一级缓存里面。 3.3、断点顺序
# 参考B站尚硅谷周阳老师录制的视频链接地址如下https://www.bilibili.com/video/BV1Hy4y1B78T?p39spm_id_frompageDrivervd_source72ebc194dbfa51ec950a52c25c337f7c 3.4、解决循环依赖的步骤 第一步Spring创建bean主要分为两个步骤即创建原始bean对象 填充对象属性和初始化 第二步每次创建bean之前Spring都会从缓存中查询该bean是否存在如果缓存中存在则直接拿来用如果没有Spring则去创建原始对象并放入三级缓存中因为是单例只能有一个 第三步当创建完A的原始对象后此时A已经在三级缓存中了接下来为A填充属性这时候发现A依赖B接着又去创建B同样的流程创建完B的原始对象后填充属性时发现B又依赖于AB实例化的时候需要A于是B先从一级缓存里面查找A没有找到接着再查二级缓存还是没有再查三级缓存于是找到了A然后Spring把三级缓存里面的A放到二级缓存里面并删除三级缓存里面的AB顺利完成初始化并将自己放入到一级缓存里面注意此时B里面的属性A依然是创建中的状态然后接着回来继续为A填充属性此时B已经创建结束Spring直接从一级缓存中取出B为A赋值完成A的初始化然后把A自己放入到一级缓存里面并删除二级缓存里面的A此时AB各自完成实例化。 3.5、解决循环依赖的思想 Spring解决循环依赖靠的是bean的 中间态 这个概念而这个中间态指的是 已经实例化但是还没有初始化的状态即半成品实例化的过程又是通过构造器完成的如果A还没有创建出来怎么提前曝光这也就解释了使用构造方法注入属性为什么无法解决循环依赖的问题。 Spring解决单例bean循环依赖的三个Map三级缓存 # 一级缓存单例池存放已经经历了完整生命周期的bean private final MapString, Object singletonObjects new ConcurrentHashMap(256); # 二级缓存存放早期暴露出来的bean对象此时bean的生命周期尚未结束属性还未填充完毕 private final MapString, Object earlySingletonObjects new HashMap(16); # 三级缓存存放可以生成bean的工厂 private final MapString, ObjectFactory? singletonFactories new HashMap(16); 3.6、详细过程