spring bean的循环依赖

在Spring框架中,Bean的循环依赖是一个常见的问题,它指的是两个或多个Bean之间通过构造函数、Setter方法或字段注入等方式形成了相互依赖的闭环。Spring框架提供了强大的依赖注入功能,同时也提供了多种机制来处理循环依赖的情况,确保应用能够正确启动和运行。

要进行了解spring的循环依赖,我们先来进行看下spring的生命周期

1.Spring Bean生命周期概述

spring的生命周期主要包含以下几个阶段

• 容器启动阶段

•Bean对象实例化阶段

•bean属性的注入阶段

•bean的初始化阶段

•bean缓存阶段

•bean销毁阶段

2.生命周期各阶段详解

2.1 容器启动阶段

我们程序员通过XML配置或Java配置(如使用@Configuration注解的类)定义Spring应用的上下文配置。配置中指定了组件扫描的包路径(通过@ComponentScan<context:component-scan>

扫描和实例化BeanDefinition对象。并将BeanDefinition对象放入到BeanDefinitionMap中。注册BeanPostProcessor,验证BeanDefinition对象是否合格。

2.2 Bean对象实例化阶段

推测Bean对象的实例化方法,并进行实例化操作。

2.3 bean属性的注入阶段

查找注入信息,完成注解解析和属性注入

2.4 bean的初始化阶段

各种Aware的回调,各种初始化方法的回调,对bean的扩展例如aop

2.5 bean缓存阶段

各种临时变量的删除操作,缓存到单例池中

2.6 bean销毁阶段

销毁方法的回调,移除单例池。

3.创建bean方法的主要逻辑

4.循环依赖

spring中的循环依赖主要是依赖的是三级缓存。这个三级缓存是我们程序员给取的名字,并不是spring官方起的名字。这个三级缓存分别是singletonObjects(一级缓存),earlySingletonObjects(二级缓存),singletonFactories(三级缓存)。

singletonObjects:也称作单例池,主要是存放的最终形态的单例bean,一般获取一个bean都是从这个集合中进行获取。

singletonFactories:二级缓存,主要存放的是ObjectFactory,作用主要是为了进行创建一个对象,这个缓存中存放的是一个工厂。

earlySingletonObjects:三级缓存,主要进行存放的是过渡的bean

假设我们现在有两个类 一个M类 一个N类,M依赖N,N同时也依赖M

@Component
public class N {

    @Autowired
    private  N n;
}

@Component
public class M {

    @Autowired
    private  N n;

}


我们接下来进行分析一下创建M,N类的时候,这三个集合的数据变化的逻辑 这里指进行分析M,N这两个对象的情况,spring内置的那些就不在考虑的范围内。

M类和N类的循环依赖流程如下所示:

1.首先我们进行M对象的创建操作,当创建M对象执行到populateBean方法的时候,此时的各个集合的情况如下:

2.当进行执行populateBean方法需要对M里的n属性进行复制的时候,会从容器中进行获取n 此时发现容器中不存在n属性,那么就会接着走上面进行创建bean的流程。这个也会走到populateBean方法,此时这三个集合的情况就如下所示:

3.在给N类的m属性进行赋值的时候,需要进行获取m属性值的时候这个时候会进行调用getSingleton方法。里面进行删除了一些代码。

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   //从单例池中获取对象信息
    Object singletonObject = this.singletonObjects.get(beanName);
    //此时进行设置N类中的m对象 这个时候从单例池中获取m对象发现对象为空
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      synchronized (this.singletonObjects) {
        // 从二级缓存中进行获取m对象,发现缓存中也没有对象信息
         singletonObject = this.earlySingletonObjects.get(beanName);
	 if (singletonObject == null && allowEarlyReference) {
               //从三级缓存中进行进行获取factory工厂
	       ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
		if (singletonFactory != null) {
                    //factory工厂不为null 进行创建对象信息
		    singletonObject = singletonFactory.getObject();
                    // 将创建好的对象信息 存放到二级缓存中
		    this.earlySingletonObjects.put(beanName, singletonObject);
		     //三级缓存中删除工厂类对象
                    this.singletonFactories.remove(beanName);
		 }
	   }
	}
   }
   return singletonObject;
}

这个时候的三个集合就会发生变化,变化之后的情况如下:

4. N类初始化完成之后的情况

5.问题与反思

为何需要三级缓存,二级缓存(singletonFactories)只进行存放一个半成品的bean为何不可以。二级缓存(singletonFactories)有什么用呢,二级缓存(singletonFactories)中存放的是一个工厂类,这个工厂类可以进行创建对象,那spring为啥要在二级缓存(singletonFactories)中存放一个工厂呢,这块有什么别的深意呢,笔者目前认为这块是在spring Aop的时候可以通过二级缓存(singletonFactories)进行创建一个代理对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小园子的小菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值