跳到主要内容
版本:3.5.10

SpringApplication

QWen Max 中英对照 SpringApplication

SpringApplication 类提供了一种便捷的方式来引导一个从 main() 方法启动的 Spring 应用程序。在许多情况下,你可以委托给静态方法 SpringApplication.run(Class, String…​),如下例所示:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyApplication {

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

}

当你的应用程序启动时,你应该会看到类似如下的输出:

.   ____          _            __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/

:: Spring Boot :: (v3.5.10)

2026-01-22T10:18:06.401Z INFO 89020 --- [ main] o.s.b.d.f.logexample.MyApplication : Starting MyApplication using Java 17.0.18 with PID 89020 (/opt/apps/myapp.jar started by myuser in /opt/apps/)
2026-01-22T10:18:06.418Z INFO 89020 --- [ main] o.s.b.d.f.logexample.MyApplication : No active profile set, falling back to 1 default profile: "default"
2026-01-22T10:18:09.358Z INFO 89020 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http)
2026-01-22T10:18:09.405Z INFO 89020 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2026-01-22T10:18:09.410Z INFO 89020 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.50]
2026-01-22T10:18:09.572Z INFO 89020 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2026-01-22T10:18:09.581Z INFO 89020 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2987 ms
2026-01-22T10:18:11.116Z INFO 89020 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/'
2026-01-22T10:18:11.159Z INFO 89020 --- [ main] o.s.b.d.f.logexample.MyApplication : Started MyApplication in 6.313 seconds (process running for 7.217)
2026-01-22T10:18:11.186Z INFO 89020 --- [ionShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown : Commencing graceful shutdown. Waiting for active requests to complete
2026-01-22T10:18:11.214Z INFO 89020 --- [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown : Graceful shutdown complete

默认情况下,会显示 INFO 级别的日志消息,包括一些相关的启动详情,例如启动应用程序的用户。如果你需要不同于 INFO 的日志级别,可以按照 日志级别(Log Levels) 中所述进行设置。应用程序版本是通过主应用程序类所在包的实现版本(implementation version)确定的。可以通过将 spring.main.log-startup-info 设置为 false 来关闭启动信息的日志记录。这也会同时关闭应用程序激活的 profile 的日志记录。

提示

若要在启动期间添加额外的日志记录,可以在 SpringApplication 的子类中重写 logStartupInfo(boolean) 方法。

启动失败

如果你的应用程序启动失败,已注册的 FailureAnalyzer Bean 将有机会提供专门的错误消息和具体的修复操作。例如,如果你在端口 8080 上启动一个 Web 应用程序,而该端口已被占用,你应该会看到类似如下的消息:

***************************
APPLICATION FAILED TO START
***************************

Description:

Embedded servlet container failed to start. Port 8080 was already in use.

Action:

Identify and stop the process that is listening on port 8080 or configure this application to listen on another port.
备注

Spring Boot 提供了众多 FailureAnalyzer 实现,你也可以添加自己的实现

如果没有故障分析器(failure analyzers)能够处理该异常,你仍然可以显示完整的条件报告(conditions report),以更好地了解哪里出了问题。为此,你需要启用 debug 属性 或为 ConditionEvaluationReportLoggingListener 启用 DEBUG 日志

例如,如果你使用 java -jar 来运行你的应用程序,可以按如下方式启用 debug 属性:

$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug

延迟初始化

SpringApplication 允许应用程序以懒加载(lazy)方式初始化。启用懒加载后,Bean 将在其被需要时才创建,而不是在应用程序启动期间创建。因此,启用懒加载可以减少应用程序的启动时间。在 Web 应用程序中,启用懒加载将导致许多与 Web 相关的 Bean 直到接收到 HTTP 请求时才会被初始化。

懒加载的一个缺点是,它可能会延迟应用程序问题的发现。如果一个配置错误的 Bean 被懒加载,那么启动时将不再发生故障,只有在该 Bean 被初始化时问题才会显现出来。此外,还必须注意确保 JVM 拥有足够的内存来容纳应用程序的所有 Bean,而不仅仅是那些在启动期间初始化的 Bean。出于这些原因,默认情况下不会启用懒加载,并且建议在启用懒加载之前,先对 JVM 的堆大小进行精细调整。

可以通过编程方式使用 SpringApplicationBuilder 上的 lazyInitialization 方法,或 SpringApplication 上的 setLazyInitialization 方法来启用延迟初始化。或者,也可以通过 spring.main.lazy-initialization 属性来启用,如下例所示:

spring.main.lazy-initialization=true
提示

如果你想在对应用程序的其余部分使用懒初始化的同时,为某些 Bean 禁用懒初始化,可以使用 @Lazy(false) 注解显式地将其 lazy 属性设置为 false。

自定义 Banner

启动时打印的 banner 可以通过在 classpath 中添加一个 banner.txt 文件,或者通过设置 spring.banner.location 属性来指定该文件的位置进行更改。如果该文件的编码不是 UTF-8,你可以设置 spring.banner.charset

在你的 banner.txt 文件中,你可以使用 Environment 中提供的任意键,以及以下占位符:

表 1. Banner 变量

变量说明
${application.version}应用程序的版本号,声明在 MANIFEST.MF 中。例如,Implementation-Version: 1.0 将被打印为 1.0
${application.formatted-version}应用程序的版本号,声明在 MANIFEST.MF 中,并格式化用于显示(用括号包围,并以 v 为前缀)。例如 (v1.0)
${spring-boot.version}您正在使用的 Spring Boot 版本。例如 3.5.10
${spring-boot.formatted-version}您正在使用的 Spring Boot 版本,格式化用于显示(用括号包围,并以 v 为前缀)。例如 (v3.5.10)
${Ansi.NAME}(或 ${AnsiColor.NAME}${AnsiBackground.NAME}${AnsiStyle.NAME}其中 NAME 是 ANSI 转义码的名称。详情请参见 AnsiPropertySource
${application.title}应用程序的标题,声明在 MANIFEST.MF 中。例如,Implementation-Title: MyApp 将被打印为 MyApp
提示

如果你想以编程方式生成 banner,可以使用 SpringApplication.setBanner(…​) 方法。使用 Banner 接口并实现你自己的 printBanner() 方法。

你也可以使用 spring.main.banner-mode 属性来确定 banner 是否需要打印到 System.outconsole)、发送到配置的 logger(log),或者完全不生成(off)。

打印的 banner 以如下名称注册为一个单例 bean:springBootBanner

备注

application.titleapplication.versionapplication.formatted-version 属性仅在使用 java -jar 或配合 Spring Boot 启动器使用 java -cp 时可用。如果你运行的是未打包的 jar 文件,并通过 java -cp <classpath> <mainclass> 启动,或者将应用程序作为原生镜像(native image)运行,则这些值将无法解析。

要使用 application.* 属性,请将你的应用程序作为打包后的 jar 文件通过 java -jar 启动,或作为未打包的 jar 文件通过 java org.springframework.boot.loader.launch.JarLauncher 启动。这样会在构建 classpath 并启动应用程序之前初始化 application.* banner 属性。

自定义 SpringApplication

如果 SpringApplication 的默认设置不符合你的需求,你可以创建一个本地实例并对其进行自定义。例如,要关闭启动横幅(banner),你可以这样写:

import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyApplication {

public static void main(String[] args) {
SpringApplication application = new SpringApplication(MyApplication.class);
application.setBannerMode(Banner.Mode.OFF);
application.run(args);
}

}
备注

传递给 SpringApplication 的构造函数参数是 Spring bean 的配置源。在大多数情况下,这些参数是对 @Configuration 类的引用,但也可能是直接对 @Component 类的引用。

也可以通过使用 application.properties 文件来配置 SpringApplication。详见 Externalized Configuration

有关配置选项的完整列表,请参阅 SpringApplication API 文档。

Fluent Builder API

如果你需要构建一个 ApplicationContext 层次结构(具有父子关系的多个上下文),或者你更喜欢使用流式构建器 API,可以使用 SpringApplicationBuilder

SpringApplicationBuilder 允许你将多个方法调用链接在一起,并提供了 parentchild 方法,可用于创建层次结构,如下例所示:

new SpringApplicationBuilder().sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);
备注

在创建 ApplicationContext 层级结构时存在一些限制。例如,Web 组件必须包含在子上下文中,并且父上下文与子上下文使用相同的 Environment。完整详情请参见 SpringApplicationBuilder 的 API 文档。

应用可用性

在平台上部署时,应用程序可以使用诸如 Kubernetes Probes 之类的基础设施向平台提供其可用性信息。Spring Boot 内置支持常用的 “liveness”(存活)和 “readiness”(就绪)可用性状态。如果你使用了 Spring Boot 的 “actuator” 支持,那么这些状态会作为健康端点组(health endpoint groups)暴露出来。

此外,你还可以通过将 ApplicationAvailability 接口注入到你自己的 Bean 中来获取可用性状态。

Liveness 状态

应用程序的 “Liveness” 状态用于指示其内部状态是否允许其正常工作,或者在当前发生故障时能否自行恢复。如果 “Liveness” 状态异常,则意味着应用程序处于无法自行恢复的状态,此时基础设施应重启该应用程序。

备注

通常,“Liveness”状态不应基于外部检查,例如健康检查。否则,一旦外部系统(如数据库、Web API 或外部缓存)发生故障,将触发平台范围内的大规模重启和级联故障。

Spring Boot 应用程序的内部状态主要由 Spring ApplicationContext 表示。如果应用上下文已成功启动,Spring Boot 会认为应用程序处于有效状态。一旦上下文被刷新,应用程序即被视为处于活跃(live)状态,详见 Spring Boot 应用程序生命周期及相关 Application Events

就绪状态

应用程序的 “Readiness” 状态表示该应用程序是否已准备好处理流量。如果 “Readiness” 状态失败,则告知平台当前不应将流量路由到该应用程序。这种情况通常发生在启动期间,即正在处理 CommandLineRunnerApplicationRunner 组件时,或者在应用程序认为自身过于繁忙而无法处理额外流量的任何时候。

一旦应用程序和命令行运行器(command-line runners)被调用,应用程序即被视为已就绪,参见 Spring Boot 应用程序生命周期及相关 Application Events

提示

在启动期间预期运行的任务应由 CommandLineRunnerApplicationRunner 组件执行,而不是使用 Spring 组件的生命周期回调方法,例如 @PostConstruct

管理应用程序可用性状态

应用程序组件可以通过注入 ApplicationAvailability 接口并调用其方法,在任意时刻获取当前的可用性状态。更常见的情况是,应用程序希望监听状态更新,或更新应用程序自身的状态。

例如,我们可以将应用程序的 “Readiness” 状态导出到一个文件中,以便 Kubernetes 的 “exec Probe” 可以检查该文件:

import org.springframework.boot.availability.AvailabilityChangeEvent;
import org.springframework.boot.availability.ReadinessState;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class MyReadinessStateExporter {

@EventListener
public void onStateChange(AvailabilityChangeEvent<ReadinessState> event) {
switch (event.getState()) {
case ACCEPTING_TRAFFIC -> {
// create file /tmp/healthy
}
case REFUSING_TRAFFIC -> {
// remove file /tmp/healthy
}
}
}

}

当应用程序崩溃且无法恢复时,我们也可以更新应用程序的状态:

import org.springframework.boot.availability.AvailabilityChangeEvent;
import org.springframework.boot.availability.LivenessState;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

@Component
public class MyLocalCacheVerifier {

private final ApplicationEventPublisher eventPublisher;

public MyLocalCacheVerifier(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}

public void checkLocalCache() {
try {
// ...
}
catch (CacheCompletelyBrokenException ex) {
AvailabilityChangeEvent.publish(this.eventPublisher, ex, LivenessState.BROKEN);
}
}

}

Spring Boot 提供了 通过 Actuator Health Endpoints 实现的 Kubernetes HTTP “Liveness” 和 “Readiness” 探针。你可以在专门章节中获取更多关于在 Kubernetes 上部署 Spring Boot 应用程序的指导。

应用事件与监听器

除了常规的 Spring Framework 事件(例如 ContextRefreshedEvent)之外,SpringApplication 还会发送一些额外的应用程序事件。

备注

某些事件实际上是在 ApplicationContext 创建之前触发的,因此你无法将这些事件的监听器注册为 @Bean。你可以使用 SpringApplication.addListeners(…​) 方法或 SpringApplicationBuilder.listeners(…​) 方法来注册它们。

如果你希望这些监听器无论应用程序以何种方式创建都能自动注册,可以在项目中添加一个 META-INF/spring.factories 文件,并使用 ApplicationListener 键来引用你的监听器,如下例所示:

org.springframework.context.ApplicationListener=com.example.project.MyListener

应用程序事件按以下顺序发送,当你的应用程序运行时:

  1. 在运行开始时(但在任何处理之前,仅注册监听器和初始化器除外)会发送一个 ApplicationStartingEvent

  2. 当上下文将要使用的 Environment 已知、但上下文尚未创建时,会发送一个 ApplicationEnvironmentPreparedEvent

  3. ApplicationContext 已准备就绪且 ApplicationContextInitializers 已被调用、但在加载任何 Bean 定义之前,会发送一个 ApplicationContextInitializedEvent

  4. 在刷新操作即将开始、但 Bean 定义已加载之后,会发送一个 ApplicationPreparedEvent

  5. 在上下文刷新完成之后、但在调用任何 ApplicationRunner 和 CommandLineRunner 之前,会发送一个 ApplicationStartedEvent

  6. 紧接着会发送一个 AvailabilityChangeEvent,其状态为 LivenessState.CORRECT,以表明应用程序被视为存活。

  7. 在所有 ApplicationRunner 和 CommandLineRunner 被调用之后,会发送一个 ApplicationReadyEvent

  8. 紧接着会发送一个 AvailabilityChangeEvent,其状态为 ReadinessState.ACCEPTING_TRAFFIC,以表明应用程序已准备好处理请求。

  9. 如果启动过程中发生异常,则会发送一个 ApplicationFailedEvent

上述列表仅包含与 SpringApplication 相关联的 SpringApplicationEvent。除此之外,在 ApplicationPreparedEvent 之后、ApplicationStartedEvent 之前,还会发布以下事件:

提示

你通常不需要使用应用事件,但知道它们的存在会很有用。在内部,Spring Boot 使用事件来处理各种任务。

备注

事件监听器不应运行可能耗时较长的任务,因为它们默认在同一线程中执行。建议改用 ApplicationRunner 和 CommandLineRunner

应用程序事件通过使用 Spring Framework 的事件发布机制进行发送。该机制的一部分确保了在子上下文中发布给监听器的事件,也会被发布到任何祖先上下文中的监听器。因此,如果你的应用程序使用了 SpringApplication 实例的层级结构,监听器可能会接收到多个相同类型的应用程序事件实例。

为了让你的监听器能够区分针对其自身上下文的事件和针对子级上下文的事件,它应当请求注入其应用上下文(application context),然后将注入的上下文与事件的上下文进行比较。可以通过实现 ApplicationContextAware 来注入上下文,或者如果该监听器是一个 bean,则可以使用 @Autowired 进行注入。

Web 环境

一个 SpringApplication 会尝试为你创建合适类型的 ApplicationContext。用于确定 WebApplicationType 的算法如下:

这意味着,如果你在同一个应用程序中同时使用 Spring MVC 和 Spring WebFlux 中新的 WebClient,默认将使用 Spring MVC。你可以通过调用 setWebApplicationType(WebApplicationType) 轻松覆盖该默认行为。

也可以通过调用 setApplicationContextFactory(…​) 方法,完全控制所使用的 ApplicationContext 类型。

提示

在 JUnit 测试中使用 SpringApplication 时,通常建议调用 setWebApplicationType(WebApplicationType.NONE)

访问应用程序参数

如果你需要访问传递给 SpringApplication.run(…​) 的应用程序参数,可以注入一个 ApplicationArguments Bean。ApplicationArguments 接口提供了对原始 String[] 参数以及已解析的 option(选项)和 non-option(非选项)参数的访问,如下例所示:

import java.util.List;

import org.springframework.boot.ApplicationArguments;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

public MyBean(ApplicationArguments args) {
boolean debug = args.containsOption("debug");
List<String> files = args.getNonOptionArgs();
if (debug) {
System.out.println(files);
}
// if run with "--debug logfile.txt" prints ["logfile.txt"]
}

}
提示

