在SingleTonBean提到AbstractBeanFactory#getBean(java.lang.String) 会先调用一次getSingleton。
Object sharedInstance = getSingleton(beanName)这行代码,获取一个singleton,这里的这个sharedInstance ,故名思意是分享的意思。想象这样一个场景:
A 依赖 B
B 依赖 A
那么创建A的时候,为A注入属性时需要注入B,从而触发B的doGetBean,那么B回头也会会触发A的doGetBean,因为A已经在创建中,所以B获取A的时候,就在这里直接getSingleton() 获取了A的早期引用。
再看下getSingleton(beanName)
public Object getSingleton(String beanName) {
// 默认允许获取早期引用allowEarlyReference == true
return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 先从singletonObjects获取,如果在singletonObjects中获取到了, 那么一定时该引用已经创建成功了
// B获取A的时候, A还在创建中,singletonObjects没有注册A对象,所以获取不到
Object singletonObject = this.singletonObjects.get(beanName);
// 接着判断 如果A正在创建中, 那么尝试获取创建中的A对象
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 从早期 earlySingletonObjects 中获取A对象, 第一次出现循环依赖的时候时获取不到的(为什么获取不到? 继续看下面),这里也是null,
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 如果允许早期引用, 才会进入该方法体, 也就是说如果allowEarlyReference == true才会进入, 当然B获取A的时候, allowEarlyReference==true
// 首先从singletonFactories获取A的 singletonFactory, B获取A的时候是可以从这里获取到的
// 因为在A创建的时候, doCreateBean中 调用 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))传入了一个singletonFactory的lambda表达式
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 调用singletonFactory.getObject()获取singletonObject, 其实就是调用getEarlyBeanReference
singletonObject = singletonFactory.getObject();
// 拿到singletonObject 后 将其加入到 earlySingletonObjects中
// 很关键: 1、这里解释第14行注释,这里我们知道为什么第一次在earlySingletonObjects中获取不到 singletonObject了。
// 2、只有第一次出现循环引用的时候才会进入到这里, 后面如果有C还依赖A,那么就会从 earlySingletonObjects中 直接获取了
// 3、如果传入 allowEarlyReference == false, 并且还获取到 A 对象,那么一定出现过循环依赖, 因为只有出现循环依赖才会走到这个方法体
this.earlySingletonObjects.put(beanName, singletonObject);
// 将 调用singletonFactory 从 singletonFactories 移除。
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
上面注释我们知道 如下定理:
1、getSingleton 先从 singletonObjects中取对象
2、如果没取到并且如果对象正在创建中,则从earlySingletonObjects 中取
3、如果还是没取到并且允许早期引用,则从singletonFactories 中取。并将其放置到earlySingletonObjects 。然后返回。
有一下推论:
1、如果从 singletonObjects取到对象,那么该对象一定创建完毕。
2、第一次循环依赖无法在earlySingletonObjects 中获取到依赖对象。
3、第二次之后如果出现循环依赖,earlySingletonObjects 一定从中获取,也就是说如果A 和 B循环依赖,A又和C循环依赖,那么C获取A的时候一定是 从 earlySingletonObjects 获取,B一定从 singletonFactories 中获取。
4、如果 A正在创建中传入 allowEarlyReference == false 还可以获取到A的引用那么,一定出现了循环依赖。
根据如上定理和推论,结合想象A 和 B 循环依赖 ,我们看AbstractAutowireCapableBeanFactory#doCreateBean 的代码:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// 先从缓存看看,是否实例化
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 实例化
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 这里又会进入一次post-processors
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// 解决循环依赖进行一次提前暴露
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");
}
// 缓存中添加一个singletonFactory, 用于被依赖者调用时获取其早期暴露, 这里主要解决在AOP情况下的循环依赖的问题,后面会有案例详解
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// exposedObject 是用于暴露给用户的引用,如果用到AOP, 那么它必须指向代理对象
Object exposedObject = bean;
try {
// 完成属性注入
populateBean(beanName, mbd, instanceWrapper);
// bean的初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
// 在不允许早期早期暴露的条件获取其早期暴露, 获得其早期引用, 听不懂, 没事后面又专门介绍
Object earlySingletonReference = getSingleton(beanName, false);
// 如果不允许早期暴露,却又获得了其earlySingletonReference, 那么必然出现了循环依赖 听不懂, 没事后面又专门介绍
if (earlySingletonReference != null) {
// 如果出现了循环依赖, 并且exposedObject == bean 这里两个引用在AOP中都是被代理对象。
// 如果出现了exposedObject != bean。说明出现被代理对象中注入了代理对象,这种不被允许,则抛出异常。听不懂, 没事后面又专门介绍
if (exposedObject == bean) {
// 将 earlySingletonReference 付给 exposedObject , 因为这里的很可能指向了代理对象, 需要将代理对象暴露返回
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
// 如果有必要的化, 将得到的bean进行注册
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
比如现在正在创建A对象, A 经历了 三个阶段
1、实例化,
2、属性赋值,
3 、初始化(初始化中可能会又AOP行为)
关于循环依赖的代码解释:
1、在代码instanceWrapper = this.factoryBeanInstanceCache.remove(beanName) 调用后,获取到A的引用。
2、接着调用 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)) 将可以获取到A的早期引用的SingletonFactory 加入到 singletonFactories 中
3、调用populateBean(beanName, mbd, instanceWrapper) 对A进行赋值,从而引发B的创建。B创建之后走到这行代码会调用A的doGetBean 从而调用getSingleton(beanName == A) 的方法。从而B能获取到A的引用。
4、B创建完成之后,继续A的后面流程,从而循环依赖解决。
为什么要搞singletonFactories ?还要调用其 getEarlyBeanReference ? B 获取A的时候会调用这个方法。
我们看下getEarlyBeanReference的代码。
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
如果我们不看 if 中的条件判断, 其实B 获取 A的时候调用 singletonFactory,其实就是直接获取A的早期引用。关键就是这个if语句。这个if语句,其实是解决了,在AOP情景下的循环依赖。
我们再看,后面一段代码:
exposedObject = initializeBean(beanName, exposedObject, mbd);进行初始化时可能会调用wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);进行AOP,那么 exposedObject其实是指向了被代理对象。
如果我们不经过处理而是在B获取A时候直接返回 A的原始对象,那么B中注入的A便不是代理对象,只有A注入了B的代理对象。那么B中调用A方法时,AOP就失效了。Spring不允许这样的AOP行为,因此看到下面有个判断。
注意 Object earlySingletonReference = getSingleton(beanName, false); 中allowEarlyReference == false,根据推论4:如果 A正在创建中传入 allowEarlyReference == false 还可以获取到A的引用那么,一定出现了循环依赖。
那么如果出现循环依赖,就需要将经历过initializeBean 的 exposedObject 与原来的 bean(这个是经历初始化之前记录的引用)。
如果二者不同,则会抛一个BeanCurrentlyInCreationException。
因此使用者在进行AOP时则要遵守一个规则:
1、Spring允许在applyBeanPostProcessorsAfterInitialization中进行AOP。
2、也允许在getEarlyBeanReference中进行AOP。
3、不出现循环依赖时,则只在 applyBeanPostProcessorsAfterInitialization实现AOP就行了
4、但是如果出现循环依赖,则必须在getEarlyBeanReference进行AOP, 这样B获取A的时候,获取的就是A的代理对象。并且,不可以在applyBeanPostProcessorsAfterInitialization。这样保证 在回到A的时候 exposedObject == bean。实现者必须在两个方法中加判断,只允许其中一个做了AOP。Spring的@Aspect 注解实现的AOP,它就遵顼这个原则。可以查看我的一个demo,演示了如何解决AOP的循环依赖问题。