怎么出现循环依赖的异常呢?写了一个例子来实现?
@Component
public class ModelA {
private ModelB modelB;
@Autowired
public ModelA(ModelB modelB){
this.modelB = modelB;
}
}
@Component
public class ModelB {
private ModelA modelA;
@Autowired
public ModelB(ModelA modelA){
this.modelA = modelA;
}
}
@Configuration
@ComponentScan(basePackages = { "com.example.demo.cycle" })
public class Test {
public static void main(String[] args) {
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { Test.class })
public class UnitTest {
@org.junit.Test
public void givenCircularDependency_whenConstructorInjection_thenItFails() {
}
}
既然会出现这种问题,那么Spring又是如何解决的呢?
处理条件
- 循环依赖的Bean是单例的
- 依赖注入的方式不能是构造函数注入的
解决方式
直接上源码,逻辑都在源码中
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
//初始化beanName
String beanName = this.transformedBeanName(name);
//从缓存中加载bean,也就是从singletonObjects容器中获取
Object sharedInstance = this.getSingleton(beanName);
Object bean;
//如果缓存中存在bean
if (sharedInstance != null && args == null) {
//检查日志的trace
if (this.logger.isTraceEnabled()) {
//判断bean是否在创建,如果是则将信息加入到logger中
if (this.isSingletonCurrentlyInCreation(beanName)) {
this.logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
} else {
this.logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//将从缓存中获取到的bean进行实例化
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
} else {//这是singletonObjects容器中没有对应的bean
//此处进行循环依赖的检查,判断bean是否进行prototype类型的创建,如果是则抛出循环依赖异常,
//Spring解决循环依赖需要bean是单例
if (this.isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
//加载父工厂,因为ingletonObjects容器中获取不到bean,所以到父工厂中获取
BeanFactory parentBeanFactory = this.getParentBeanFactory();
//判断父工厂是否为null以及判断配置文件是否包含bean所对应的属性,如果不包含就到parentBeanFacotory中加载bean
if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
String nameToLookup = this.originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
}
if (args != null) {
return parentBeanFactory.getBean(nameToLookup, args);
}
if (requiredType != null) {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
return parentBeanFactory.getBean(nameToLookup);
}
if (!typeCheckOnly) {
this.markBeanAsCreated(beanName);
}
try {
//获取bean的属性
RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
this.checkMergedBeanDefinition(mbd, beanName, args);
//判断当前bean是否依赖其它bean,如果依赖则先初始化依赖的这个bean
String[] dependsOn = mbd.getDependsOn();
String[] var11;
if (dependsOn != null) {
var11 = dependsOn;
int var12 = dependsOn.length;
for(int var13 = 0; var13 < var12; ++var13) {
String dep = var11[var13];
if (this.isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
//注册一个当前bean依赖的其它bean,依赖的其它bean注册到dependenciesForBeanMap容器中
this.registerDependentBean(dep, beanName);
try {
this.getBean(dep);
} catch (NoSuchBeanDefinitionException var24) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", var24);
}
}
}
//判断bean的类型(Singleton、Prototype、Scope),然后进行初始化
if (mbd.isSingleton()) {
sharedInstance = this.getSingleton(beanName, () -> {
try {
//创建bean方法
return this.createBean(beanName, mbd, args);
} catch (BeansException var5) {
this.destroySingleton(beanName);
throw var5;
}
});
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) {
var11 = null;
Object prototypeInstance;
try {
this.beforePrototypeCreation(beanName);
prototypeInstance = this.createBean(beanName, mbd, args);
} finally {
this.afterPrototypeCreation(beanName);
}
bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} else {
String scopeName = mbd.getScope();
Scope scope = (Scope)this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
this.beforePrototypeCreation(beanName);
Object var4;
try {
var4 = this.createBean(beanName, mbd, args);
} finally {
this.afterPrototypeCreation(beanName);
}
return var4;
});
bean = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
} catch (IllegalStateException var23) {
throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton", var23);
}
}
} catch (BeansException var26) {
this.cleanupAfterBeanCreationFailure(beanName);
throw var26;
}
}
//检查所需类型是否与bean实例的类型是否匹配。
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = this.getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
} else {
return convertedBean;
}
} catch (TypeMismatchException var25) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", var25);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
} else {
return bean;
}
}
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
//存放单例bean的容器
private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
//存放需要提前引用的bean的容器
private final Map<String, Object> earlySingletonObjects = new HashMap(16);
//存放依赖bean的容器
private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap(64);
@Nullable
public Object getSingleton(String beanName) {
return this.getSingleton(beanName, true);
}
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
synchronized(this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
//将需要提前引用的bean存放到容器中
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
}
总结
-
各种面试题总说Spring解决循环依赖是依靠三级缓存,现在看了源码知道了三级缓存其实就是三个容器:singletonObjects 、earlySingletonObjects 、dependenciesForBeanMap 。
-
整体流程总结:
-
从singletonObjects 中加载bean,如果获取不到则将bean通过put方法放入earlySingletonObjects 中。
-
如果获取到bean则将获取到的bean进行实例化
-
进行循环依赖检查
-
singletonObjects 没有数据则到parentBeanFactory中获取
-
获取bean的属性
-
检查属性中是否依赖其它bean,如果依赖则先初始化依赖的bean
-
最后根据不同的类型创建bean的实例
-
按照这个逻辑慢慢读,我懂了,你呢?