理论基础
Spring解决循环依赖基于Java的引用传递,当获得对象的引用时,对象的属性是可以延后设置的。但是构造器必须是在获取引用之前执行
Java值传递与引用传递
Bean实例化和初始化
Bean创建流程
Spring IOC容器的三级缓存
//DefaultSingletonBeanRegistry.class
/** 一级缓存,保存已经创建Bean,可以直接使用*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** 二级缓存,保存已实例化(执行了构造方法)但尚未注入属性的Bean*/
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/** 三级缓存,保存ObjectFactory<?>,解决动态代理创建Bean可能导致Bean不唯一问题 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** 当前正在创建Bean集合,Bean开始创建前放入,完成创建后移除 */
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
ObjectFactory
// 函数式接口,支持Lambda表达式,它可以将创建对象的步骤封装到ObjectFactory中交给自定义的Scope来选择是否需要创建对象来灵活的实现scope。具体参见Scope接口
@FunctionalInterface
public interface ObjectFactory<T> {
T getObject() throws BeansException;
}
样例分析
假设当前Spring应用中存在两个Service类互相依赖且应用启懂事首先创建ServiceA实例
public class ServiceA {
@Autowired
private ServiceB serviceB;
...
}
public class ServiceB {
@Autowired
private ServiceA serviceA;
...
}
源码分析
Bean创建主流程为AbstractBeanFactory.class的doGetBean方法,这里主要分析单例且为非懒加载(non-lazy)加载Bean的创建过程
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// 步骤1:尝试从1级缓存获取Bean实例(针对手动注册到容器中Bean)
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 此处代码省略...
try {
// 获取Bean定义
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// 此处代码省略...
// 步骤2:Bean实例创建
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);
}
// 此处代码省略...
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// 此处代码省略...
return (T) bean;
}
分支流程步骤1处getSingleton方法如下,ServiceA实例未创建,也不存在当前正创建Bean (isSingletonCurrentlyInCreation)集合中,此处直接返回null
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 首先从1级缓存获取Bean,获取到直接返回
Object singletonObject = this.singletonObjects.get(beanName);
// 如果1级缓存中没有并且待获取Bean正在创建中,尝试从2级缓存获取
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
// 如果2级缓存中没有并且待获取Bean允许提前暴露引用,尝试从3级缓存获取Bean
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 通过getObject()拿到半成品Bean
singletonObject = singletonFactory.getObject();
// 将半成品Bean放入2级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
// 从3级缓存移除
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
步骤2处getSingleton方法
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
// 再次尝试从1级缓存获取
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
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!)");
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 在这里执行传入ObjectFactory方法创建Bean(即createBean方法)
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// Bean创建完成后添加至1级缓存,并从2,3级缓存中移除
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
createBean方法会转至AbstractAutowireCapableBeanFactory.class#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()) {
// 创建Bean对象,并且将对象包裹在BeanWrapper中
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 再从Wrapper中把Bean原始对象(非代理), 此时Bean有了地址值能被引用
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
// ...
// 是否提前暴露原始对象的引用(单例 && 允许循环依赖 && 当前正在创建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的早期引用方法添加至3级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
// Bean属性填充
populateBean(beanName, mbd, instanceWrapper);
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) {
// 此处getSingleton第二个参数为false->不会从3级缓存获取Bean
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
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(...);
}
}
}
}
// ...
return exposedObject;
}
在ServiceA属性注入时需要创建ServiceB,此时会回到AbstractBeanFactory.class的doGetBean方法进行ServiceB的Bean创建
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
@Async注解使用不当导致spring循环依赖异常问题分析
启动报错信息如下:
[ERROR] 211220 14:44:34.802 - Application run failed (org.springframework.boot.SpringApplication) (main)
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'fqaDefectServiceImpl': Unsatisfied dependency expressed through field 'fqaReportService'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'fqaReportServiceImpl': Bean with name 'fqaReportServiceImpl' has been injected into other beans [fqaTaskInfoServiceImpl] 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.
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:584)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:370)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1336)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:572)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:759)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:548)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:386)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
at com.tplink.tpqms.TpqmsApplication.main(TpqmsApplication.java:31)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。