Spring Boot 还会向 Spring 的 Environment 注册一个 CommandLinePropertySource。这使得你也可以使用 @Value 注解来注入单个应用程序参数。

使用 ApplicationRunner 或 CommandLineRunner

如果你需要在 SpringApplication 启动后运行一些特定代码,可以实现 ApplicationRunnerCommandLineRunner 接口。这两个接口的工作方式相同,都提供了一个 run 方法,该方法会在 SpringApplication.run(…​) 完成之前被调用。

备注

该合约非常适合用于那些应在应用程序启动后、但在开始接收流量之前运行的任务。

CommandLineRunner 接口以字符串数组的形式提供对应用程序参数的访问,而 ApplicationRunner 则使用前面讨论过的 ApplicationArguments 接口。以下示例展示了一个带有 run 方法的 CommandLineRunner

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class MyCommandLineRunner implements CommandLineRunner {

@Override
public void run(String... args) {
// Do something...
}

}

如果定义了多个 CommandLineRunnerApplicationRunner Bean,并且它们必须按特定顺序调用,你可以额外实现 Ordered 接口,或使用 Order 注解。

应用退出

每个 SpringApplication 都会向 JVM 注册一个关闭钩子(shutdown hook),以确保在退出时 ApplicationContext 能够优雅地关闭。所有标准的 Spring 生命周期回调(例如 DisposableBean 接口或 @PreDestroy 注解)均可使用。

