SpringBoot启动流程核心步骤

wen java案例 2

SpringBoot启动流程核心步骤:从入口到容器的完整解析

目录导读

  • SpringBoot启动的入口与核心类

    SpringBoot启动流程核心步骤

  • 启动流程第一阶段:初始化SpringApplication

  • 启动流程第二阶段:运行SpringApplication

  • 核心步骤详解:环境准备、上下文创建、自动配置

  • 常见问题与面试问答

  • 性能优化与调试建议


SpringBoot启动的入口与核心类

SpringBoot应用的启动始于一个简单的main方法,通常如下:

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

这里最核心的类是SpringApplication,它负责整个启动流程的编排,而@SpringBootApplication是一个组合注解,等效于@EnableAutoConfiguration + @ComponentScan + @SpringBootConfiguration

问:@SpringBootApplication必须放在启动类上吗?
答:是的,它标记了配置类的位置,SpringBoot会基于该包路径进行组件扫描和自动配置。


启动流程第一阶段:初始化SpringApplication

当调用SpringApplication.run()时,首先会创建一个SpringApplication实例,初始化过程包括:

  1. 推断应用类型:通过类路径是否存在DispatcherServletReactive相关类,判断是Servlet(传统Web)还是Reactive(响应式)应用。
  2. 设置BootstrapRegistryInitializer:从spring.factories中加载所有BootstrapRegistryInitializer实现,用于早期初始化。
  3. 设置ApplicationContextInitializer:同样从spring.factories加载,这些初始化器会在容器刷新前对上下文进行定制。
  4. 设置ApplicationListener:加载所有事件监听器,用于监听启动过程中的事件(如ApplicationStartedEventApplicationReadyEvent)。
  5. 推断主启动类:通过堆栈信息找到调用run方法的类,并记录为主配置类。

问:为什么需要推断应用类型?
答:因为不同Web类型需要不同的ApplicationContext实现(如AnnotationConfigServletWebServerApplicationContext vs AnnotationConfigReactiveWebServerApplicationContext),这一步决定了后续容器的选择。


启动流程第二阶段:运行SpringApplication

初始化完成后,执行run(String... args)方法,这是启动的核心阶段,主要步骤如下:

1 启动计时器

记录启动开始时间,用于后续打印启动耗时。

2 创建并配置ApplicationArguments

封装命令行参数,提供便捷的访问方式。

3 配置当前环境

  • 如果有配置spring.profiles.active,则激活对应的Profile。
  • spring.factories加载EnvironmentPostProcessor,对Environment进行后置处理(如加载随机数源、属性源)。

4 打印Banner

默认打印SpringBoot的ASCII艺术字Logo,可通过spring.banner.location自定义。

5 创建ApplicationContext

根据之前推断的应用类型,创建相应的ApplicationContext实例,对于Servlet应用,创建AnnotationConfigServletWebServerApplicationContext

