目录
一、前言
二、模拟场景
三、Spring实现流程
四、源码解读
1、加载ServiceA
2、添加缓存
3、依赖注入
4、实例化ServiceB
5、对ServiceB进行依赖注入
6、Spring重新加载剩余单例
7、重新加载ServiceA
8、循环依赖
一、前言
Spring以5.2.x版本为例,通过debug源码调试、图文解读方式,彻底了解spring在循环依赖的处理上做了哪些工作。
二、模拟场景
创建两个service,在ServiceA中注入ServiceB,在ServiceB中注入ServiceA,这样ServiceA和ServiceB便相互引用,也就形成了循环依赖。
代码如下:
package com.zhufeng.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author 月夜烛峰
* @date 2022/8/16 10:35
*/
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
}
package com.zhufeng.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author 月夜烛峰
* @date 2022/8/16 10:36
*/
@Service
public class ServiceB {
@Autowired
private ServiceA serviceA;
}
三、Spring实现流程
为了更为清晰明了的阅读后续部分,先整理了spring解决循环引用的流程图,本篇也是围绕该图结合spring源码实现进行详细讲解。
四、源码解读
1、加载ServiceA
在spring启动时,会扫描所有需要加载的bean,带有@Controller、@Service、@Autowired等注解都会被spring扫描,然后进行实例化。
源码:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
扫描到ServiceA时,会先创建一个ServiceA的实例,serviceB作为ServiceA中的一个属性,初始值为null,此时ServiceA还处于创建中。
注意:
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
这里就是spring解决循环依赖的方法,简单理解就是:提前将已实例化的但还未设置依赖的bean实例缓存起来。
2、添加缓存
把已经实例化的bean添加到singletonFactory中
//这里有三个判断条件:1、是否为单例;2、是否允许循环依赖;3、当前单例是否正在创建中
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");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
3、依赖注入
扫描ServiceA中需要依赖注入的bean,也就是serviceB。
首先从beanFactory中获取是否存在serviceB的实例化对象。
此时serviceB并没有开始实例化,所以为null。
注入代码:
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
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;
}
ServiceA先实例化,依赖先不加载,代码逻辑如下:
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
...
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// 此处判断,可能存在循环依赖
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
...
if (!typeCheckOnly) {
// 此处先将ServiceA实例化,但不加载依赖
markBeanAsCreated(beanName);
}
try {
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
...
}
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
...
}
else {
...
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
...
return (T) bean;
}
也就是这里
if (!typeCheckOnly) {
// 此处先将ServiceA实例化,但不加载依赖
markBeanAsCreated(beanName);
}
至此,ServiceA的创建过程告一段落。
4、实例化ServiceB
Spring开始实例化ServiceB,过程和ServiceA相同
在实例化ServiceB的过程中,先也将ServiceB加入缓存
在singletonFactories中已经存在serviceA的实例化对象。
5、对ServiceB进行依赖注入
扫描ServiceB中的serviceA,开始依赖注入
源码如下:
/**
* Class representing injection information about an annotated field.
*/
private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {
private final boolean required;
private volatile boolean cached;
@Nullable
private volatile Object cachedFieldValue;
public AutowiredFieldElement(Field field, boolean required) {
super(field, null);
this.required = required;
}
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
if (!this.cached) {
Object cachedFieldValue = null;
if (value != null || this.required) {
cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
this.cachedFieldValue = cachedFieldValue;
this.cached = true;
}
}
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}
源码第667行,在注入serviceA之前,serviceA为null
由于servcieA已经在缓存中存在,所以从缓存中根据serviceA可以获取ServiceA的实例,注入成功,如上图。
至此,ServiceB完成实例化以及依赖注入。
6、Spring重新加载剩余单例
当所有bean都完成实例化后,spring开始加载所有剩下的非懒加载的单例
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
源码:org.springframework.context.support.AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
7、重新加载ServiceA
spring扫描剩下未完成初始化的单例,servcieA中缺少注入依赖,会重新执行实例化流程。
8、循环依赖
此时ServiceB已完成实例化,所以可以从缓存中获取serviceB
ServiceA中的serviceB此时还没有注入,所以为null
完成注入后,可以看到出现了循环依赖,但spring加载正常,没有报错。
这里就是spring解决循环依赖的方法,一句话就是:提前将已实例化的但还未设置依赖的bean实例缓存起来。