spring bean循环依赖源码分析(包括bean生命周期)

前言:本文主要从spring源码来分析spring bean的生命周期以及spring如何解决bean循环依赖问题。

1、何为spring bean循环依赖问题?

 1.1、创建3个类,A、B、C

@Component
public class A {

    @Autowired
    private B b;

}

@Component
public class B {

    @Autowired
    private C c;

}

@Component
public class C {

    @Autowired
    private A a;

}

以上A、B、C三个类中,A需要注入B,B需要注入C,C需要注入A,在spring ioc容器中,就形成了一个循环依赖。

2、spring bean生命周期

2.1、在分析spring bean循环依赖问题之前,我们需要了解下spring bean生命周期(即spring bean的初始化过程),因为spring bean的循环依赖是发生在spring bean生命周期中的。

2.2、spring bean生命周期图例

2.3、调用BeanFactory#getBean方法时,发生了什么?

在BeanFactory#getBean方法的完整逻辑中,spring设计了bean的三级缓存。

/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
        singletonObject = this.earlySingletonObjects.get(beanName);
        if (singletonObject == null && allowEarlyReference) {
            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            if (singletonFactory != null) {
                singletonObject = singletonFactory.getObject();
                this.earlySingletonObjects.put(beanName, singletonObject);
                this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

singletonObjects:一级缓存,存放已初始化的bean实例

earlySingletonObjects:二级缓存,存放提前曝光的bean对象

singletonFactories:三级缓存,存放提前曝光bean对象的ObjectFactory

当我们调用BeanFactory#getBean方法时,首先从singletonObjects缓存中获取,如果不存在,再从earlySingletonObjects缓存中获取,如果不存在,再从singletonFactories缓存中获取,如果三级缓存都不存在,则会创建bean,触发完整的bean生命周期流程。

如果从singletonFactories缓存中获取到了bean对象的ObjectFactory,则调用ObjectFactory#getObject方法生成bean,并存放到earlySingletonObjects缓存中。

2.4、 spring bean生命周期说明

2.4.1、实例化java对象

2.4.2、如果bean的scope为单例,且开启了提前曝光bean映射,则将bean封装成ObjectFactory,调用addSingletonFactory方法将bean添加到singletonFactories中

2.4.3、调用AbstractAutowireCapableBeanFactory#populateBean方法填充属性

2.4.4、如果bean实现了BeanNameAware接口,则调用BeanNameAware#setBeanName方法,传递beanName

2.4.5、如果bean实现了BeanFactoryAware接口,则调用BeanFactoryAware#setBeanFactory方法,传递spring工厂自身

2.4.6、如果bean实现了ApplicationContextAware接口,则调用ApplicationContextAware#setApplicationContext,传递spring上下文(这一步调用ApplicationContextAware#setApplicationContext方法也是由2.3.6的BeanPostProcessor#postProcessBeforeInitialization方法来触发的,因为在初始化BeanFactory时,会通过ApplicationContextAwareProcessor承载,添加到beanPostProcessors中,然后再调用registerBeanPostProcessors方法添加自定义的BeanPostProcessor到beanPostProcessors中,所以ApplicationContextAware接口能在自定义的BeanPostProcessor前面触发)

2.4.7、遍历BeanPostProcessor,调用BeanPostProcessor#postProcessBeforeInitialization方法,传递bean对象和beanName

2.4.8、如果bean实现了InitializingBean接口,则调用InitializingBean#afterPropertiesSet方法

2.4.9、如果bean定义了init-method或@PostConstruct注解,则调用自定义初始化方法

2.5.0、遍历BeanPostProcessor,调用BeanPostProcessor#postProcessAfterInitialization方法,传递bean对象和beanName

2.5.1、bean初始化完成,存放bean对象到singletonObjects缓存中

2.5.2、bean销毁时,如果bean实现了DisposableBean接口,则调用DisposableBean#destroy方法

2.5.3、bean销毁时,如果bean定义了destroy-method或@PreDestroy注解,则调用自定义销毁方法

3、解决循环依赖问题

3.1、由第2点spring bean生命周期流程可以看出,spring bean循环依赖发生在创建bean的属性注入阶段,在创建A时,需要注入B,这时B还没创建,所以走创建B流程,在创建B时,需要注入C,这时C还没创建,所以走创建C流程,在创建C时,需要注入A,这时A还在初始化中,所以形成了一个循环依赖。

3.2、因为在创建A时,提前将A曝光到singletonFactories中,所以在创建C时,可以从singletonFactories中获取到A的引用,这时C可以完成完整的bean生命周期流程,从而B成功注入了C,这时B可以完成完整的bean生命周期流程,从而A成功注入了B,这时A也可以完成完整的bean生命周期流程,从而解决了bean的循环依赖问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值