这是第四个后置处理器的源码学习笔记
第四个后置处理器,主要是为了完成对循环依赖的支持
org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference
这是第四个后置处理器的方法名,在spring源码中,实现了该方法的,只有两个beanPostProcessor,分别是:
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getEarlyBeanReference
org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter#getEarlyBeanReference
其中InstantiationAwareBeanPostProcessorAdapter的getEarlyBeanReference()方法没有做什么处理,只是原封不动的把bean返回了出去
主要的功能,在AbstractAutoProxyCreator#getEarlyBeanReference这里
我们首先来看这个方法的代码
@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
this.earlyProxyReferences.add(cacheKey);
}
return wrapIfNecessary(bean, beanName, cacheKey);
}
代码只有这么几行,但是会发现,这几行代码,其实就是第八个后置处理器(生成动态代理对象)所做的事情;
接下来我们来看第四个后置处理器的外层的逻辑
/**
* 第四个后置处理器执行的前提条件是:
* 1.当前bean是单实例的
* 2.当前beanFactory允许循环依赖:allowCircularReferences这个参数没找到在哪个扩展点中可以改为false,初始化默认是true,所以我们姑且认为大部分情况下这个参数都是true
* 3.当前bean正在创建中,这里是判断是否在一个集合中
* singletonsCurrentlyInCreation会在开始初始化之前,判断当前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");
}
/**
* mpy 第四次调用后置处理器 获取一个提前暴露的对象 objectFactory 用来解决循环依赖
* 这里还有一个关键的作用,可以追进去看一下,这里可能会完成动态代理对象的生成(AOP)
* 正常情况下,AOP的动态代理是在调用org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String)的时候,才会生成(也即:第八个后置处理器)
* 但是,如果是循环依赖的话,会在 org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference(java.lang.Object, java.lang.String) 中完成
*
* 所以:对于循环依赖,这里提前暴露的对象,虽然没有完成后面的初始化方法的解析(invokeInitMethod),但是完成了动态代理对象的生成
*
* 这里getEarlyBeanReference();不会立即执行,而是在从二级缓存中获取对象的时候,会调用该方法,在该方法中完成动态代理
*
*/
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
/**
* 这里是第四个后置处理器的逻辑
* 在这里,会把第四个后置处理器作为一个ObjectFactory存入到一个map集合中
* 所以这个后置处理器,并不会立即执行,而是在从map取出来的时候,会被执行,那什么时候会被取出来呢?
* 在循环依赖中
* Add the given singleton factory for building the specified singleton
* if necessary.
* <p>To be called for eager registration of singletons, e.g. to be able to
* resolve circular references.
* @param beanName the name of the bean
* @param singletonFactory the factory for the singleton object
*/
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
/**
* 这里会加一层判断,如果单实例池中已经有bean对象了,就无须再插入到singletonFactories中,此时也就不存在
* 循环依赖的问题了
*/
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
这里的逻辑也就是这几行代码,主要是为了属性循环依赖,那至于第四个后置处理器在什么时候会被调用呢?
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String)
/**
*
* singletonObjects是spring单实例池
* 我们暂时称
* earlySingletonObjects为三级缓存 该map是在后面进行判断,是否允许循环依赖,如果允许,就把bean存到这个map中
* singletonFactories为二级缓存 在判断是单实例bean的时候,将包含bean的beanFactory存到该map中,这个map中存储的是一个生成代理对象的factory
* singletonObjects为一级缓存,存储的是实例化之后的bean
*
* 在这里,三级缓存的map保存的是从二级缓存中取到的一个对象,取到之后,从二级缓存中将bean删除
* 这样做是为了防止重复创建,
*
* 在获取到依赖的对象之后,会进行一次类型校验 org.springframework.beans.factory.support.AbstractBeanFactory#isTypeMatch(java.lang.String, org.springframework.core.ResolvableType)
*
* 循环依赖的处理:
* 如果A注入了B,B也注入了A;在第一次实例化A的时候,会注入A,注入A的时候,会反过来去实例化B
*/
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//mpy 这里只需要从二级缓存中拿一次就行,如果没有二级缓存,每次进来都需要从二级缓存get一次,影响效率
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
/**
* 这里getObject会调用getEarlyBeanReference(beanName, mbd, bean)方法,完成动态代理对象的生成
* 这里为什么要调用这个方法?
* 我的理解是这样的:在属性注入之后,还有两个后置处理器需要调用:
* 1.applyBeanPostProcessorsBeforeInitialization invokeInitMethod方法,也即:调用bean的初始化方法的后置处理器
* 2.applyBeanPostProcessorsAfterInitialization 这里完成的是:代理对象的生成(比如:AOP动态代理对象生成,事务方法代理对象生成)
*
* 既然有了循环依赖,总要有一个bean是要先注入的,在注入
*/
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
就是这里,所以我们说第四个后置处理器是为了完成对循环依赖的处理;
在A依赖B,B依赖A的情况下,先对A对象完成动态代理对象的生成,然后在注入之后,再执行属性注入、初始化方法回调等方法;其实这里有一个点没有搞懂,为什么在循环依赖中,一定要在注入bean的时候,先完成动态代理对象的生成?