在上一篇文章《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 是从哪来的呢?在后续的文章中我们将就这点展开讨论。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于