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

Spring 启动流程详解

sequenceDiagram participant U as 用户 participant AC as AnnotationConfigApplicationContext participant BF as BeanFactory participant BFP as BeanFactoryPostProcessor participant BPP as BeanPostProcessor 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 note right of BF: 加载BeanDefinition AC->>BF: prepareBeanFactory() note right of BF: 配置类加载器、添加处理器 AC->>BFP: invokeBeanFactoryPostProcessors() BFP-->>BF: 修改BeanDefinition note right of BFP: 处理@Configuration等 AC->>BPP: registerBeanPostProcessors() BPP-->>AC: 注册完成 note right of BPP: 支持AOP、依赖注入 AC->>AC: initMessageSource() AC->>AC: initApplicationEventMulticaster() AC->>BF: finishBeanFactoryInitialization() BF->>BEAN: preInstantiateSingletons() BEAN-->>BF: 创建单例Bean(实例化、注入、初始化) note right of BEAN: AOP代理生成 AC->>AC: finishRefresh() note right of AC: 发布ContextRefreshedEvent U-->>AC: 容器启动完成

在面试中,经常会被问到 Spring 的启动流程,这不仅考察你对 Spring 框架的理解深度,也反映了你对框架底层机制的掌握程度。本文将详细介绍 Spring 容器的启动流程(以 AnnotationConfigApplicationContext 为例),并分析每个步骤的核心作用。

Spring 启动流程概述

Spring 的启动流程主要围绕 ApplicationContext 的创建和初始化展开。无论是基于 XML 配置还是注解配置,其核心逻辑都集中在 AbstractApplicationContextrefresh() 方法中。以下是启动流程的详细步骤:

1. 容器初始化:创建 ApplicationContext

启动 Spring 应用的第一步是实例化一个 ApplicationContext。以注解配置为例,我们通常会使用 AnnotationConfigApplicationContext

java 复制代码
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
  • 作用 :这一步会加载配置类(例如 AppConfig),并初始化 Spring 容器的基本结构。
  • 细节 :构造方法会调用 this() 初始化 BeanFactory(默认是 DefaultListableBeanFactory),并注册配置类本身作为一个 Bean。

2. 准备刷新:prepareRefresh()

调用 refresh() 方法是 Spring 启动的核心入口,在此之前会执行一些准备工作:

  • 初始化属性源:加载环境变量、系统属性等。
  • 验证必要属性:检查是否有必须的配置项缺失。
  • 准备监听器:初始化事件监听器,为后续事件发布做准备。

3. 创建并配置 BeanFactory:obtainFreshBeanFactory()

这一步会创建一个全新的 BeanFactory,并加载 Bean 定义:

  • 加载配置 :如果是注解配置,会扫描 @ComponentScan 指定的包路径,解析 @Component@Service 等注解,生成 BeanDefinition
  • 注册 Bean 定义 :将扫描到的 Bean 定义注册到 BeanFactory 中。
  • 分析BeanFactory 是 Spring 的核心组件,负责管理 Bean 的生命周期。此时尚未创建 Bean 实例,只是注册了元信息。

4. 准备 BeanFactory:prepareBeanFactory()

BeanFactory 进行进一步配置,使其具备完整功能:

  • 添加 BeanPostProcessor :例如 ApplicationContextAwareProcessor,用于支持 Aware 接口。
  • 设置类加载器:配置默认的类加载器,通常是当前线程的上下文类加载器。
  • 忽略某些接口 :如 Aware 接口,避免被自动注入。

5. 执行 BeanFactory 后处理器:invokeBeanFactoryPostProcessors()

这一步会调用所有 BeanFactoryPostProcessor,对 BeanDefinition 进行修改:

  • 典型例子ConfigurationClassPostProcessor 会解析 @Configuration 类,处理 @Bean 方法,生成额外的 BeanDefinition
  • 分析:这是 Spring 支持注解配置的关键步骤,允许动态调整 Bean 定义。

6. 注册 BeanPostProcessor:registerBeanPostProcessors()

将所有 BeanPostProcessor 注册到容器中,准备在 Bean 创建时介入:

  • 作用:支持 AOP、依赖注入等功能的实现。
  • 顺序 :根据 PriorityOrderedOrdered 接口排序执行。

