关于ApplicationContext的启动流程详解

 更新时间:2025年03月10日 08:39:30   作者:冰糖心书房  
ApplicationContext是Spring框架中用于管理和配置Bean的核心接口,它的启动流程包括准备刷新、获取BeanFactory、准备BeanFactory、后置处理BeanFactory、调用BeanFactoryPostProcessor、注册BeanPostProcessor

ApplicationContext的启动流程

  • ApplicationContext 是 Spring IoC 容器的核心接口,它提供了配置、访问和管理 Bean 的功能。
  • ApplicationContext 的启动流程可以细分为以下几个关键步骤,这些步骤主要在 AbstractApplicationContext 类的 refresh() 方法中实现:

1. prepareRefresh()

- 准备刷新:

  • 设置启动时间戳。
  • 设置容器的激活状态。
  • 初始化属性源 (property sources),用于解析占位符(例如,${...})。
  • 验证必需的属性(如果有)。
  • 创建并保存早期事件监听器集合 (early application listeners).

2. obtainFreshBeanFactory()

- 获取 BeanFactory:

  • 如果存在旧的 BeanFactory,则销毁其中的 Bean 并关闭旧的 BeanFactory
  • 创建新的 BeanFactory (通常是 DefaultListableBeanFactory)。
  • 设置 BeanFactory 的序列化 ID (如果需要)。
  • 定制 BeanFactory (例如,设置类加载器、添加后置处理器等)。
  • 加载 Bean 定义 (调用 loadBeanDefinitions 方法):
    • XmlBeanDefinitionReader: 从 XML 配置文件加载。
    • AnnotatedBeanDefinitionReader: 从注解配置类加载。
    • ClassPathBeanDefinitionScanner: 扫描类路径并加载带有注解的 Bean。

3. prepareBeanFactory(beanFactory)

- 准备 BeanFactory:

  • 设置 BeanFactory 的类加载器。
  • 设置表达式解析器 (用于解析 SpEL 表达式)。
  • 设置属性编辑器注册器。
  • 添加内置的 BeanPostProcessor (例如,ApplicationContextAwareProcessorApplicationListenerDetector 等)。
  • 配置依赖关系解析(忽略某些接口的自动装配,注册特殊的依赖项)。
  • 注册一些内置的 Bean (例如,environmentsystemPropertiessystemEnvironment)。

4. postProcessBeanFactory(beanFactory)

- BeanFactory 后置处理:

  • 允许子类对 BeanFactory 进行进一步的定制。
  • 这是一个模板方法,由具体的 ApplicationContext 实现类(如 AnnotationConfigApplicationContext)提供具体实现。

5. invokeBeanFactoryPostProcessors(beanFactory)

- 调用 BeanFactoryPostProcessor:

  • 调用所有已注册的 BeanFactoryPostProcessor (包括 BeanDefinitionRegistryPostProcessor)。
    • 先调用实现了 PriorityOrdered 接口的。
    • 再调用实现了 Ordered 接口的。
    • 最后调用普通的 BeanFactoryPostProcessor
  • BeanFactoryPostProcessor 可以在 Bean 实例化之前修改 BeanFactory 的配置元数据。
  • BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor的子接口,它可以在Bean 定义加载完成后,但在 Bean 实例化之前执行,允许添加、删除或修改 Bean 定义。

6. registerBeanPostProcessors(beanFactory)

- 注册 BeanPostProcessor:

  • 注册所有实现了 BeanPostProcessor 接口的 Bean。
    • 先注册实现了 PriorityOrdered 接口的。
    • 再注册实现了 Ordered 接口的。
    • 最后注册普通的 BeanPostProcessor
    • 重新注册内部的 BeanPostProcessor (MergedBeanDefinitionPostProcessor).
  • BeanPostProcessor 可以在 Bean 初始化前后进行处理。

7. initMessageSource()

- 初始化 MessageSource:

  • 初始化国际化消息源 (MessageSource)。
  • 如果在 BeanFactory 中找到名为 messageSource 的 Bean,则使用该 Bean;否则,创建一个默认的 DelegatingMessageSource

8. initApplicationEventMulticaster() - 初始化事件广播器:

  • 初始化应用事件广播器 (ApplicationEventMulticaster)。
  • 如果在 BeanFactory 中找到名为 applicationEventMulticaster 的 Bean,则使用该 Bean;否则,创建一个默认的 SimpleApplicationEventMulticaster

9. onRefresh()

- 刷新 (可选):

  • 这是一个模板方法,由具体的 ApplicationContext 实现类提供具体实现。
  • 例如,AbstractRefreshableWebApplicationContext 会在这里创建或刷新 Servlet 上下文。

10. registerListeners()

- 注册监听器:

  • 将之前收集的早期应用事件监听器 (early application listeners) 和在容器中定义的监听器注册到事件广播器 (ApplicationEventMulticaster)。
  • 发布早期的应用事件 (early application events).

11. finishBeanFactoryInitialization(beanFactory)

- 完成 BeanFactory 初始化:

  • 初始化类型转换器 (ConversionService),如果存在名为 conversionService 的 Bean。
  • 冻结配置(不允许再修改 Bean 定义)。
  • 实例化所有剩余的非懒加载的单例 Bean (调用 beanFactory.preInstantiateSingletons())。

12. finishRefresh()

