前言:本文主要从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的循环依赖问题。