Bean生命周期各阶段的解析参考:
整体概括
什么是循环依赖
两个bean,a与b,a中注入了b,b中注入了a,a与b相互依赖。这里就是发生了循环依赖,spring使用三级缓存处理循环依赖。
注意:必须是单例作用域的Bean才可以用三级缓存处理
什么是三级缓存
存放Bean的集合 (来自DefaultSingletonBeanRegistry中),用于解决循环依赖:
-
一级缓存,存放完全初始化好的Bean的集合,从这个集合中取出来的Bean可以立即返回
javaprivate final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); -
二级缓存,存放已实例化,但没有初始化与属性注入的Bean的集合,二级缓存中的bean是从三级缓存中拿出来的
javaprivate final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16); -
三级缓存,存放单实例Bean工厂(
ObjectFactory)的集合,ObjectFactory里面是已实例化但没有依赖注入与初始化的beanjavaprivate final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
三级缓存解决循环依赖过程:
两个bean,A与B,A中需要注入B,B中需要注入A。
-
假设
A先开始创建。A实例化阶段完成,此时A还没有进行属性注入,这时的早期A会存入三级缓存 (三级缓存会判断A是否要代理,需要就存A的代理类,不需要就存原始类)。然后进行属性注入,即注入B,此时B还不存在,这时会暂停A的注入,转而去创建B。 -
B开始创建,实例化完成后进入属性注入阶段,开始向B中注入A,此时会从三级缓存 取A(如果A有代理,拿到的就是A的代理类,没有代理拿到的就是原始对象)。因为上一步A已经存入到三级缓存 了,所以此处可以拿到一个早期的A,然后将A放入二级缓存,并将其从三级缓存 中删除。取到A后注入到B中,完成B的初始化。最后将完整的B放入一级缓存。 -
B成功完成初始化后,A继续生命周期流程,去注入B,此时B已经初始化好了,可以直接取到B了,然后将B注入A中,再把A存入一级缓存 。这时A与B都成功完成了生命周期流程,如果后面还有依赖他们的其他Bean,便可以直接从一级缓存获取了。
涉及的源码
在容器运行过程的实例化阶段与初始化依赖注入阶段中,都涉及到循环依赖的处理,下面简单介绍两个阶段涉及循环依赖处理的源码。发生循环依赖时,主要就是下面源码的嵌套调用,简单了解即可,可以忽略直接看过程分析。
实例化时
回顾源码的方法调用过程:主启动类run() ----> refreshContext() ----> finishBeanFactoryInitialization() ----> preInstantiateSingletons() 。
实例化开始在DefaultListableBeanFactory 的 preInstantiateSingletons 方法中,它会执行getBean方法进行Bean创建:
getBean方法会调用doGetBean方法(AbstractBeanFactory内),在此方法内有两步循环依赖 的处理,两步处理都是使用getSingleton方法:
第一步处理:创建bean前先去一级缓存取,取到了就直接返回,不再执行创建过程,以此避免重复创建,节约性能。因为当一个Bean完成了实例化、属性注入、初始化的步骤后,它最后会被存入一级缓存中(下面会介绍这个存入的步骤)。
第二步处理 :在第一步没能从一级缓存拿到bean时,这里会将当前bean标记为正在创建中的状态,并调用createBean方法创建当前bean,创建好后在把bean存入一级缓存中,后面再有依赖当前bean的其他bean时,就可以直接从一级缓存中获取进行注入了
java
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
String beanName = transformedBeanName(name);
Object beanInstance;
// 第一步
// 尝试从一级缓存中获取Bean,如果获取到则直接返回,避免重复创建,节约性能。
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
// logger.............
// 处理从缓存中获取的bean实例,主要是判断该实例是普通的bean还是FactoryBean:
// 1.如果是FactoryBean,并且请求的bean名称没有`&`前缀,则返回FactoryBean创建的Bean对象;否则,返回FactoryBean本身
// 2.如果只是普通bean,则直接返回
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
//........
// 第二步
// 如果一级缓存中没有获取到bean,下面会进行创建。如果获取到这里就不执行了
// 此处的getSingleton方法涉及第二步循环依赖的处理,且方法参数与上面第一步的不同
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
} // catch ......
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
//.............
}
return adaptBeanInstance(name, beanInstance, requiredType);
}
初始化时
实例化时执行的
createBean方法会进入到AbstractAutowireCapableBeanFactory的doCreateBean方法,
doCreateBean方法通过createBeanInstance(beanName, mbd, args)创建出Bean实例后,就进入初始化阶段了。初始化时也分为两步:
第一步是获取当前bean的早期引用,并将此引用存入三级缓存
第二步 是在依赖注入时执行getBean 方法获取需要注入的bean
java
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// ...........
if (instanceWrapper == null) {
//这里是Bean实例化
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 下面是处初始化阶段:
// ...........
// 第一步循环依赖处理,获取早期bean的引用存入三级缓存
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 获取一个早期Bean的引用,并将其放入三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
// 第二步循环依赖处理,属性注入
populateBean(beanName, mbd, instanceWrapper);
// 这里是初始化,主要是执行`@PostConstruct`标注的初始化方法,不涉及循环依赖处理
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {}
//..............
return exposedObject;
}
下面分别介绍这两步处理源码
早期Bean的引用存入三级缓存
初始化阶段循环依赖的第一步处理:早期Bean的引用存入三级缓存
createBeanInstance方法实例化出Bean实例后,调用 SmartInstantiationAwareBeanPostProcessor 后置处理器的 getEarlyBeanReference 方法获取一个Bean实例的早期引用,然后将该引用存入三级缓存中:
getEarlyBeanReference方法会根据Bean实例 获取到Bean的引用addSingletonFactory方法会将Bean的引用 存入三级缓存singletonFactories中
java
/**
* 当前的Bean定义(mbd)必须同时满足如下3个条件:
* 1.是否是单例----isSingleton(), 因为三级缓存无法解决非单例bean的循环依赖
* 2.是否允许循环依赖----allowCircularReferences
* 3.该单例Bean当前是否正在创建中----isSingletonCurrentlyInCreation(beanName)
*
* 这里条件成立,因为实例化时第二步的getSingleton方法会把Bean标记为正在创建中的状态,且spring默认允许循环依赖
*
* */
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// getEarlyBeanReference获取早期Bean的引用,调用的是SmartInstantiationAwareBeanPostProcessor后置处理器的实现
// addSingletonFactory将早期Bean的引用存入三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
先进入getEarlyBeanReference方法,此方法会去调用SmartInstantiationAwareBeanPostProcessor后置处理器的getEarlyBeanReference实现,取到早期Bean的引用(早期Bean即实例化完成,但是还没有进行属性注入与初始化的bean):
java
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
// 置换引用,exposedObject是bean的一个副本、引用
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
// 遍历后置处理器
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
// 调用处理器的 获取早期引用方法
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
// 返回引用
return exposedObject;
}
进入SmartInstantiationAwareBeanPostProcessor后置处理器的getEarlyBeanReference方法:
java
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {
// 默认情况下,直接返回传入的原始bean实例,不做任何处理
default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
return bean;
}
}
再进入addSingletonFactory内,把bean引用存入三级缓存:
java
// bean引用封装为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)) {
// singletonFactories就是三级缓存,这里把Bean存入三级缓存
this.singletonFactories.put(beanName, singletonFactory);
// 从二级缓存中移除此Bean
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
依赖注入
初始化阶段循环依赖的第二步处理:依赖注入
populateBean方法是 Spring 容器中处理属性赋值与依赖注入的方法,负责将依赖注入的值设置到 bean 实例中。
进入该方法内,下面展示其处理依赖注入的关键部分,调用InstantiationAwareBeanPostProcessor处理器的postProcessProperties:
java
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// .................
// 如果存在`InstantiationAwareBeanPostProcessor`则遍历这些后处理器,调用`postProcessProperties`方法,该方法用于执行依赖注入
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
// 遍历`InstantiationAwareBeanPostProcessor`处理器实现
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
// 调用`postProcessProperties`方法,该方法允许后置处理器修改属性值,这里也是处理依赖注入的地方
// `@Autowired`和`@Inject`等注解的处理就是在这个回调中实现的
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
// ............
// 更新`pvs`为后置处理器修改后的值
pvs = pvsToUse;
}
}
// ...............
}
真正执行注入操作的是InstantiationAwareBeanPostProcessor处理器的实现类AutowiredAnnotationBeanPostProcessor,在它的postProcessProperties方法实现中:
- 会收集需要注入的依赖信息,将依赖信息封装为元数据
- 调用元数据对象的
inject方法,该方法会获取当前Bean中每个需要被注入的属性Field和方法Method,依次对其进行注入操作
java
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 第一步,收集需要注入的元数据信息
// 依赖注入执行前,`MergedBeanDefinitionPostProcessor`处理器已经收集过了,所以这里可以直接从缓存中获取
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// 第二步,执行注入
// 将属性注入到目标Bean当中,内部循环遍历每一个需要注入的属性和方法进行注入
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
InjectionMetadata有两个实现类AutowiredFieldElement与AutowiredMethodElement,分别代表属性注入 与方法注入 ,这里以属性注入为例,进入AutowiredFieldElement的inject方法,它又有两步操作:
- 调用
resolveFieldValue方法来解析并获取依赖 - 如果获取到依赖,方法最后会通过反射将依赖 注入到当前Bean属性中
java
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
// 获取目标属性
Field field = (Field) this.member;
Object value;
// 根据缓存标志决定如何获取注入值
if (this.cached) {
try {
// 如果cached为true,则尝试从缓存中获取
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
catch (NoSuchBeanDefinitionException ex) {
// 如果缓存中找不到,则进行解析获取
value = resolveFieldValue(field, bean, beanName);
}
}
else {
// 如果cached为false,则直接调用resolveFieldValue来解析获取属性的值
value = resolveFieldValue(field, bean, beanName);
}
// 执行反射注入
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
解析并获取依赖的过程在resolveFieldValue方法内,进入后看到beanFactory.resolveDependency:
java
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
// ..............
Object value;
try {
// 解析依赖,获取需要注入的值
// 这个方法是Spring容器解析依赖的核心方法,它会根据依赖描述符(字段类型、注解等)从容器中找到需要的Bean
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
// ..............
// 返回解析得到的值
return value;
}
再进入beanFactory.resolveDependency,它会根据不同的依赖类型做不同的处理,最关键步骤是其内部调用的doResolveDependency方法:
java
// descriptor:依赖描述符,封装了依赖的字段、方法参数等信息
// requestingBeanName:当前正在创建的Bean名称
// autowiredBeanNames:被注入的Bean名称
// typeConverter:类型转换器,用于类型转换
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// ................
if (result == null) {
// 这里是最关键的处理,进行实际的依赖解析
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
进入
doResolveDependency,它会真正去查找需注入的bean,此方法主要涉及:处理@Value注解、集合类型注入、获取依赖的bean、以及从多个满足注入条件的bean中选出唯一一个:
此方法内最重要的代码是descriptor.resolveCandidate,它会调用 getBean 方法获取需要注入的bean 。假设两个bean相互依赖,先创建的bean就是通过这里调用的getBean方法,来获取另一个bean为自己完成注入的。这时,就会重新循环到上面实例化步骤的doGetBean方法了。
java
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// ................
// 如果候选对象是Class类型,则通过descriptor.resolveCandidate解析实际bean实例
if (instanceCandidate instanceof Class) {
// 此处的resolveCandidate会调用getBean方法,去获取需要注入的bean,此处也涉及了循环依赖
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
// .................
Object result = instanceCandidate;
// .........
// 返回要注入的bean实例
return result;
}
循环依赖过程分析
设计一个场景: 有两个单例bean,A与B,A中注入了B,B中注入了A。假设A先进行创建。
下面结合源码来分析循环依赖的处理过程:
第一步处理
容器启动,先进行bean-A的实例化,代码调用过程:主启动类run() ----> refreshContext() ----> finishBeanFactoryInitialization() ----> preInstantiateSingletons()
此时代码执行到
DefaultListableBeanFactory的preInstantiateSingletons方法中,它会执行getBean,再进一步调用doGetBean方法(AbstractBeanFactory内)进行A的创建:
doGetBean 方法逻辑 :先尝试从缓存中获取A,取不到就创建。注意这里有两个getSingleton方法,它很重要。
java
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
String beanName = transformedBeanName(name);
Object beanInstance;
// 第一步涉及循环依赖的处理
// 尝试从多级缓存中获取A,如果获取到则直接返回,取不到就创建。由于A是第一次创建,这里取不到。
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
// ...........
}
// 如果缓存中没有获取到A,下面调用createBean方法进行A的创建
else {
//........
if (mbd.isSingleton()) {
// 第二步循环依赖的处理,创建A
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
} // catch ......
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
//.............
}
return adaptBeanInstance(name, beanInstance, requiredType);
}
先看第一步执的
getSingleton方法,它从多级缓存 获取bean,具体代码在DefaultSingletonBeanRegistry中:
由于此时的A是第一次创建,容器中不存在A的实例,所以第一步的getSingleton方法一定返回空。
另外一点:如果是第一次创建A,代码走到这里时,还不会把A标记为正在创建中的bean,所以即便方法体内有从二三级缓存获取bean的逻辑,也不会执行。
java
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 尝试从一级缓存获取A
Object singletonObject = this.singletonObjects.get(beanName);
// 此时一级缓存中并没有A,且A也没有被标记为正在创建中,此条件不成立,下面也不会执行
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 尝试从二级缓存获取,如果找到直接返回,这里二级也没有
singletonObject = this.earlySingletonObjects.get(beanName);
// 如果前两级缓存都没有,且允许早期引用,进入同步块
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// 再次检查一级缓存,防止其他线程已创建
singletonObject = this.singletonObjects.get(beanName);
// 如果一级缓存没 再次检查二级缓存
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
// 如果二级缓存仍然没有,从三级缓存获取,
// 如果三级缓存也没有,则此方法结束,走后面的创建流程
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
// 如果三级缓存获取到了
if (singletonFactory != null) {
// 通过ObjectFactory获取bean对象
singletonObject = singletonFactory.getObject();
// 将对象放入二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
// 从三级缓存移除bean
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
下面看第二步的getSingleton
第二步处理
第一步的
getSingleton获取为空后,进入doGetBean中第二个getSingleton方法,代码同样在DefaultSingletonBeanRegistry内,但参数列表与上一个不同:
第二步的getSingleton方法还会再次尝试从一级缓存获取A,当然还是获取不到,这时会有两步处理:
- 将A的
beanName存入singletonsCurrentlyInCreation集合(一个用于存放正在创建中的单例bean的集合 ),也是就把A标记为正在创建中的bean (所以在第一次创建A时,前面第一步的getSingleton方法只会从一级缓存取)。 - 通过传入的
ObjectFactory参数,以lamdba 形式调用createBean方法创建A。
第二步的
getSingleton方法源码解析
java
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
// 检查A的beanName非空
Assert.notNull(beanName, "Bean name must not be null");
// 加锁确保线程安全(单实例bean的创建线程)
// singletonObjects是一级缓存,用于存放已经创建好的bean(已经实例化、初始化好的完整bean)
synchronized (this.singletonObjects) {
// 从一级缓存中获取A,如果存在则直接返回,这里取不到
Object singletonObject = this.singletonObjects.get(beanName);
// 此时一级缓存获取不到A,条件成立进入下面处理
if (singletonObject == null) {
// 如果一级缓存不存在A,检查A是否处于销毁状态,如果是则抛出异常。因为不允许在销毁过程中创建bean
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
// logger......
// 将A的bean名称添加到`正在创建的单例bean集合`中,该集合名为singletonsCurrentlyInCreation
// 就是这里把A标记为了正在创建中的Bean
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 进行A的创建,这里的singletonFactory是传入的lamdba表达式,
// 其实此处就是执行外面那个createBean方法来创建A
singletonObject = singletonFactory.getObject();
// 以此为界,本方法下面的代码先不用关注,先去看createBean创建A的流程...................................
// 如果创建成功,设置newSingleton标志为true,表示创建了新单实例bean-A
newSingleton = true;
}
catch (IllegalStateException ex) {
//...........
}
// 最后一定调用的
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 将A的bean名称从`正在创建的单例bean集合`中移除
afterSingletonCreation(beanName);
}
// 如果成功创建了新的单实例bean-A,则将A的实例添加到一级缓存,并清除二、三级缓存。
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
// 最后返回A
return singletonObject;
}
}
第三步处理
接上面getSingleton中执行createBean,此时创建A的createBean方法会执行到AbstractAutowireCapableBeanFactory的doCreateBean方法,在doCreateBean中通过createBeanInstance方法创建出A实例,然后开始A的属性注入与初始化阶段:
初始化阶段循环依赖的第一步处理:将A的引用存入三级缓存
- 调用
SmartInstantiationAwareBeanPostProcessor处理器的getEarlyBeanReference方法,获取早期A的引用,这里的早期意思就是A还没进行属性注入与初始化 - 调用
addSingletonFactory将A的早期引用存入三级缓存singletonFactories中
如下是doCreateBean中涉及处理的源码解析:
java
//................
if (instanceWrapper == null) {
// 此处返回A的早期实例
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//................省略部分源码,下面是循环依赖处理
/**
* 通过判断当前A的Bean定义(mbd):
* 1.是否是单例----isSingleton(),
* 2.是否允许循环依赖----allowCircularReferences,
* 3.该单例Bean当前是否正在创建中----isSingletonCurrentlyInCreation(beanName)
*
* 同时满足上面3个条件则进行早期单例bean的暴露:
* A是单例,Spring默认允许循环依赖,且在第二步处理时A已被标记为正在创建中,此处条件成立。
*
* */
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// getEarlyBeanReference获取早期A的引用,调用的是SmartInstantiationAwareBeanPostProcessor处理器的实现
// addSingletonFactory将早期A的引用存入三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
//................
spring默认允许循环依赖,A是单例,且前面第二步处理中,已经把A存入singletonsCurrentlyInCreation集合,也是就把A标记为正在创建中的bean,所以if条件成立:
先进入
getEarlyBeanReference方法,获取引用。这里调用的是
SmartInstantiationAwareBeanPostProcessor后置处理器的getEarlyBeanReference方法:
java
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
// 这里的bean就是A,exposedObject是A的一个副本,最后返回的也是这个副本
// A到这里刚刚完成实例化,还没有进行属性注入与初始化,所以说获取的是早期A的引用,exposedObject就是A的引用。
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
// 遍历后置处理器
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
// 调用处理器方法,获取早期引用方
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
// 返回早期引用
return exposedObject;
}
进入SmartInstantiationAwareBeanPostProcessor后置处理器的getEarlyBeanReference方法:
java
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {
// 默认情况下,直接返回传入的A实例,不做任何处理,如果有存在代理的情况,调用的就是另一个实现了,这里就默认返回A实例
default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
return bean;
}
}
然后进入
addSingletonFactory内,把A的引用存入三级缓存:
java
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
// singletonFactories就是三级缓存,这里把A存入三级缓存
this.singletonFactories.put(beanName, singletonFactory);
// 从二级缓存中移除A,这里其实二级缓存中也还没有A
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
第四步处理
上面存完A的引用到三级缓存后,进行A的依赖注入处理
在上面第三步获取到A的引用并存入三级缓存后,代码执行到如下源码的populateBean方法位置,进行属性注入:
java
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// ...........
// 获取一个早期A的引用,并将其放入三级缓存
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// logger...........
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
// 属性注入
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
}
//..............
return exposedObject;
}
进入
populateBean内部,它调用InstantiationAwareBeanPostProcessor处理器的postProcessProperties方法执行注入:
java
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// .................
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
// 遍历`InstantiationAwareBeanPostProcessor`处理器的所有实现,处理`@Autowired`和`@Inject`等注解的依赖注入
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
// ............
}
}
// ...............
}
实际执行依赖注入的实现类是
AutowiredAnnotationBeanPostProcessor处理器,进入此处理器的postProcessProperties方法,该方法做两个操作:
- 收集A中需要注入的依赖信息,将依赖信息封装为元数据,元数据内包含的就是需要注入的B
- 调用元数据对象的
inject方法,该方法会获取A中每个需要被注入的属性Field和方法Method,依次对其进行注入操作,这里会获取到B,然后将B注入到A中
java
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 第一步,收集需要注入的元数据信息
// 依赖注入执行前,`MergedBeanDefinitionPostProcessor`处理器已经收集过了,所以这里可以直接从缓存中获取
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// 第二步,执行注入:先找到B实例,在注入到A中
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
InjectionMetadata有两个实现类AutowiredFieldElement与AutowiredMethodElement,分别代表属性注入 与方法注入 ,这里假设B是A中的一个属性,所以会进入AutowiredFieldElement的inject方法,它又执行两步操作:
- 调用
resolveFieldValue方法来获取B - 如果能取到B,通过反射把B注入到A中
java
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
// 获取A中的B属性
Field field = (Field) this.member;
Object value;
// 根据缓存标志决定如何获取注入值
if (this.cached) {
try {
// 如果cached为true,则尝试从缓存中获取
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
catch (NoSuchBeanDefinitionException ex) {
// 如果缓存中找不到,则重新解析
value = resolveFieldValue(field, bean, beanName);
}
}
else {
// 如果cached为false,则直接调用resolveFieldValue来解析字段的值
value = resolveFieldValue(field, bean, beanName);
}
// 执行反射注入
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
直接进入resolveFieldValue方法:
通过
resolveFieldValue再进入doResolveDependency方法内调用过程:
resolveFieldValue--->resolveDependency--->doResolveDependency。
doResolveDependency 方法内的 descriptor.resolveCandidate 会调用 getBean 方法获取需要注入的B:
java
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// ................
if (instanceCandidate instanceof Class) {
// 此处的resolveCandidate会调用getBean方法,去获取B
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
// .................
Object result = instanceCandidate;
// .........
// 如果上面处理无误,返回要注入的B
return result;
}
执行到这,A的创建过程会暂停在依赖注入这一步,转而进行B的创建。
第五步处理
通过上面
descriptor.resolveCandidate调用的getBean方法,获取B的实例,用于给A进行注入。
此时,获取B的getBean方法会重新回到AbstractBeanFactory.doGetBean方法进行B的创建,这里相当于又回到了第一步处理,不过这次是创建B了:
java
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
String beanName = transformedBeanName(name);
Object beanInstance;
// 尝试从一级缓存中获取B,如果获取到则直接返回。
// 因为B还没有被创建,这里取不到,走下面的getSingleton
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
// ...........
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
// 如果一级缓存中没有获取到B,下面调用createBean进行B的创建
else {
//........
// 创建B
if (mbd.isSingleton()) {
// 这里的getSingleton依然获取不到B
// 但会把B存入正在创建的bean集合中,标记B为正在创建中的状态,然后执行createBean去创建B
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
} // catch ......
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
//.............
}
return adaptBeanInstance(name, beanInstance, requiredType);
}
同样,因为这时B也是第一次创建,doGetBean内的两个getSingleton都无法从缓存中获取到B。在把B标记为正在创建的状态后,走下面分支的createBean。
createBean方法内调用doCreateBean,继续执行B的创建。
第六步处理
接第五步,进入到
AbstractAutowireCapableBeanFactory的doCreateBean方法,在doCreateBean中通过createBeanInstance方法创建出B实例后,进入B的属性注入与初始化阶段:
这一步获取早期B的引用,将早期B的引用存入三级缓存
java
//................
if (instanceWrapper == null) {
// 此处返回B的早期实例
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//................
// B是单例,spring默认允许循环依赖,且B已标记为正在创建中。这里条件成立
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 获取早期B的引用,将早期B的引用存入三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
//................
第七步处理
向三级缓存存完B的早期引用后,进入
populateBean方法给B执行依赖注入
java
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// ...........
// 获取一个早期B的引用,并将其放入三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
Object exposedObject = bean;
try {
// 执行B的属性注入
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {}
//..............
return exposedObject;
}
这里依旧以属性注入为例,B中有一个A类型的属性需要被注入。
populateBean进一步调用AutowiredAnnotationBeanPostProcessor的postProcessProperties方法:
java
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 第一步,收集需要注入的元数据信息
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// 第二步,执行注入:去找A的实例,注入到B中
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
进入
AutowiredFieldElement的inject方法,它又执行两步操作:
- 调用
resolveFieldValue方法来获取A - 如果能取到A,通过反射把A注入到B中
java
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
// 获取B中的A属性
Field field = (Field) this.member;
Object value;
// 根据缓存标志决定如何获取注入值
if (this.cached) {
try {
// 如果cached为true,则尝试从缓存中获取
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
catch (NoSuchBeanDefinitionException ex) {
// 如果缓存中找不到,则重新解析
value = resolveFieldValue(field, bean, beanName);
}
}
else {
// 如果cached为false,则直接调用resolveFieldValue来解析字段的值
value = resolveFieldValue(field, bean, beanName);
}
// 执行反射注入
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
这里直接进入
doResolveDependency方法内(调用过程为resolveFieldValue--->resolveDependency--->doResolveDependency)通过
resolveCandidate调用getBean方法获取需要注入的A:
java
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// ................
if (instanceCandidate instanceof Class) {
// 此处的resolveCandidate会调用getBean方法,去获取A
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
// .................
Object result = instanceCandidate;
// .........
// 如果上面处理无误,返回要注入的A
return result;
}
第八步处理
通过上面
descriptor.resolveCandidate调用的getBean方法,去获取A的实例,用于给B进行注入。
此时,获取B的getBean方法会重新回到doGetBean方法(AbstractBeanFactory内)进行A的创建,这里相当于又回到了第一步处理,进行A的二次获取:
java
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
String beanName = transformedBeanName(name);
Object beanInstance;
// 尝试从多级缓存中获取A,这里会从三级缓存中拿到A,因为之前的第三步处理已经把A存进去了
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
// ...........
// 此处会判断A是工厂bean还是普通bean,不同类型做不同处理,最后还是返回A的实例
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
//............
return adaptBeanInstance(name, beanInstance, requiredType);
}
最关键的部分来了,A在前面的创建过程中:
- 第二步处理时,A被标记为正在创建中的bean
- 第三步处理时,已经通过
SmartInstantiationAwareBeanPostProcessor处理器的getEarlyBeanReference方法,获取到早期A的引用存入了三级缓存
所以此处可以直接从三级缓存 获取到A(注意这里取到A后会把它从三级缓存 删除,并存到二级缓存 中),来给B进行注入,不需要在执行createBean方法进行实例化、初始化那一套了:
java
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 尝试从一级缓存获取完全初始化好的A,如果找到直接返回,这里取不到
Object singletonObject = this.singletonObjects.get(beanName);
// 如果一级缓存没有,且该bean正在创建中,可能涉及循环依赖
// 这里的条件判断成立,因为一级缓存没取到,前面A的创建过程中它已经被标记为正在创建中了
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 尝试从二级缓存获取,此时二级缓存没有A
singletonObject = this.earlySingletonObjects.get(beanName);
// 如果前两级缓存都没有,且允许早期引用,进入同步块
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// 再次检查一级缓存,防止其他线程已创建
singletonObject = this.singletonObjects.get(beanName);
// 如果一级缓存没 再次检查二级缓存
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
// 如果二级缓存仍然没有,从三级缓存获取,这里可以取到A
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
// 如果三级缓存获取到了A
if (singletonFactory != null) {
// 通过ObjectFactory获取A的对象实例
singletonObject = singletonFactory.getObject();
// 将A实例放入二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
// 从三级缓存移除A
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
// 返回A
return singletonObject;
}
第九步处理
获取到A后,回到第七步处理后面的doResolveDependency方法内,再向上返回到AutowiredFieldElement的inject方法,在inject方法完成注入,即把A注入到B中。
然后执行剩余的初始化initializeBean方法(此方法不涉及循环依赖处理了),最后返回已完成整个创建流程的完整B:
java
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// ...........
// 获取一个早期B的引用,并将其放入三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
Object exposedObject = bean;
try {
// 执行B的属性注入
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {}
//..............
// 返回B
return exposedObject;
}
第十步处理
B创建完成后,继续执行A的注入流程。
这时第九步处理中的doCreateBean方法,会将创建完成的B返回下面的createBean方法中,这里相当于回到了第五步处理中:
java
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
//........
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
} // catch ......
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
//.............
}
return adaptBeanInstance(name, beanInstance, requiredType);
}
此时
doCreateBean方法取到了B的实例,然后在getSingleton方法中将B实例存入到了一级缓存:
java
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
// ........
try {
// 这里执行的就是createBean,singletonObject就是创建完成的B
singletonObject = singletonFactory.getObject();
// 如果创建成功,设置newSingleton标志为true,表示创建了新单实例bean-B
newSingleton = true;
}
catch (IllegalStateException ex) {
//...........
}
//..........
// 如果成功创建了新的单实例bean-B,则将B的实例添加到一级缓存,并清除二、三级缓存。
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
// 最后返回B
return singletonObject;
}
}
返回到descriptor.resolveCandidate处。
第十一步处理
descriptor.resolveCandidate将B实例返回到doResolveDependency,进而再返回到AutowiredAnnotationBeanPostProcessor的postProcessProperties方法去执行inject(这里是回到了第四步处理),将B注入到A中:
java
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 第一步,收集需要注入的元数据信息
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// 第二步,执行注入:先找到B实例,在注入到A中
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
执行完这里后,A的依赖注入就完成了,后面会执行初始化(不涉及循环依赖处理)。最后一路返回到第二步处理的
getSingleton方法:
重要的两个处理:
- 把A从正在创建的Bean的集合中移除
- 把A存入一级缓存,从二三级缓存中移除A
java
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
// .................
// 这里的singletonObject就是完成依赖注入与初始化的A
singletonObject = singletonFactory.getObject();
// 如果创建成功,设置newSingleton标志为true,表示创建了新单实例bean-A
newSingleton = true;
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 将A的bean名称从`正在创建的单例bean集合`中移除
afterSingletonCreation(beanName);
}
// 如果成功创建了新的单实例bean-A,则将A的实例添加到一级缓存,并清除二、三级缓存中的A。
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
// 最后返回A
return singletonObject;
}
}
经过这个完整的过程后,A与B都作为完整的Bean被存入了一级缓存。后面在有其他的Bean依赖A或B,便可以直接在doGetBean
方法中,通过第一个getSingleton从一级缓存拿到A或B进行注入了
总体梳理
有两个bean,A与B,A中注入了B,B中注入了A。假设A先进行创建,执行doGetBean方法创建A:
-
doGetBean方法中,会先使用getSingleton方法通过A 的beanName,尝试去一二三级缓存中获取A的实例,因为A 是第一次创建所以这里取不到(会先去一级缓存去,当一级缓存取不到且A 处于正在创建中的状态时,才会再去二三级缓存取。这里A是第一次创建,一级缓存没有,也没有被标记为正在创建中)
-
上面取不到就进行A 的创建,会在
doGetBean方法内另一个重载的getSingleton方法中执行创建,该getSingleton方法会先把A 标记为正在创建中,然后调用createBean方法创建A -
createBean进一步执行到doCreateBean方法,doCreateBean会先把早期(没有属性注入与初始化)A 实例的引用存入三级缓存,然后在执行populateBean方法对A进行属性注入 -
populateBean方法调用AutowiredAnnotationBeanPostProcessor处理器的postProcessProperties方法,先收集A 中需要注入的属性,即B ,然后执行把B 注入到A 中的注入操作(AutowiredFieldElement的inject方法) -
进入
AutowiredFieldElement的inject方法,通过如下的调用流程一直调用到getBean,用getBean获取B 来给A 进行注入:
inject--->resolveFieldValue--->resolveDependency--->doResolveDependency--->resolveCandidate--->getBean -
暂停A 的处理,进入创建B 的过程。
getBean调用doGetBean创建B ,这里相当于循环回到了第一步, 还是在doGetBean方法中先使用第一个getSingleton方法通过B 的beanName,去一二三级缓存中取B ,因为B这里也是第一次创建所以取不到 -
进入
doGetBean的第二个getSingleton方法,因为B 此时也是第一次创建,所以还是取不到。这时B 被标记为正在创建中,并执行createBean方法创建B -
创建B的
createBean进一步执行到doCreateBean方法,doCreateBean会先把早期(没有属性注入与初始化)B 实例的引用存入三级缓存,然后在执行populateBean方法对B进行属性注入 -
处理B 的
populateBean方法调用AutowiredAnnotationBeanPostProcessor处理器的postProcessProperties方法,先收集B 中需要注入的属性,即A ,然后执行AutowiredFieldElement的inject方法把A 注入到B中 -
进入
AutowiredFieldElement的inject方法,还是按照第5 小步的调用流程一直调用到getBean,用getBean获取A 来给B进行注入: -
B 中获取A 的
getBean调用doGetBean,这时在doGetBean的第一个getSingleton方法中,虽然一级缓存获取不到,但是在第2 步中A 被标记为正在创建中,所以此处三级可以获取到A了 -
把从三级缓存获取到的A 返回到第10 步的
AutowiredFieldElement.inject方法处,把A 注入到B 中,此时完成了B的依赖注入。 -
完成B的依赖注入后,继续向上返回,到第7 步创建B 的
getSingleton方法中执行的createBean,这个createBean返回B 实例,在getSingleton方法中把B存入一级缓存并返回 -
回到第6 步,继续A 的注入,把B 注入到A 中,A完成依赖注。然后通过
createBean方法将完整的A 实例返回到doGetBean中的getSingleton方法(第2步),把A从正在创建中的的Bean集合中移除、并存入一级缓存。 -
最后A与B都完成了创建,再有其他的Bean依赖他们时,便可在
doGetBean内的第一个getSingleton方法处,直接从一级缓存拿到A或B进行注入了
延申
其他解决循环依赖的方法
除三级缓存外,也可通过@Lazy注解解决循环依赖,其原理是通过延迟加载来打破循环依赖的链。具体来说,当两个或多个Bean相互依赖时,如果使用@Lazy注解,Spring容器在创建Bean时不会立即注入依赖的Bean,而是注入一个代理对象。当实际需要调用代理对象的方法时,才会去初始化真正的Bean。
关于构造器注入的循环依赖
三级缓存无法解决构造器注入的循环依赖,是因为构造器注入发生在 Bean 实例化阶段,而三级缓存机制依赖于 Bean 已经完成实例化。虽然实例化前会有从一二三级缓存获取bean实例的操作,但是因为bean没有完成实例化及后续步骤,所以获取不到
三级缓存无法解决构造器注入循环依赖的根本原因:
- 时机不匹配:构造器注入发生在 Bean 实例化阶段,而三级缓存机制要求 Bean 必须先完成实例化才能暴露早期引用。
- 依赖顺序:构造器参数必须在实例化之前就解析完成,此时当前 Bean 还没有被创建,无法提供早期引用。
- 设计限制:Spring 的设计决定了构造器注入是"全有或全无"的操作,要么所有依赖都可用并成功创建实例,要么失败。