老生谈spring(二十):循环依赖(二)
1、首先看doGetBean的方法,进来对name进行一个解析,如果是别名转换成beanName。然后二话不说,调用getSingleton方法去拿这个实例。
2、getSingleton方法就是从三级缓存中去获取这个bean实例,首先从单例池singletonObjects中获取,获取不到则判断这个bean是否正在被创建,判断的依据就是singletonsCurrentlyInCreation容器里是否有这个beanName(创建bean前会把beanName放到singletonsCurrentlyInCreation)。如果是那么从earlySingletonObjects中获取这个bean,如果获取不到再从singletonFactories获取这个bean的工厂,如果能拿到这个工厂,那么就用这个工厂去创建bean,并且把创建的bean缓存到earlySingletonObjects中。
@Override
@Nullable
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
/**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
@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;
}
3、由于一开始这个bean是没有被创建的,它也没有bean工厂,所有getSingleton返回的是个null。由于返回的是null,所有第一个if就不进,进入的是else的代码。else的代码有个很明显的地方,就是判断这个bean的作用域是否是单例的。如果是那么调用重载的getSingleton方法,这个方法有两个参数,第一个是beanNmae,第二个传的是一个lambda表达式。可能有些人不是很熟悉lambda表达式,这里你简单认为传的就是一个匿名的bean工厂对象并且为它的getObject方法提供了实现,这个实现调用了createBean方法。
4、如果lambda表达式还么看懂那就先不管,我们来看重载的getSingleton方法。在getSingleton的方法里首先用synchronized保证现场安全,然后在beforeSingletonCreation这个方法把beanName存放到singletonsCurrentlyInCreation,表示这个bean正在被创建(呼应第2点)。然后使用singletonFactory的getObject方法去创建这个bean,而第3点中说过getObject的实现就是调用createBean方法。
5、createBean方法的主要代码其实就是调了doCreateBean,这就是spring的代码风格,do开头的方法才是真正干活的。
6、doCreateBean我们也只看与循环依赖有关的代码,这里有个判断earlySingletonExposure是否为true,如果为true则提前暴露一个bean工厂。而earlySingletonExposure为true的满足条件就是这个bean是否是单例的,并且这个bean是否正在创建,并且allowCircularReferences是否为true。(现在你知道上一节中为什么把allowCircularReferences设置为false就不支持循环依赖了吧)
7、做完这件事后,就来到populateBean方法进行属性填充(依赖注入)。这个依赖注入的是一个bean的话也是调用到getBean方法,后面会详细讲解populateBean这个方法,这里就不作详细讲解了。假设创建A的bean执行到这里,就会去getBean创建B,而B又依赖注入了A,那么就会再次触发到A的getBean操作,而之所以不会陷入死循环就是因为在创建A对象提前暴露了A的工厂(三级缓存中的singletonFactories),所以这次getBean操作是能拿到一个半成品的A的bean,这时就能把这个半成品的bean注入到B中,在完成了B的生命周期后就能完成A中的B对象的注入。
8、由于这个过程非常绕,所以这里再描述一下这个步骤:
A 的getBean->提前暴露A的工厂->populateBean注入B->B的getBean->提前暴露B的工厂->populateBean注入A->A 的getBean->三级缓存中有A的工厂,用A的工厂创建这个bean->返回B的populateBean注入A->完成B的生命周期->返回A的populateBean注入B->完成A的生命周期
9、结语:思考两个问题:1、为什么三级缓存要缓存一个Bean的工厂?2、为什么要用三级缓存?二级不可以吗?