BeanCurrentlyInCreationException循环依赖问题

问题

问题代码

@Service
public class ForlanAServiceImpl implements ForlanAService {

	@Autowired
	private ForlanBService forlanBService;

	@Async
	public void test(){

	}
	
	//省略代码...
}

@Service
public class ForlanBServiceImpl implements ForlanBService {

	@Autowired
	private ForlanAService forlanAService;

	//省略代码...
}

出现BeanCurrentlyInCreationException异常

Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'forlanAServiceImpl': Bean with name 'forlanAServiceImpl' has been injected into other beans [forlanBServiceImpl] 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 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:623) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
	at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1307) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1227) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
	... 33 common frames omitted

分析

看异常信息,其实就是出现了循环依赖问题
我们找到对应的异常信息源码,如下:

if (earlySingletonExposure) {
	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(beanName,
						"Bean with name '" + beanName + "' has been injected into other beans [" +
						StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
						"] 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 " +
						"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
			}
		}
	}
}

可以看出,正常情况下,Spring已经帮我们处理循环依赖的问题,通过提前暴露对象(未完全初始化的对象),但是为什么我们这里不行?
出现上面的异常情况,需要满足3个条件:
1、这里如果不相等,说明exposedObject 被改变了,被增强了

if (exposedObject == bean) {
	exposedObject = earlySingletonReference;
}

2、实例化的类依赖其它类

else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName))

3、依赖的类还没实例化好

if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
	actualDependentBeans.add(dependentBean);
}

所以,是因为在类ForlanAServiceImpl中加入异步方法时,Spring会创建一个代理对象来执行该异步方法,这个代理对象在创建过程中也需要依赖其他Bean,而这个代理对象所在的类A与其他Bean存在循环依赖关系,就会导致BeanCurrentlyInCreationException异常

解决

@Service
public class ForlanBServiceImpl implements ForlanBService {

	@Autowired
	@Lazy
	private ForlanAService forlanAService;

	//省略代码...
}

你可能感兴趣的:(Java,java)