Spring 启动流程分析-含时序图

891 阅读4分钟

Spring 启动流程详解与时序图

在面试中,Spring 的启动流程是一个高频问题。本文将通过时序图和详细分析,带你深入理解 Spring 容器(以 AnnotationConfigApplicationContext 为例)的启动过程,并解答一些常见疑惑。

时序图

以下是 Spring 启动流程的时序图(使用 Mermaid 语法,可在 Mermaid Live Editor 中渲染):

sequenceDiagram
    participant U as 用户
    participant AC as AnnotationConfigApplicationContext
    participant BF as DefaultListableBeanFactory
    participant BFP as BeanFactoryPostProcessor
    participant BPP as BeanPostProcessor
    participant EM as ApplicationEventMulticaster
    participant EL as ApplicationListener
    participant BEAN as Bean实例

    U->>AC: new AnnotationConfigApplicationContext(AppConfig)
    AC->>AC: refresh()
    AC->>AC: prepareRefresh()
    note right of AC: 初始化环境、属性源、验证属性

    AC->>BF: obtainFreshBeanFactory()
    BF-->>AC: 返回BeanFactory(含BeanDefinition)
    note right of BF: 扫描@Component、注册Bean定义

    AC->>BF: prepareBeanFactory()
    note right of BF: 配置类加载器、添加Aware处理器、忽略接口

    AC->>BFP: invokeBeanFactoryPostProcessors()
    BFP-->>BF: 修改BeanDefinition(如@Configuration)
    note right of BFP: 动态调整Bean定义

    AC->>BPP: registerBeanPostProcessors()
    BPP-->>AC: 注册完成(按@Order排序)
    note right of BPP: 支持AOP、依赖注入

    AC->>AC: initMessageSource()
    AC->>EM: initApplicationEventMulticaster()
    EM-->>AC: 返回事件多播器

    AC->>AC: onRefresh()
    note right of AC: 子类扩展(如Spring Boot启动Web容器)

    AC->>EM: registerListeners()
    EM->>EL: 添加ApplicationListener
    note right of EL: 监听ContextRefreshedEvent等

    AC->>BF: finishBeanFactoryInitialization()
    BF->>BEAN: preInstantiateSingletons()
    BEAN-->>BF: 实例化、依赖注入、初始化(三级缓存、Aware、AOP)
    note right of BEAN: 处理循环依赖、@PostConstruct

    AC->>EM: finishRefresh()
    EM->>EL: publishEvent(ContextRefreshedEvent)
    note right of EM: 通知容器就绪

    U-->>AC: 容器启动完成

Spring 启动流程详解

1. 容器初始化:创建 ApplicationContext

用户通过 new AnnotationConfigApplicationContext(AppConfig.class) 创建容器,触发启动流程。

2. 为什么要 refresh()?它的深意是什么?

  • 调用refresh()AbstractApplicationContext 的核心方法,启动容器的入口。
  • 深意
    • Spring 设计之初,BeanFactory 是一个轻量级容器,只负责 Bean 的创建和管理。但 ApplicationContext 作为高级容器,增加了事件机制、国际化等功能。
    • refresh() 的作用是“刷新”容器状态,将所有组件(Bean 定义、处理器、事件系统等)初始化并整合为一个完整的运行时环境。
    • 它是一个“一次性启动”的过程,确保容器从无到有,状态一致,避免手动调用多个方法带来的复杂性。
  • 类比:就像电脑开机,refresh() 是按下电源键后系统自检和加载的全过程。

3. 创建并配置 BeanFactory

  • obtainFreshBeanFactory()
    • 创建 DefaultListableBeanFactory,扫描 @ComponentScan 路径,注册 BeanDefinition
  • prepareBeanFactory()
    • 配置类加载器、添加 BeanPostProcessor(如 ApplicationContextAwareProcessor)。
    • 忽略接口的疑惑
      • Spring 会忽略 Aware 接口(如 BeanNameAwareBeanFactoryAwareApplicationContextAware)的自动注入。
      • 原因:这些接口不是通过 @Autowired 注入,而是由特定的 BeanPostProcessor 在 Bean 初始化时手动设置。例如,ApplicationContextAwareProcessor 会调用 setApplicationContext()
      • 深意:避免开发者误用自动注入导致混乱,同时保持 Aware 机制的控制权在框架手中。

