构造器循环依赖
示例
@Component
public class RoleService {
private UserService userService;
public RoleService(UserService userService) {
this.userService = userService;
}
}
@Component()
public class UserService {
private RoleService roleService;
public UserService(RoleService roleService) {
this.roleService = roleService;
}
}
结果
BeanCurrentlyInCreationException
该问题无法解决
具体分析参照下面
field循环依赖
默认singleton
示例
@Component
public class RoleService {
@Autowired
private UserService userService;
public void test() {
System.out.println("RoleService->" + userService);
}
}
@Component()
public class UserService {
@Autowired
private RoleService roleService;
public void test() {
System.out.println("UserService->" + roleService);
}
}
结果
可以成功创建,并自动注入
Spring对循环依赖的处理方案
创建Bean的简要流程,以上面示例代码为例
- 检测到要创建roleService
- 调用无参构造,实例化
- 检测到依赖userService
- 将bean"roleService"标志为创建中的状态,并将已经实例化的roleService放到缓存(map)中
- 去beanFactory中去获取userService
- 没有获取到,就回去创建
- 调用userService的无参构造,实例化
- 检测到依赖roleService
- 去缓存(map)中查找,获取到roleService,并注入
- userService初始化完成
- 从beanFactory中获取userService,并注入roleService
- roleService初始化完成
源码分析
我们从AnnotationConfigApplicationContext的构造方法进入,
在refresh()方法中
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
然后进入到
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
其中,显然不是FactoryBean,所以会进入else里的getBean(beanName)
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}
进入方法,最后会进入到doGetBean方法,第一次,显然还没有实例化bean,上面的判断会跳过,会先执行如下方法
// 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);
}
然后会进入其中的createBean(beanName, mbd, args),进入到doCreateBean方法,以下就会完成roleService的实例化,但是此时其中的成员变量userService还是null
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
接下来会执行到如下代码
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));
}
进入addSingletonFactory,可以看到Spring会把已经实例化的roleService存储到singletonFactories中,registeredSingletons中仅存储的beanName
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);
}
}
}
回到doCreateBean方法
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
进入populateBean方法,进入如下循环,当循环到AutowiredAnnotationBeanPostProcessor时,此时就可以进入他的postProcessProperties方法
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
进入postProcessProperties方法
try {
metadata.inject(bean, beanName, pvs);
}
进入到inject方法,此时的beanName就是第一次创建的bean的成员变量,是userService,此时就会去进行userService初始化
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
}
element.inject(target, beanName, pvs);
}
}
}
源码嵌套很多,这里就不贴了,之后还是会进入doGetBean方法,然后和上面类似,调用无参构造,完成userService的实例化,然后依然会去进行注入,这时,就会从上面的singletonFactories中找到已经完成实例化的roleService,完成注入,userService初始化完成,之后再执行完成就会顺利完成对roleService的注入
prototype
如果将以上的userService和roleService任意一个变为prototype,都可以完成注入
但如果两者同时变为prototype,就会抛出BeanCurrentlyInCreationException
由于没有具体应用场景,就不分析了
结论
构造器循环依赖Spring无法解决
singleton的成员变量的循环依赖可以解决,prototype的不行
补充一: beanFactory.getBean()是很强大的方法,其中可以获取容器中的bean,也可以初始化懒加载的bean,也可以每次初始化prototype的bean
补充二:如果是singleton的bean依赖prototype的bean,使用@Lookup就可以每次获取新的prototype的bean,不做任何处理的话,这个bean就会使单例的