循环依赖
Spring使用依赖注入(DI)来实现控制反转(IoC),因而不可避免的会存在循环依赖的情况:当容器中的多个bean
互相引用形成闭环的时候,就出现了循环依赖。
// 创建A时需要B的实例,创建B时也需要A的实例,循环依赖产生
@Component
class A {
@Autowired
B b;
}
@Component
class B {
@Autowired
A a;
}
Spring中,依赖注入又可细分为构造函数注入和setter
注入,相应地循环依赖的产生也有多种情况:
-
A的构造函数依赖B,B的构造函数也依赖A
-
A的构造函数依赖B,B持有一个A类型的属性,反之亦然
-
A持有一个B类型的属性,B也持有一个A类型的属性
如何解决
Spring使用缓存来解决循环依赖,创建bean
时不等它完全初始化就提早暴露到缓存中,后续bean
在创建过程中如果需要依赖其它bean
则优先从缓存中获取(即使此时获取到的bean
不是完全可用的状态)。这种策略其实是基于Java的引用传递,当我们获取到对象的引用时,对象的属性是可以延后设置的(但引用产生的前提是调用了构造函数)。
很明显,在这种策略下前文提到的第一种情况是无法解决的,后两种情况则是有条件的解决。为什么说是有条件的解决呢?我们知道,Spring容器中的bean
存在scope
的概念,prototype
类型的bean
不会被缓存,每次请求都会重新创建一个,而singleton
类型的bean
在整个容器中有且仅有一个,理所应当会被缓存,因而仅有singleton
类型的bean
在产生循环依赖时能够得到解决。
如何实现
了解了循环依赖产生的原因和Spring解决循环依赖的策略,接下来让我们一起探究一下在Spring 5.0.15.RELEASE
中是如何实现的。
不管是构造函数注入还是setter
注入,首先要从容器中获取到对应bean实例
,这部分逻辑在org.springframework.beans.factory.support.AbstractBeanFactory
中:
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
@Override
public <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, null, args, false);
}
可以看到,重载的getBean(...)
最后都代理给了doGetBean(...)
:
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 转换bean name,比如传入的是bean的别名,那么要通过别名获取到真正的bean name
final String beanName = transformedBeanName(name);
Object bean;
// 重点:检查缓存或者创建对象的工厂中是否有对应的实例
// 也正是在这里使用了三级缓存来解决循环依赖
Object sharedInstance = getSingleton(beanName);
// 缓存中有直接返回
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
} else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 如果是FactoryBean需要获取其创建的对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} else {
// prototype类型如果产生循环依赖则无法解决
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 如果当前工厂没有,就向上查找其父工厂
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
} else if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
} else {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
// 如果不仅仅做类型检查
// 就标记一下是创建bean
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
// XML中定义的bean可能会有parent,如果有进行合并
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// 如果设置了前置依赖,先初始化依赖
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
} catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// dependsOn处理完成以后,就可以初始化自身了
if (mbd.isSingleton()) {
// 通过lambda表达式生成的ObjectFactory来创建对象
// 创建完成以后放入缓存
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
} catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
// 同样得处理FactoryBean的情况
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) { // prototype无关缓存,每次都重新创建就完事了
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
} finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} else { // 既不是singleton也不是prototype,就只能通过指定的Scope去创建了
String scopeName = mbd.getScope();
final 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, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
} finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
} catch (IllegalStateException ex) {
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",
ex);
}
}
} catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// 检查一下类型是否匹配
// 如果类型不匹配,尝试进行转换
// 比如说容器中存放的是Number,requiredType是String
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
} catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
其中最重要的就是重载的getSingleton(...)
方法,它定义在AbstractBeanFactory
的父类DefaultSingletonBeanRegistry
中:
@Override
@Nullable
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 首先查看缓存中是否存在
Object singletonObject = this.singletonObjects.get(beanName);
// 缓存中没有,并且正处在创建过程中(比如正解析依赖)
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 再看看有没有提前暴露出来
singletonObject = this.earlySingletonObjects.get(beanName);
// 如果没有提前暴露出来并且允许提前暴露的话
if (singletonObject == null && allowEarlyReference) {
// 那就通过ObjectFactory去创建了
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
// 创建完成以后,从singletonFactories缓存提升到earlySingletonObjects
// 可以看到,二级缓存和三级缓存是互斥的
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
// 首先检查一级缓存
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!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
// 标记当前bean正处在创建过程中
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 通过工厂创建
singletonObject = singletonFactory.getObject();
newSingleton = true;
} catch (IllegalStateException ex) {
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创建完成
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 添加到一级缓存
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
前文提到Spring是基于缓存来解决循环依赖的,这里的缓存指的就是getSingleton(String, boolean)
方法中涉及的三级缓存:
/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
- singletonObjects:用于保存
bean名称
和bean实例
之间的映射关系 - singletonFactories:用于保存
bean名称
和创建bean的工厂
之间的映射关系 - earlySingletonObjects:也是用于保存
bean名称
和bean实例
之间的映射关系,与singletonObjects
不同的是,存放在earlySingletonObjects
中的bean实例
,当它还处在创建过程中的时候就可以通过BeanFactory#getBean(...)
获取到了,其目的是用来检测循环引用
一级缓存在bean
完全初始化以后设置,二级缓存由三级缓存提升而来,三级缓存是在哪里设置的呢?getSingleton(String, ObjectFactory<?>)
中使用到了ObjectFactory
,而 ObjectFactory#getObject()
又调用了createBean(...)
,继续往下追踪,最后来到org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
:
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// 解析beanName对应的beanClass
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// 为lookup method服务
try {
mbdToUse.prepareMethodOverrides();
} catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// 让InstantiationAwareBeanPostProcessor类型的处理器得到执行
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
} catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
// 真正的创建逻辑代理给doCreateBean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
} catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
发现创建bean
的逻辑被代理给了doCreateBean(...)
,继续查看doCreateBean(...)
,刨去无关代码后终于找到了设置三级缓存的逻辑。
// 是singleton类型的bean,且正处在创建过程中
// allowCircularReferences默认是true
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 此时就会将创建这个bean的ObjectFactory存入三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
至此,Spring是如何解决循环依赖的就比较清晰了。
为什么是三级缓存
之所以使用三级缓存,是为了可扩展性。仔细观察存入三级缓存的ObjectFactory,可以看到它调用了getEarlyBeanReference(...)
:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
这个方法主要是判断了一下是否存在SmartInstantiationAwareBeanPostProcessor
类型的BeanPostProcessor
,如果有的话就逐个执行。SmartInstantiationAwareBeanPostProcessor
主要用在Spring框架内部,诸如Autowired
、Aop proxy
均是在这一层实现的。如果只使用两级缓存,bean
的创建就无法延迟执行,也就没有机会进行额外处理了。
网友评论