此外,如果 Bean 希望在调用 SpringApplication.exit() 时返回特定的退出码,可以实现 ExitCodeGenerator 接口。随后可将该退出码传递给 System.exit(),作为状态码返回,如下例所示:

import org.springframework.boot.ExitCodeGenerator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class MyApplication {

@Bean
public ExitCodeGenerator exitCodeGenerator() {
return () -> 42;
}

public static void main(String[] args) {
System.exit(SpringApplication.exit(SpringApplication.run(MyApplication.class, args)));
}

}

此外,ExitCodeGenerator 接口也可以由异常类实现。当遇到此类异常时,Spring Boot 会返回该实现的 getExitCode() 方法所提供的退出码。

如果有多个 ExitCodeGenerator,则使用第一个生成的非零退出码。为了控制调用生成器的顺序,可以额外实现 Ordered 接口,或使用 Order 注解。

管理功能

可以通过指定 spring.application.admin.enabled 属性来启用应用程序的管理相关功能。这会在平台的 MBeanServer 上暴露 SpringApplicationAdminMXBean。你可以使用此功能远程管理你的 Spring Boot 应用程序。该功能对于任何服务包装器(service wrapper)实现也可能很有用。

提示

如果你想了解应用程序运行在哪个 HTTP 端口上,可以通过键为 local.server.port 的属性获取。