- 完成刷新:

  • 清空资源缓存 (例如,ResourceBundleMessageSource 的缓存)。
  • 初始化生命周期处理器 (LifecycleProcessor),如果存在名为 lifecycleProcessor 的 Bean。
  • 调用 LifecycleProcessoronRefresh() 方法。
  • 发布 ContextRefreshedEvent 事件,通知所有监听器容器已刷新。
  • 注册 LiveBeansView MBean (如果启用).

13. 异常处理和重置

  • 如果在 refresh() 过程中发生异常, 则销毁已经创建的单例 Bean.
  • 重置容器的激活状态.

总结流程图:

+-----------------------+
|   start()             |
+-----------------------+
        |
        V
+-----------------------+
|   refresh()           |
+-----------------------+
        |
        V
+-----------------------+
|   prepareRefresh()    |  (准备刷新)
+-----------------------+
        |
        V
+-----------------------+
| obtainFreshBeanFactory()| (获取 BeanFactory, 加载 Bean 定义)
+-----------------------+
        |
        V
+-----------------------+
| prepareBeanFactory()  |  (准备 BeanFactory)
+-----------------------+
        |
        V
+-----------------------+
|postProcessBeanFactory()| (BeanFactory 后置处理, 可选)
+-----------------------+
        |
        V
+-----------------------+
|invokeBeanFactoryPPs()| (调用 BeanFactoryPostProcessor)
+-----------------------+
        |
        V
+-----------------------+
|registerBeanPostPrcs()| (注册 BeanPostProcessor)
+-----------------------+
        |
        V
+-----------------------+
| initMessageSource()   |  (初始化 MessageSource)
+-----------------------+
        |
        V
+-----------------------+
|initApplicationEventM()| (初始化事件广播器)
+-----------------------+
        |
        V
+-----------------------+
|   onRefresh()         |  (刷新, 可选)
+-----------------------+
        |
        V
+-----------------------+
| registerListeners()   |  (注册监听器)
+-----------------------+
        |
        V
+-----------------------+
|finishBeanFactoryInit()| (完成 BeanFactory 初始化, 实例化单例 Bean)
+-----------------------+
        |
        V
+-----------------------+
|  finishRefresh()      |  (完成刷新, 发布 ContextRefreshedEvent)
+-----------------------+
        |
        V
+-----------------------+
|     容器就绪           |
+-----------------------+

关键点:

  • refresh() 方法是 ApplicationContext 启动的核心。
  • BeanFactory 是实际创建和管理 Bean 的组件。
  • BeanDefinition 描述了如何创建和配置 Bean。
  • BeanFactoryPostProcessor 可以在 Bean 实例化之前修改 BeanFactory 的配置元数据。
  • BeanPostProcessor 可以在 Bean 初始化前后进行处理。
  • ApplicationListener 可以监听容器发布的事件。
  • Spring Boot 在 Spring Framework 的基础上,进一步简化了 ApplicationContext 的创建和配置,但其核心启动流程仍然遵循上述步骤。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 自制Java工具实现翻译鼠标选中文本

    自制Java工具实现翻译鼠标选中文本

    这篇文章主要为大家详细介绍了如何自制Java工具实现ctrl+c+c翻译鼠标选中文本,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
    2024-01-01
  • MPAndroidChart开源图表库的使用介绍之饼状图、折线图和柱状图

    MPAndroidChart开源图表库的使用介绍之饼状图、折线图和柱状图

    这篇文章主要介绍了MPAndroidChart开源图表库的使用介绍之饼状图、折线图和柱状图的相关资料,需要的朋友可以参考下
    2016-02-02
  • java+jdbc+mysql+socket搭建局域网聊天室

    java+jdbc+mysql+socket搭建局域网聊天室

    这篇文章主要为大家详细介绍了java+jdbc+mysql+socket搭建局域网聊天室,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-01-01
  • 通过RedisTemplate连接多个Redis过程解析

    通过RedisTemplate连接多个Redis过程解析

    这篇文章主要介绍了通过RedisTemplate连接多个Redis过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-08-08
  • SpringMVC请求乱码处理的2种方式

    SpringMVC请求乱码处理的2种方式

    这篇文章主要介绍了SpringMVC请求乱码处理的2种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • Spring Cloud Gateway使用Token验证详解

    Spring Cloud Gateway使用Token验证详解

    这篇文章主要介绍了Spring Cloud Gateway使用Token验证详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-02-02
  • 基于java 线程的几种状态(详解)

    基于java 线程的几种状态(详解)

    下面小编就为大家带来一篇基于java 线程的几种状态(详解)。小编觉得挺不错的,现在就想给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • idea鼠标控制放大缩小的操作

    idea鼠标控制放大缩小的操作

    这篇文章主要介绍了idea鼠标控制放大缩小的操作教程,具有很好的参考价值,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • 解析Tars-Java客户端源码

    解析Tars-Java客户端源码

    Tars是基于名字服务使用Tars协议的高性能RPC开发框架,同时配套一体化的服务治理平台,帮助个人或者企业快速的以微服务的方式构建自己稳定可靠的分布式应用
    2021-06-06
  • Java实现随机验证码功能实例代码

    Java实现随机验证码功能实例代码

    在这里,我们使用servlet来实现随机验证码的实现,有需要的朋友可以参考一下
    2013-08-08

最新评论