注入Bean的大致流程:
AbstractApplicationContext#refresh()方法最后一步 finishBeanFactoryInitialization 会对扫描到Bean进行实例化注入。该方法主要是遍历扫描的Bean然后调用 AbstractBeanFactory#getBean()方法进行实例化Bean并注入。
实例化过程如下:
以AbstracBeanFactory#getBean()为入口开始注入某个Bean
尝试从缓存中获取Bean,若没有获取到则进行实例化并缓存
若缓存中没有取到Bean则开始实例化Bean,首先会调用 DefaultSinigletonBeanRegostry#getSingleton(beanName, singletonFactory)方法.该方法步骤大致为:
标识当前正在创建的Bean -----》 实例化Bean ------》 取消该Bean正在创建的标识 -----》 将Bean注入到IOC中
getSingleton方法首先会为当前的Bean加一个正在创建中的标识,主要体现在getSingleton方法中调用的beforeSingletonCreation(beanName)方法。主要将该beanName添加到 DefaultSingletonBeanRegistry#singletonsCurrentlyInCreation中表面该Bean正在被创建,避免并发创建
实例化Bean,这个过程比较复杂,所以只列举与本例有关的。实例化Bean时会先确定Bean的构造器,若构造器有参数则处理参数(若IOC中有参数类型的Bean直接取出来即可,否则要实例化该参数类型的Bean并注入(从第三步往后重复执行),然后赋值)后再实例化Bean。
实例化Bean完成之后,则吧singletonsCurrentlyInCreation中该bean 的标识去掉。
将实例化好的Bean注入IOC中
//构造器循环依赖案例
@Service
public class AService {
private BService bservice;
public AService (BService bService) {
this.bService = bService;
}
}
@Service
public class BService {
private AService aService;
public BService (AService aService) {
this.aService = aService;
}
}
如上所示是一个典型的构造器循环依赖,启动后直接报循环依赖错误.为什么setter方式的循环依赖不报错而构造器依赖就报错呢?接下来我们就仔细分析一下为什么构造器依赖会报错:
Spring会遍历AService和BService依次实例并注入,所以首先会实例化AService。当实例化AService时将该bean加入 singletonsCurrentlyInCreation中标识该Bean正在被创建。然后会确定AService的构造器将其实例化出来,但是构造器中有一个BService bService参数,并且判断IOC中没有此Bean然后就会调用流程中的第三步开始实例化BService(注意:此时AService还被标识正在创建)。创建BService时又会将BService放入singletonsCurrentlyInCreation中标识BService正在被创建。然后会确定BService的构造器并实例化该Bean,但是构造器中有一个AService aService参数,然后会到IOC中找aService这个bean,很显然是找不到的,然后就会去创建AService(注意:此时BService也被标识正在创建),首先会调用beforeSingletonCreation将AService标识为正在创建中(此时AService、BService都在 singletonsCurrentlyInCreation中),但是由于singletonsCurrentlyInCreation已经包含AService了,所以此时会抛出异常
protected void beforeSingletonCreation(String beanName) {//beanName : A Service
//因为此时singletonsCurrentlyInCreation中包含 AService和BService,现在又要添加singletonsCurrentlyInCreation中添加AService将会返回false,所以会抛出异常
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
综上所述,Spring无法解决构造器循环依赖是因为相互依赖的Bean一个没有完成实例化,也就是一个构造器都没有执行成功,所以陷入了无限循环。若不是beforeSingletonCreation方法抛了异常则会陷入无限循环的状态
Bean的实例化过程中会调用 AbstractAutowireCapableBeanFactory#doCreateBean方法:然后调用无参构造器实例化出该Bean。若Bean满足单例Bean并且开启了允许循环依赖并且是正在创建中的Bean则调用 addSingletonFactory()方法将Bean放入第三级缓存中 singletonFactories中。在本例中就是将实例化好的AService放入三级缓存中,然后开始解析AService中的属性 bService.首先查看IOC中是否存在bService,发现不存在则开始创建BService,又因为BService也是无参构造器所以可以实例化出BService并将其放入三级缓存中。然后处理BService的属性 aService.最终会在三级缓存中获取aService,然后完成BService的注入。BService完成注入后AService也就完成了注入。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//调用无参构造器实例化出Bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
.....
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
//当Bean为单例并且开启了循环依赖并且是正在创建中的Bean,才会将实例化好的Bean添加到三级缓存中。重点是单例Bean哦
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//调用DefaultSingletonBeanRegidtry#addSingletonFactory()方法将该Bean放入 singletonFactories第三级缓存中
addSingletonFactory(beanName, new ObjectFactory
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
Spring三级缓存可以解决setter方式注入的循环依赖但是无法解决构造器循环依赖,原理就是使用Bean的无参构造器进行Bean的实例化,然后将Bean放入三级缓存中,进而解决循环依赖。
解决setter循环依赖需要满足: Bean是单例的、Spring开启了循环依赖、该Bean为当前正在创建的Bean(即singletonCurrentlyInCreation中必须包含该Bean)
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));