应用启动跟踪

在应用程序启动期间,SpringApplicationApplicationContext 会执行许多与应用程序生命周期、Bean 生命周期甚至应用程序事件处理相关的任务。通过 ApplicationStartup,Spring Framework 允许你使用 StartupStep 对象来跟踪应用程序的启动过程。这些数据可以用于性能分析,或者只是为了更好地理解应用程序的启动流程。

在设置 SpringApplication 实例时,你可以选择一个 ApplicationStartup 的实现。例如,要使用 BufferingApplicationStartup,你可以这样写:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;

@SpringBootApplication
public class MyApplication {

public static void main(String[] args) {
SpringApplication application = new SpringApplication(MyApplication.class);
application.setApplicationStartup(new BufferingApplicationStartup(2048));
application.run(args);
}

}

第一个可用的实现 FlightRecorderApplicationStartup 由 Spring Framework 提供。它将 Spring 特定的启动事件添加到 Java Flight Recorder 会话中,用于分析应用程序,并将其 Spring 上下文生命周期与 JVM 事件(例如内存分配、GC、类加载等)进行关联。配置完成后,你可以通过启用 Flight Recorder 来运行应用程序以记录数据:

$ java -XX:StartFlightRecording:filename=recording.jfr,duration=10s -jar demo.jar