6 准备上下文(prepareContext

这是最复杂的步骤之一,具体包括:

  • 设置环境:将前面创建的Environment绑定到上下文中。
  • 应用初始化器:执行之前加载的ApplicationContextInitializer
  • 注册启动参数:将ApplicationArguments作为Bean注册到容器中。
  • 加载Bean定义:扫描主配置类(即Application.class),将其作为配置类加载。
  • 处理事件:发送ApplicationPreparedEvent事件。

7 刷新上下文(refreshContext

调用AbstractApplicationContext.refresh(),这是Spring容器的核心启动过程,内含:

  • prepareRefresh():刷新前的准备工作。
  • obtainFreshBeanFactory():创建或刷新BeanFactory。
  • prepareBeanFactory():配置BeanFactory的标准特性。
  • postProcessBeanFactory():后处理器扩展点。
  • invokeBeanFactoryPostProcessors():执行BeanFactoryPostProcessor(包括自动配置的核心ConfigurationClassPostProcessor)。
  • registerBeanPostProcessors():注册Bean后处理器。
  • initMessageSource():初始化国际化资源。
  • initApplicationEventMulticaster():初始化事件广播器。
  • onRefresh():启动内嵌Web容器(如Tomcat、Jetty)。
  • registerListeners():注册监听器。
  • finishBeanFactoryInitialization():实例化所有非懒加载的单例Bean。
  • finishRefresh():完成刷新,发出ContextRefreshedEvent

8 启动后处理

afterRefresh():空方法,留给子类扩展。

9 发送启动完成事件

  • ApplicationStartedEvent:在上下文刷新后、但未调用CommandLineRunnerApplicationRunner之前发出。
  • ApplicationReadyEvent:在所有Runner执行完成后发出,表示应用已就绪。

10 返回ConfigurableApplicationContext

最终返回已准备好的上下文对象,用户可通过它获取Bean。

问:refreshContext过程中,内嵌Tomcat是在哪一步启动的?
答:在onRefresh()阶段。ServletWebServerApplicationContext会创建并启动内嵌Web服务器(如Tomcat),并绑定到指定端口。


核心步骤详解:环境准备、上下文创建、自动配置

1 环境准备

Environment对象持有应用运行时所需的所有配置属性(如application.properties、系统环境变量、命令行参数),多个PropertySource按优先级排序,相同的key会覆盖。

2 自动配置原理

自动配置的核心是@EnableAutoConfiguration,它通过AutoConfigurationImportSelector加载spring.factories中所有org.springframework.boot.autoconfigure.EnableAutoConfiguration配置项,这些配置类中通常包含@ConditionalOnClass@ConditionalOnMissingBean等条件注解,确保仅在满足条件时生效。

问:为什么自动配置类通常在Jar包中而不在项目里?
答:这是SpringBoot的“约定优于配置”设计,Jar包中的自动配置类通过SPI机制加载,用户只需引入依赖(如spring-boot-starter-web),自动配置类便会按条件生效。


常见问题与面试问答

Q1:SpringBoot启动流程中,哪些步骤可以干预?
A:多个扩展点:

  • ApplicationContextInitializer:在容器刷新前修改上下文。
  • ApplicationRunner / CommandLineRunner:应用启动后执行自定义逻辑。
  • EnvironmentPostProcessor:修改Environment属性源。
  • SpringApplicationRunListener:监听启动各个阶段。

Q2:如果启动时找不到数据库连接会如何?
A:如果配置了spring.datasource.initialization-mode且数据库不可达,容器刷新时会抛出BeanCreationException,导致启动失败,可以通过@SpringBootApplication(exclude=DataSourceAutoConfiguration.class)排除自动配置。

Q3:启动流程中Bean的实例化顺序是怎样的?
A:先实例化BeanFactoryPostProcessor相关Bean,然后是BeanPostProcessor,最后是普通Bean,同类型Bean按@Order注解或Ordered接口排序。@DependsOn可以显式指定依赖顺序。


性能优化与调试建议

  • 显示启动耗时详情:在application.properties中设置spring.autoconfigure.exclude可以排除不必要的自动配置类,减少加载时间。
  • 使用spring-boot-starter-actuator:通过/actuator/health端点查看应用状态,/actuator/beans查看Bean列表。
  • 启用懒加载spring.main.lazy-initialization=true可延迟Bean初始化,提升启动速度(适用于非生产环境)。
  • 诊断启动慢:添加--debug参数,SpringBoot会输出自动配置报告和条件匹配日志,帮助定位耗时环节。

SpringBoot启动流程从@SpringBootApplication注解开始,经过初始化、环境构建、上下文刷新、自动配置加载、内嵌服务器启动,最终完成应用就绪,理解每一个步骤及其扩展点,不仅能帮助我们快速定位启动问题,还能对Spring框架的控制反转和依赖注入有更深层的认识,在实际开发中,合理利用各阶段的自定义能力,可以构建出更灵活、更健壮的应用。


参考来源:本研究综合了SpringBoot官方文档、开源社区源码分析文章及多个技术博客的精华内容,结合最新版本(2.7.x/3.x)的代码结构进行提炼与整合。

抱歉,评论功能暂时关闭!