基于 Spring Framework v5.2.6.RELEASE
前情提要
上一篇分析了 Spring 执行 Bean 实例初始化的源码,包含了感知接口方法的处理 BeanPostProcessor 中处理方法的执行,以及 Bean 的初始化方法的执行。本篇回到doCreateBean
方法中,继续分析后续的代码。
依赖检查
接着看后续的代码。
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.");
}
}
}
}
这里的判断条件earlySingletonExposure
默认为true
,因此会进入最外层if
语句块,进入之后,会再次尝试通过getSingleton
方法从缓存中获取 Bean 实例。之前,Spring 已经将创建好的 Bean 实例添加到了第三级缓存也就是singletonFactories
中,但是这里调用getSingleton
方法时,传入的allowEarlyReference
的值为true
,也就是不允许从工厂缓存中获取,因此,第一次执行到这里的时候,返回的是null
,此时,下一层的if
语句块中的内容不会被执行。
假设,在 Spring 创建完早期的 Bean 实例,并将其添加到工厂缓存中之后,有其他的地方,通过缓存获取到了早期的 Bean 实例,那么这里是可以获取到earlySingletonReference
的。我们试着分析一下,在这种情况下,Spring 会怎么处理。
首先,判断了exposedObject == bean
,这两个对象分别是执行populateBean
和initializeBean
两个方法之后和之前的 Bean 实例引用。如果它俩还是同一个对象的话,就把earlySingletonReference
赋值给exposedObject
,exposedObject
是最终方法要返回的 Bean 实例对象。
如果它俩已经不是一个对象了,那么在执行else if
语句块中的逻辑。这里判断了在容器不允许循环引用时注入原始 Bean 实例的情况下是否有其他的 Bean 依赖了当前的 Bean,如果有的话,执行后续的检查。找到所有依赖当前 Bean 的 Bean 的名称,通过调用removeSingletonIfCreatedForTypeCheckOnly
方法,将其中不在alreadyCreated
集合中的beanName
对应的 Bean 从容器中移除,这部分是指用于类型检查的 Bean。如果其中有alreadyCreated
集合中包含的 Bean,则将其添加到actualDependentBeans
集合中。最后,如果actualDependentBeans
不为空,则抛出异常。异常信息大意是说,当前的 Bean 已经作为循环引用的一部分以原始的版本注入了其他的 Bean 中,但已经被包装,意味着那些 Bean 使用的不是当前 Bean 的最终版本。
注册 DisposableBean
接下来是最终的 Bean 实例被返回之前的最后一段代码。
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
根据方法名称,这里注册了 DisposableBean,目前我们还不知道 DisposableBean 是什么,进入方法看看源码。
// org.springframework.beans.factory.support.AbstractBeanFactory#registerDisposableBeanIfNecessary
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
if (mbd.isSingleton()) {
// Register a DisposableBean implementation that performs all destruction
// work for the given bean: DestructionAwareBeanPostProcessors,
// DisposableBean interface, custom destroy method.
registerDisposableBean(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
else {
// A bean with a custom scope...
Scope scope = this.scopes.get(mbd.getScope());
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
}
scope.registerDestructionCallback(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
}
}
这里根据当前的 Bean 是不是单例 Bean 分别做了处理,如果是单例 Bean 的话,执行了如下操作:
registerDisposableBean(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
进入registerDisposableBean方法:
public void registerDisposableBean(String beanName, DisposableBean bean) {
synchronized (this.disposableBeans) {
this.disposableBeans.put(beanName, bean);
}
}
这里只是把beanName
和调用方法时创建的 DisposableBeanAdapter 添加到了容器的disposableBeans
集合中。我们再看看 DisposableBeanAdapter 到底是什么。
DisposableBeanAdapter
它是 DisposableBean 接口的一个实现类,DisposableBean 的接口定义如下:
public interface DisposableBean {
void destroy() throws Exception;
}
这里只有一个destroy
方法。DisposableBean 其实是一个跟上一篇中介绍的 InitializingBean 很类似的接口。InitializingBean 中定义了 Bean 初始化时调用的方法afterPropertiesSet
,而 DisposableBean 中的destroy
方法则是 Bean 实例被销毁的时候调用的。也就是说,如果一个 Bean 想要在自己被销毁时执行一些自定义的逻辑,就可以通过实现 DisposableBean 接口,在destroy
方法中实现这些逻辑。
同样的,即使不实现 DisposableBean 接口,也可以跟 InitializingBean 对应的init-method属性一样,在 XML 中指定一个实例销毁时执行的方法名称。配置方式如下:
<bean id="user" class="xxx.User" destroy-method="destroy" />
DisposableBeanAdapter 类实现了 DisposableBean 接口,那它肯定包含了销毁 Bean 实例的逻辑。这里 Spring 通过调用registerDisposableBean方法,为每一个刚刚初始化完的 Bean 都注册了销毁的逻辑。注意,这里只是注册,这段逻辑只会在对象被销毁的时候,由 Spring 调用destroy
方法执行。
Spring 为 Bean 实例注册的销毁逻辑
接下来,找到 DisposableBeanAdapter 的destroy
方法,看看这里具体为每个 Bean 添加了那些注销的逻辑。
// org.springframework.beans.factory.support.DisposableBeanAdapter#destroy
@Override
public void destroy() {
if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
processor.postProcessBeforeDestruction(this.bean, this.beanName);
}
}
if (this.invokeDisposableBean) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking destroy() on bean with name '" + this.beanName + "'");
}
try {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((DisposableBean) this.bean).destroy();
return null;
}, this.acc);
}
else {
((DisposableBean) this.bean).destroy();
}
}
catch (Throwable ex) {
String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
if (logger.isDebugEnabled()) {
logger.warn(msg, ex);
}
else {
logger.warn(msg + ": " + ex);
}
}
}
if (this.destroyMethod != null) {
invokeCustomDestroyMethod(this.destroyMethod);
}
else if (this.destroyMethodName != null) {
Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
if (methodToInvoke != null) {
invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
}
}
}
方法中用到的一些成员变量,是在创建 DisposableBeanAdapter 时,构造方法中初始化的。这个方法算是 Spring 给每个 Bean 提供的销毁逻辑的实现,代码不少,但是仔细看一下关键的逻辑并不多:
首先,找到 Bean 对应的 DestructionAwareBeanPostProcessor 后处理器,执行其postProcessBeforeDestruction
方法。后处理器见过很多了,这里就不再详细介绍了,它也是 BeanPostProcessor 的子接口,这个方法在执行销毁逻辑之前调用,可以看作是 Spring 给我们留了一个执行销毁逻辑之前的扩展点。
然后,判断invokeDisposableBean
成员变量的值,这个成员变量是在构造方法中初始化的,我们看一下它的值是怎么来的。
this.invokeDisposableBean =
(this.bean instanceof DisposableBean && !beanDefinition.isExternallyManagedDestroyMethod("destroy"));
这里其实跟调用初始化方法时的判断逻辑是一样的,回到destroy
方法中,如果当前的 Bean 实现了 DisposableBean 接口,并且它的destroy
方法不是外部管理的,那么就调用它的destroy
方法。
最后一部分,调用invokeCustomDestroyMethod方法的逻辑,跟调用自定义初始化方法的逻辑也类似,如果配置了自定义的销毁方法(也就是bean标签的destroy-method
属性),则执行。
总结
至此,用了 10 篇文章,从getBean方法开始,Spring 创建和初始化 Bean 实例对象的过程就分析完了。