基于 Spring Framework v5.2.6.RELEASE
前情提要
上一篇分析了 Spring 完成早期 Bean 实例的创建后的一部分流程,其中包括很重要的属性注入的部分,这一篇接着分析之后的代码。在doCreateBean
方法中,属性注入的部分在populateBean
方法中完成,本文分析initializeBean
方法的源码,它在populateBean
执行完成之后执行,完成 Bean 实例的初始化。
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
Bean 实例的初始化
进入initializeBean
方法查看源码。
// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
虽然也是一个很重要的步骤,但是其中的代码并不多,而且仔细分析之后,发现关键代码就是以下的 4 行,从调用的方法名称,也能知道它们的具体作用:
invokeAwareMethods(beanName, bean)
执行感知接口的方法。applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)
执行后处理器中初始化之前的处理invokeInitMethods(beanName, wrappedBean, mbd)
执行初始化方法applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName)
执行后处理器中初始化之后的处理
接下来逐一分析。
执行感知接口的方法
先看invokeAwareMethods
方法。
// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeAwareMethods
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
这里的逻辑很简单,如果 Bean 实现了 BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 三个接口中的一个或多个,就调用接口的方法,将对应的属性注入到 Bean 实例中。这里只处理了这三个跟 Bean 本身有关的感知接口,其他的比如 ApplicationContextAware 等感知接口的处理逻辑,其实在容器初始化的过程中,已经通过 BeanPostProcessor 的方式注册到了容器中,可以参考 Spring 源码阅读 12:BeanFactory 预处理 中的「添加感知接口的后处理器」小节。
执行后处理器在初始化前后的处理逻辑
接下来看后处理器的处理逻辑,分别在执行 Bean 初始化方法的前后执行了 BeanPostProcessor 的postProcessBeforeInitialization
和postProcessAfterInitialization
方法。
// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
这两个方法的逻辑除了调用了后处理器的不同方法以外,其他都没什么区别。
在分析 Spring 容器初始化的代码时,曾经详细介绍过 BeanPostProcessor,如果我们需要自定义一些 Bean 初始化前后的处理逻辑,可以开发一个 BeanPostProcessor 的实现类,并将其作为 Bean 添加到配置文件中,在 Spring 初始化容器的过程中,会将所有 BeanPostProcessor 类型的 Bean 都作为后处理器注册到容器中,并且在注册前还进行了排序。因此,在这里执行后处理器逻辑的时候,直接按列表中的顺序执行就可以了。
关于 BeanPostProcessor 的更详细内容,以及 BeanPostProcessor 是如何注册到容器中的,可以参考这篇:Spring 源码阅读 14:注册 BeanPostProcessor
执行 Bean 的初始化方法
接下来看invokeInitMethods
方法。
// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeInitMethods
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
这段代码的逻辑也很简单,主要是两部分:
- 如果当前处理的 Bean 实例实现了 InitializingBean 接口,那么调用它的
afterPropertiesSet
方法。 - 从 BeanDefinition 中获取initMethodName,也就是初始化方法名称,在 Bean 实例上执行这个方法。
这两部分分开来讲。
InitializingBean
先看 InitializingBean 接口是什么。
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
接口中只定义了一个afterPropertiesSet
方法,也就是说,如果一个 Bean 实现了 InitializingBean 接口,那么它的afterPropertiesSet
将会在这个时候被调用。因此,如果我们需要一个 Bean 在初始化的时候执行一段特定的逻辑,可以通过实现 InitializingBean 接口,在afterPropertiesSet
实现这些逻辑。
这一部分只针对实现了 InitializingBean 接口的 Bean 实例。
自定义初始化方法
接下来看第二部分。首先会获取 BeanDefinition 的initMethodName
成员变量,它其实对应的 XML 配置文件中bean
标签的init-method
属性,这个属性的值对应类中的一个同名的无参方法。配置方法如下:
<bean id="user" class="xxx.User" init-method="init" />
获取到方法名,在执行之前,还要进行以下一系列判断:
- 方法名不能是空的
- 如果当前的 Bean 实现了 InitializingBean 接口,且这里配置的方法名是afterPropertiesSet,那么,这个方法在之前已经执行过了,这里不在执行。
- 通过
isExternallyManagedInitMethod
方法判断,如果是外部管理的初始化方法,则不在此处执行。
判断无误后,会通过invokeCustomInitMethod
执行这个自定义的初始化方法。这个方法的代码比较多,但是逻辑比较简单,就是通过反射,执行方法。
总结
至此,initializeBean
方法中的源码就分析完了。完成了初始化的方法之后,Spring 创建和初始化 Bean 实例的流程也接近了尾声,后面还有一些最后的处理工作,留到下一篇中进行分析。