Spring Boot 自带了 BufferingApplicationStartup 的实现;该实现用于缓冲启动步骤,并将其转储到外部指标系统中。应用程序可以在任意组件中请求类型为 BufferingApplicationStartup 的 Bean。

Spring Boot 也可以配置为暴露一个 startup endpoint,以 JSON 文档的形式提供此信息。

虚拟线程

虚拟线程需要 Java 21 或更高版本。为了获得最佳体验,强烈推荐使用 Java 24 或更高版本。要启用虚拟线程,请将 spring.threads.virtual.enabled 属性设置为 true

在为你的应用程序启用此选项之前,你应该考虑阅读官方的 Java 虚拟线程文档。在某些情况下,由于“Pinned Virtual Threads”(被固定的虚拟线程),应用程序可能会出现吞吐量下降的情况;该页面还解释了如何使用 JDK Flight Recorder 或 jcmd CLI 来检测此类情况。

备注

如果启用了虚拟线程(virtual threads),配置线程池的属性将不再生效。这是因为虚拟线程是在 JVM 范围内的平台线程池(platform thread pool)上进行调度的,而不是在专用的线程池上。

注意

虚拟线程的一个副作用是它们属于守护线程(daemon threads)。当 JVM 中所有线程都是守护线程时,JVM 将会退出。这种行为在某些场景下可能引发问题,例如当你依赖 @Scheduled 注解的 Bean 来维持应用运行时。如果你使用了虚拟线程,调度器线程将是一个虚拟线程,因此也是守护线程,无法阻止 JVM 退出。这不仅影响任务调度,其他技术也可能存在类似问题。为确保在所有情况下 JVM 都能持续运行,建议将属性 spring.main.keep-alive 设置为 true。这样即使所有线程都是虚拟线程,JVM 也会保持运行。