乐闻世界logo
搜索文章和话题

Spring Boot 的启动流程是怎样的?

3月7日 12:04

Spring Boot 启动流程详解

入口方法

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

启动流程总览

shell
SpringApplication.run() ├── 1. 创建 SpringApplication 实例 │ ├── 推断应用类型 (Servlet/Reactive/None) │ ├── 加载 BootstrapRegistryInitializer │ ├── 加载 ApplicationContextInitializer │ └── 加载 ApplicationListener └── 2. 执行 run() 方法 ├── 2.1 启动计时器 ├── 2.2 创建 DefaultBootstrapContext ├── 2.3 配置 headless 模式 ├── 2.4 发布 Starting 事件 ├── 2.5 准备 Environment ├── 2.6 打印 Banner ├── 2.7 创建 ApplicationContext ├── 2.8 准备 ApplicationContext ├── 2.9 刷新 ApplicationContext ├── 2.10 执行 Runner └── 2.11 发布 Started 事件

详细启动步骤

第一步:创建 SpringApplication 实例

java
public SpringApplication(Class<?>... primarySources) { // 资源加载器 this.resourceLoader = null; // 主配置类 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); // 推断应用类型 this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 加载 BootstrapRegistryInitializer this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories(); // 加载 ApplicationContextInitializer setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 加载 ApplicationListener setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 推断主类 this.mainApplicationClass = deduceMainApplicationClass(); }

应用类型推断逻辑:

java
static WebApplicationType deduceFromClasspath() { // 存在 reactor.netty.http.server.HttpServer 且不存在 // org.springframework.web.servlet.DispatcherServlet if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null) && !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) { return WebApplicationType.REACTIVE; } // 存在 javax.servlet.Servlet 或 jakarta.servlet.Servlet for (String className : SERVLET_INDICATOR_CLASSES) { if (ClassUtils.isPresent(className, null)) { return WebApplicationType.SERVLET; } } return WebApplicationType.NONE; }

第二步:执行 run() 方法核心流程

java
public ConfigurableApplicationContext run(String... args) { // 1. 启动计时器 StartupStep startupStep = this.applicationStartup.start("spring.boot.application.starting"); // 2. 创建 BootstrapContext DefaultBootstrapContext bootstrapContext = createBootstrapContext(); // 3. 配置 headless 模式 configureHeadlessProperty(); // 4. 获取 SpringApplicationRunListeners SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(bootstrapContext, this.mainApplicationClass); try { // 5. 准备 ApplicationArguments ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 6. 准备 Environment ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); configureIgnoreBeanInfo(environment); // 7. 打印 Banner Banner printedBanner = printBanner(environment); // 8. 创建 ApplicationContext context = createApplicationContext(); context.setApplicationStartup(this.applicationStartup); // 9. 准备 ApplicationContext prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); // 10. 刷新 ApplicationContext(核心) refreshContext(context); // 11. 刷新后处理 afterRefresh(context, applicationArguments); // 12. 启动完成 listeners.started(context); // 13. 执行 Runner callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, null); throw new IllegalStateException(ex); } return context; }

第三步:准备 Environment

java
private ConfigurableEnvironment prepareEnvironment( SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) { // 创建或获取 Environment ConfigurableEnvironment environment = getOrCreateEnvironment(); // 配置 PropertySources 和 Profiles configureEnvironment(environment, applicationArguments.getSourceArgs()); // 发布 EnvironmentPrepared 事件 listeners.environmentPrepared(bootstrapContext, environment); // 绑定到 SpringApplication ConfigurationPropertySources.attach(environment); return environment; }

配置文件加载顺序(优先级从高到低):

  1. 命令行参数
  2. java:comp/env 的 JNDI 属性
  3. Java 系统属性(System.getProperties())
  4. 操作系统环境变量
  5. RandomValuePropertySource
  6. jar 包外部的 application-{profile}.properties
  7. jar 包内部的 application-{profile}.properties
  8. jar 包外部的 application.properties
  9. jar 包内部的 application.properties
  10. @PropertySource 注解定义的属性
  11. 默认属性(SpringApplication.setDefaultProperties)

第四步:创建 ApplicationContext

java
protected ConfigurableApplicationContext createApplicationContext() { return this.applicationContextFactory.apply(this.webApplicationType); } // 根据应用类型创建不同的上下文 // Servlet -> AnnotationConfigServletWebServerApplicationContext // Reactive -> AnnotationConfigReactiveWebServerApplicationContext // None -> AnnotationConfigApplicationContext

第五步:准备 ApplicationContext

java
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { // 设置 Environment context.setEnvironment(environment); // 应用后处理器 postProcessApplicationContext(context); // 执行 ApplicationContextInitializer applyInitializers(context); // 发布 ContextPrepared 事件 listeners.contextPrepared(context); // 注册 Spring Boot 特殊 Bean ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { beanFactory.registerSingleton("springBootBanner", printedBanner); } // 加载主配置类 Set<Object> sources = getAllSources(); load(context, sources.toArray(new Object[0])); // 发布 ContextLoaded 事件 listeners.contextLoaded(context); }

第六步:刷新 ApplicationContext(核心)

java
private void refreshContext(ConfigurableApplicationContext context) { refresh(context); // 注册 ShutdownHook if (this.registerShutdownHook) { shutdownHook.registerApplicationContext(context); } } // 调用 AbstractApplicationContext.refresh() @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 1. 准备刷新 prepareRefresh(); // 2. 获取 BeanFactory ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 3. 准备 BeanFactory prepareBeanFactory(beanFactory); try { // 4. 子类扩展 postProcessBeanFactory(beanFactory); // 5. 执行 BeanFactoryPostProcessor invokeBeanFactoryPostProcessors(beanFactory); // 6. 注册 BeanPostProcessor registerBeanPostProcessors(beanFactory); // 7. 初始化 MessageSource initMessageSource(); // 8. 初始化事件广播器 initApplicationEventMulticaster(); // 9. 子类扩展(WebServer 在此初始化) onRefresh(); // 10. 注册监听器 registerListeners(); // 11. 初始化所有非懒加载单例 Bean finishBeanFactoryInitialization(beanFactory); // 12. 完成刷新 finishRefresh(); } catch (BeansException ex) { destroyBeans(); closeBeanFactory(); throw ex; } } }

WebServer 启动时机:

java
// ServletWebServerApplicationContext.onRefresh() @Override protected void onRefresh() { super.onRefresh(); try { // 创建并启动 WebServer(Tomcat/Jetty/Undertow) createWebServer(); } catch (Throwable ex) { throw new ApplicationContextException("Unable to start web server", ex); } }

第七步:执行 Runner

java
private void callRunners(ApplicationContext context, ApplicationArguments args) { List<Object> runners = new ArrayList<>(); // 获取所有 ApplicationRunner runners.addAll(context.getBeansOfType(ApplicationRunner.class).values()); // 获取所有 CommandLineRunner runners.addAll(context.getBeansOfType(CommandLineRunner.class).values()); // 排序并执行 AnnotationAwareOrderComparator.sort(runners); for (Object runner : new LinkedHashSet<>(runners)) { if (runner instanceof ApplicationRunner) { callRunner((ApplicationRunner) runner, args); } if (runner instanceof CommandLineRunner) { callRunner((CommandLineRunner) runner, args); } } }

启动事件监听

java
// 可以通过实现 ApplicationListener 监听启动过程 @Component public class MyApplicationListener implements ApplicationListener<ApplicationStartedEvent> { @Override public void onApplicationEvent(ApplicationStartedEvent event) { System.out.println("Application started!"); } }

主要事件类型:

事件触发时机
ApplicationStartingEventrun 方法开始执行时
ApplicationEnvironmentPreparedEventEnvironment 准备完成时
ApplicationContextInitializedEventContext 初始化完成时
ApplicationPreparedEventContext 准备完成时
ApplicationStartedEventContext 刷新完成时
ApplicationReadyEvent所有 Runner 执行完成时
ApplicationFailedEvent启动失败时

总结

Spring Boot 启动流程可以概括为:

  1. 实例化阶段:推断应用类型,加载初始化器和监听器
  2. 环境准备阶段:准备 Environment,加载配置文件
  3. 上下文创建阶段:创建并配置 ApplicationContext
  4. 刷新阶段:加载 Bean 定义,初始化 Bean,启动 WebServer
  5. 启动完成阶段:执行 Runner,发布启动完成事件

理解启动流程有助于排查启动问题、自定义启动逻辑和优化启动性能。

标签:Spring Boot