4. BeanFactoryPostProcessor

  • 调用 invokeBeanFactoryPostProcessors(),如 ConfigurationClassPostProcessor,解析 @Configuration@Bean,动态调整 BeanDefinition

5. BeanPostProcessor 是什么?

  • 调用registerBeanPostProcessors() 注册所有 BeanPostProcessor
  • 定义BeanPostProcessor 是一个接口,允许在 Bean 实例化后、初始化前后介入,执行自定义逻辑。
  • 例子
    • AOP:AbstractAutoProxyCreator 在初始化后生成代理对象。
    • Aware:设置 BeanNameAware 的值。
  • @Order 的作用:多个 BeanPostProcessor 可通过 @OrderOrdered 接口排序,确保执行顺序。例如,AOP 代理需要在属性填充后执行。
  • 与 BFP 的区别BeanFactoryPostProcessor 修改 BeanDefinition,而 BeanPostProcessor 操作已创建的 Bean 实例。

6. onRefresh() 的作用

  • 调用onRefresh()refresh() 中的一个钩子方法。
  • 作用:提供给子类扩展,例如 Spring Boot 在此启动嵌入式 Web 容器(如 Tomcat)。
  • 与 refresh() 的区别
    • refresh() 是整个启动流程的总控方法,onRefresh() 是其中的一个步骤。
    • 它不是“重新刷新”,而是“特定场景下的初始化”,名称上容易误解。
  • 深意:体现了 Spring 的可扩展性,允许子类在标准流程中插入自定义逻辑。

7. 注册事件监听器:registerListeners()

  • 调用:将 ApplicationListener 注册到 ApplicationEventMulticaster
  • 事件是什么?
    • Spring 的事件基于观察者模式,ApplicationEvent 是事件实体,ApplicationListener 是监听器。
    • 例子:ContextRefreshedEvent 表示容器刷新完成。
  • 如何理解
    • 类比于“消息队列”,事件发布后,监听器异步处理。
    • 代码实体:ApplicationEventMulticaster#multicastEvent() 负责分发。
  • 作用:解耦业务逻辑,例如容器启动后通知某些组件执行初始化。

8. 实例化单例 Bean:finishBeanFactoryInitialization()

  • 调用beanFactory.preInstantiateSingletons()
  • 详细过程
    1. 实例化:通过构造方法创建对象。
    2. 三级缓存解决循环依赖
      • 一级缓存:单例池,存完全初始化的 Bean。
      • 二级缓存:早期暴露的对象(未初始化)。
      • 三级缓存:工厂对象,用于生成代理(如 AOP)。
      • 流程:A 依赖 B,B 未完成时,A 从二级缓存获取 B 的早期引用。
    3. 属性填充:执行依赖注入。
    4. 初始化
      • 调用 Aware 接口方法(如 setBeanName)。
      • 执行 @PostConstruct(通过 CommonAnnotationBeanPostProcessor)。
      • 调用 init-methodInitializingBean.afterPropertiesSet()
    5. AOP 代理:由 BeanPostProcessor 生成代理对象。
  • 分析:这是 Spring 核心功能(DI 和 AOP)的实现阶段。

9. 完成刷新:finishRefresh()

  • 调用:发布 ContextRefreshedEvent
  • ContextRefreshedEvent 是什么?
    • 一个具体的事件类,继承自 ApplicationEvent,表示容器已就绪。
    • 代码实体new ContextRefreshedEvent(this),由 ApplicationEventMulticaster 分发。
  • 作用:通知监听器容器启动完成,可能触发后续逻辑。

总结

Spring 的 refresh() 流程是一个从无到有的构建过程,通过 BeanFactoryBeanPostProcessor 和事件机制,实现了高度灵活的容器管理。理解这些细节,不仅能应对面试,还能帮助你更好地使用和扩展 Spring。