7. 初始化消息源和事件多播器

  • 消息源 :初始化 MessageSource,支持国际化。
  • 事件多播器 :初始化 ApplicationEventMulticaster,用于事件发布和监听。

8. 初始化其他特殊 Bean:onRefresh()

子类可以重写此方法,执行特定初始化逻辑。例如,Spring Boot 在此初始化嵌入式 Web 容器。

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

将所有 ApplicationListener 注册到事件多播器中,确保事件机制正常工作。

10. 实例化所有单例 Bean:finishBeanFactoryInitialization()

这一步是 Bean 创建的高潮:

  • 预实例化单例 :调用 beanFactory.preInstantiateSingletons(),触发所有非懒加载单例 Bean 的创建。
  • 生命周期
    1. 实例化:通过构造方法创建对象。
    2. 属性填充:执行依赖注入。
    3. 初始化 :调用 InitializingBean.afterPropertiesSet()@PostConstruct 方法。
    4. AOP 代理:如果需要,生成代理对象。
  • 分析:这是 Spring 依赖注入和 AOP 的核心实现阶段。

11. 完成刷新:finishRefresh()

  • 发布事件 :发布 ContextRefreshedEvent,通知容器已就绪。
  • 初始化 Lifecycle Bean :调用实现了 Lifecycle 接口的 Bean 的 start() 方法。

12. 关闭钩子注册(可选)

如果是通过 ConfigurableApplicationContext 创建,会注册 JVM 关闭钩子,确保容器优雅关闭。

流程图示

以下是简化的流程图,便于理解:

scss 复制代码
初始化 ApplicationContext
       ↓
prepareRefresh()
       ↓
obtainFreshBeanFactory()
       ↓
prepareBeanFactory()
       ↓
invokeBeanFactoryPostProcessors()
       ↓
registerBeanPostProcessors()
       ↓
finishBeanFactoryInitialization()
       ↓
finishRefresh()

关键点分析

  1. BeanFactory vs ApplicationContext
    • BeanFactory 是基础容器,负责 Bean 的创建和管理。
    • ApplicationContext 是高级容器,增加了事件机制、国际化等功能。
  2. 依赖注入的实现
    • finishBeanFactoryInitialization() 中通过 getBean() 递归解决依赖。
  3. AOP 的实现
    • 通过 BeanPostProcessor(如 AbstractAutoProxyCreator)在 Bean 初始化后生成代理。
  4. 扩展点
    • BeanFactoryPostProcessorBeanPostProcessor 是开发者扩展 Spring 的主要途径。

常见面试问题

  • Q1:refresh() 方法的作用是什么?
    • 答:refresh() 是 Spring 容器启动的核心方法,负责初始化容器、加载 Bean 定义、创建 Bean 实例等全流程。
  • Q2:Bean 是如何被创建的?
    • 答:在 finishBeanFactoryInitialization() 中,通过 getBean() 方法触发实例化、依赖注入和初始化。
  • Q3:AOP 在哪个阶段生效?
    • 答:在 Bean 初始化后,由 BeanPostProcessor 实现代理对象的生成。

总结

Spring 的启动流程是一个精心设计的过程,从配置加载到 Bean 实例化,体现了其高度模块化和可扩展性。理解这一流程不仅能应对面试,还能帮助开发者更好地调试和优化 Spring 应用。希望这篇博客能为你提供清晰的思路!

相关推荐
Asthenia041210 分钟前
编译原理基础:FOLLOW 集合与 LL(1) 文法条件
后端
Asthenia041216 分钟前
编译原理基础:FIRST 集合与提取公共左因子
后端
欧宸雅1 小时前
Clojure语言的持续集成
开发语言·后端·golang
Bruce_Liuxiaowei1 小时前
基于Flask的DeepSeek~学术研究领域智能辅助系统设计与实现
后端·python·flask·deepseek
Asthenia04121 小时前
面试官问:你谈谈网络协议栈是什么?你觉得Java工程师需要了解哪些部分?
后端
穿林鸟2 小时前
Spring Boot项目信创国产化适配指南
java·spring boot·后端
褚翾澜2 小时前
Haskell语言的NoSQL
开发语言·后端·golang
伏游2 小时前
【BUG】生产环境死锁问题定位排查解决全过程
服务器·数据库·spring boot·后端·postgresql·bug
hycccccch3 小时前
Springcache+xxljob实现定时刷新缓存
java·后端·spring·缓存