在上一篇文章《SpringBoot 系列:(一)SpringBoot 启动过程》 的章节“执行 ConfigurableApplicationContext 对象的 refresh 方法 ”中,我们一句话跳过了对 ConfigurableApplicationContext 的 refresh 方法的解析,未做深入的解读。而在执行 refresh 方法之前,SpringApplication 帮我们做了一些准备工作;在执行 refresh 方法之后,整个容器已经构建成功可以被正常使用了。那么,这个 refresh 方法到底内部进行了何种处理?这即是本文需要探讨的问题。
以下,我将以 AnnotationConfigApplicationContext 为示例,分析其 refresh 方法是如何来构建 BeanFactory 的。
总体流程
下图展示的是 AnnotationConfigApplicationContext 的继承关系。跟踪其 refresh 方法,最终追溯到 AbstractApplicationContext 类的 refresh 方法上。
从 AbstractApplicationContext 类的 refresh 方法,我们大致整理出如下的容器构建流程:
- 准备工作
- 生成一个 BeanFactory 实例
- 调整 BeanFactory
- 触发 BeanFactoryPostProcessor
- 注册 BeanPostProcessor
- 其他动作
- 初始化 MessageSource
- 初始化事件广播器
- onRefresh 回调
- 注册事件监听器
- 初始化 Singleton bean
- 后续处理
从AbstractApplicationContext类的refresh方法代码
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备工作,记录容器启动时间、标记启动状态、处理配置文件中的占位符
prepareRefresh();
// 获取一个beanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 对beanFactory做进一步调整,如设置类加载器等
prepareBeanFactory(beanFactory);
try {
// 钩子方法,开放给AbstractApplicationContext的子类实现
postProcessBeanFactory(beanFactory);
// 调用所有的BeanFactoryPostProcessor的postProcessBeanFactory方法
invokeBeanFactoryPostProcessors(beanFactory);
// 注册BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 初始化MessageSource,用于国际化
initMessageSource();
// 初始化事件广播器
initApplicationEventMulticaster();
// 钩子方法,开放给AbstractApplicationContext的子类实现
onRefresh();
// 注册事件监听器
registerListeners();
// 初始化所有的非lazy的singleton bean【重点】
finishBeanFactoryInitialization(beanFactory);
// 一些后续处理动作,如广播ContextRefreshedEvent事件
finishRefresh();
}catch (BeansException ex) {
//代码省略
}finally {
resetCommonCaches();
}
}
}
各流程探究
下面,我们将就上述的各流程,深入到代码中,查看每一个流程究竟干了哪些事情。
准备工作
这里的准备工作,主要是指 AbstractApplicationContext 的 prepareRefresh 方法
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
//省略日志输出
initPropertySources();
getEnvironment().validateRequiredProperties();
this.earlyApplicationEvents = new LinkedHashSet<>();
}
从代码不难看出 ,准备工作包括记录启动时间、标记启动状态、处理配置文件中的占位符、验证配置文件。其中,处理配置文件中的占位符 (initPropertySources)是一个回调方法,AbstractApplicationContext 本身不提供具体实现。
生成一个 BeanFactory 实例
AbstractApplicationContext类
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//省略日志输出
return beanFactory;
}
AbstractApplicationContext 类的 refreshBeanFactory 和 getBeanFactory 方法,都由其子类 GenericApplicationContext 实现
GenericApplicationContext类
protected final void refreshBeanFactory() throws IllegalStateException {
// 代码省略
this.beanFactory.setSerializationId(getId());
}
public final ConfigurableListableBeanFactory getBeanFactory() {
return this.beanFactory;
}
通过代码可知,GenericApplicationContext 的 beanFactory 是一个 DefaultListableBeanFactory 实例。后续所有 bean 的管理,都是委托给该 beanFactory 进行的。因此,本质上 AnnotationConfigApplicationContext 是以一种组合的方式来实现容器的功能,而非用继承的方式。
对于非 SpringBoot 工程,比如,使用 ClassPathXmlApplicationContext 构建容器时,AbstractApplicationContext 的子类 AbstractRefreshableApplicationContext 会实现 refreshBeanFactory 方法:在生成一个 DefaultListableBeanFactory 实例后,会用该实例去加载类路径下的 xml 文件,从而维护一个 beanName 到 beanDefinition 的 map。此时,beanDefinition 中记录的是 bean 的配置信息,bean 对象还未生成。
回到主流程上,对于 AnnotationConfigApplicationContext 而言,通过 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(),AbstractApplicationContext 获取到的 beanFactory 是一个 DefaultListableBeanFactory 实例。
调整 BeanFactory
调整 BeanFactory,包含了 AbstractApplicationContext 类本身对于 beanFactory 的调整(AbstractApplicationContext 的 prepareBeanFactory 方法),以及 AbstractApplicationContext 的子类对于 beanFactory 的调整。
触发 BeanFactoryPostProcessor
通过 PostProcessorRegistrationDelegate 的 invokeBeanFactoryPostProcessors 方法来触发 BeanFactoryPostProcessor 的 postProcessBeanFactory。这里,我们需要区分一下 BeanFactoryPostProcessor 以及后续马上就要遇到的 BeanPostProcessor。
BeanFactoryPostProcessor 是用来处理、修改 bean 定义信息的后置处理器,这个时候 bean 还没有初始化,只是定好了 BeanDefinition。BeanFactory 创建时,在 BeanFactoryPostProcessor 接口的 postProcessBeanFactory 方法中,我们可以修改 bean 的定义信息,例如修改属性的值,修改 bean 的 scope 为单例或者多例。
而 BeanPostProcessor 则用于 bean 初始化前后对 bean 做一些操作,即 bean 的构造方法调用后(大前提,bean 实例已经生成了),在 bean 的初始化方法调用前和 bean 的初始化方法调用后,可以通过 BeanPostProcessor 对 bean 做一些修改。
一个 bean 的生命周期如下图所示:
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
public interface BeanPostProcessor {
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
这里需要注意,在调用 AnnotationConfigApplicationContext 的构造方法时,在其内部生成了一个 AnnotatedBeanDefinitionReader。在 AnnotatedBeanDefinitionReader 的生成过程中,会向 beanFactory 注册一个 ConfigurationClassPostProcessor。
ConfigurationClassPostProcessor 是一个 BeanFactoryPostProcessor,用于解析处理各种注解,包括:@Configuration、@ComponentScan、@Import、@PropertySource、@ImportResource、@Bean。SpringBoot 的自动配置也是通过 ConfigurationClassPostProcessor 来完成。
注册 BeanPostProcessor
AbstractApplicationContext 通过 PostProcessorRegistrationDelegate.registerBeanPostProcessors 来注册 BeanPostProcessor
其他动作
这里说的其他动作,包含初始化 MessageSource、初始化事件广播器、执行子类的 onRefresh 回调和注册事件监听器。由于不是我们关注的主要内容,因此不展开详细说明。
初始化 Singleton bean
AbstractApplicationContext 类
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// ... 省略很多代码
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
}
根据前面的分析,这里的 beanFactory 是一个 DefaultListableBeanFactory 类实例。
DefaultListableBeanFactory类
public void preInstantiateSingletons() throws BeansException {
//省略很多代码
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
...
}
else {
getBean(beanName);
}
}
}
}
getBean(beanName) 最终调用AbstractBeanFactory
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//... 省略很多代码
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
}
AbstractAutowireCapableBeanFactory类
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
//... 省略很多代码
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
//... 省略很多代码
}
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {
//... 省略很多代码
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
//创建一个BeanWrapper
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
Object exposedObject = bean;
try {
//属性装配。前面只是实例化了,但是各个字段还没有值
populateBean(beanName, mbd, instanceWrapper);
// 各种ware、init-method、BeanPostProcessor等都是在这里处理的
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
return exposedObject;
}
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
...
}
else {// 注入各种ware
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//调用BeanPostProcessors的postProcessBeforeInitialization
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
//调用init方法
invokeInitMethods(beanName, wrappedBean, mbd);
if (mbd == null || !mbd.isSynthetic()) {
//调用BeanPostProcessors的postProcessInitialiAfterzation
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
至此,一个 BeanFactory 构造完毕并能被正常使用了。
- 后续处理
最后,广播事件,ApplicationContext 初始化完成等。非重点,跳过不分析。
总结
我们以 AnnotationConfigApplicationContext 为例,分析了 BeanFactory 的构建过程。
在文中曾提及,使用 ClassPathXmlApplicationContext 构建容器时,生成 DefaultListableBeanFactory 实例后,该实例会去加载类路径下的 xml 文件,从而维护一个 beanName 到 beanDefinition 的 map。后续则是基于这些 beanDefinition 来实例化所有的 no-lazy singleton bean 的。
但从前面的分析中可以看出,SpringBoot 启动主流程并没有主动去维护类似的 beanName 到 beanDefinition 的 map。那么,SpringBoot 实例化各种 bean 的时候,对应的 BeanDefinition 是从哪来的呢?在后续的文章中我们将就这点展开讨论。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于