SpringApplication
SpringApplication
类提供了一种便捷的方式来引导一个从 main()
方法启动的 Spring 应用。在许多情况下,您可以委托给静态 SpringApplication.run
方法,如下例所示
-
Java
-
Kotlin
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);
}
}
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class MyApplication
fun main(args: Array<String>) {
runApplication<MyApplication>(*args)
}
当您的应用启动时,您应该会看到类似以下的输出
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.3.5)
2024-10-24T12:03:05.386Z INFO 112801 --- [ main] o.s.b.d.f.logexample.MyApplication : Starting MyApplication using Java 17.0.13 with PID 112801 (/opt/apps/myapp.jar started by myuser in /opt/apps/)
2024-10-24T12:03:05.406Z INFO 112801 --- [ main] o.s.b.d.f.logexample.MyApplication : No active profile set, falling back to 1 default profile: "default"
2024-10-24T12:03:08.644Z INFO 112801 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http)
2024-10-24T12:03:08.685Z INFO 112801 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2024-10-24T12:03:08.690Z INFO 112801 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.31]
2024-10-24T12:03:08.898Z INFO 112801 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2024-10-24T12:03:08.900Z INFO 112801 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 3244 ms
2024-10-24T12:03:10.275Z INFO 112801 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/'
2024-10-24T12:03:10.290Z INFO 112801 --- [ main] o.s.b.d.f.logexample.MyApplication : Started MyApplication in 5.964 seconds (process running for 7.025)
默认情况下,会显示 INFO
级别的日志消息,包括一些相关的启动细节,例如启动应用的用户。如果您需要除 INFO
之外的日志级别,您可以设置它,如 日志级别 中所述。应用版本是使用主应用类包中的实现版本确定的。可以通过将 spring.main.log-startup-info
设置为 false
来关闭启动信息日志记录。这也会关闭应用活动配置文件的日志记录。
要在启动期间添加其他日志记录,您可以在 SpringApplication 的子类中覆盖 logStartupInfo(boolean) 。 |
启动失败
如果您的应用启动失败,注册的 FailureAnalyzers
将有机会提供专门的错误消息和解决问题的具体操作。例如,如果您在端口 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 实现,您可以 添加您自己的。 |
如果没有任何故障分析器能够处理异常,您仍然可以显示完整的条件报告以更好地了解发生了什么错误。为此,您需要 启用 debug
属性 或 为 org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
启用 DEBUG
日志记录。
例如,如果您正在使用 java -jar
运行您的应用,您可以按如下方式启用 debug
属性
$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug
延迟初始化
SpringApplication
允许应用程序延迟初始化。启用延迟初始化后,Bean 会在需要时创建,而不是在应用程序启动期间创建。因此,启用延迟初始化可以缩短应用程序启动时间。在 Web 应用程序中,启用延迟初始化将导致许多与 Web 相关的 Bean 延迟到接收到 HTTP 请求时才初始化。
延迟初始化的一个缺点是它可能会延迟发现应用程序问题。如果错误配置的 Bean 是延迟初始化的,则故障将不再在启动时发生,而问题只有在 Bean 初始化时才会变得明显。还必须注意确保 JVM 拥有足够的内存来容纳所有应用程序的 Bean,而不仅仅是在启动期间初始化的那些 Bean。出于这些原因,默认情况下不会启用延迟初始化,建议在启用延迟初始化之前对 JVM 的堆大小进行微调。
可以使用 SpringApplicationBuilder
上的 lazyInitialization
方法或 SpringApplication
上的 setLazyInitialization
方法以编程方式启用延迟初始化。或者,可以使用 spring.main.lazy-initialization
属性启用它,如下例所示
-
属性
-
YAML
spring.main.lazy-initialization=true
spring:
main:
lazy-initialization: true
如果在对应用程序的其余部分使用延迟初始化的同时,想要禁用某些 Bean 的延迟初始化,可以使用 @Lazy(false) 注解将其 lazy 属性显式设置为 false。 |
自定义 Banner
可以通过将 banner.txt
文件添加到类路径或将 spring.banner.location
属性设置为该文件的路径来更改启动时打印的 Banner。如果文件使用 UTF-8 以外的编码,则可以设置 spring.banner.charset
。
在 banner.txt
文件中,您可以使用 Environment
中可用的任何键以及以下任何占位符
变量 | 描述 |
---|---|
|
应用程序的版本号,如 |
|
应用程序的版本号,如 |
|
您正在使用的 Spring Boot 版本。例如 |
|
您正在使用的 Spring Boot 版本,格式化以供显示(用括号括起来并在前面加上 |
|
其中 |
|
应用程序的标题,如 |
如果要以编程方式生成 Banner,可以使用 SpringApplication.setBanner(…) 方法。使用 org.springframework.boot.Banner 接口并实现您自己的 printBanner() 方法。 |
您还可以使用 spring.main.banner-mode
属性来确定是否必须在 System.out
(console
)上打印 Banner,发送到已配置的日志记录器(log
),或者根本不生成 Banner(off
)。
打印的 Banner 作为单例 Bean 注册,名称如下:springBootBanner
。
仅当您使用 要使用 |
自定义 SpringApplication
如果 SpringApplication
的默认值不符合您的要求,则可以创建一个本地实例并对其进行自定义。例如,要关闭 Banner,您可以编写
-
Java
-
Kotlin
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);
}
}
import org.springframework.boot.Banner
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class MyApplication
fun main(args: Array<String>) {
runApplication<MyApplication>(*args) {
setBannerMode(Banner.Mode.OFF)
}
}
传递给 SpringApplication 的构造函数参数是 Spring Bean 的配置源。在大多数情况下,这些是 @Configuration 类,但也可能是 @Component 类的直接引用。 |
也可以使用 application.properties
文件配置 SpringApplication
。有关详细信息,请参阅 外部化配置。
有关配置选项的完整列表,请参阅 SpringApplication
API 文档。
Fluent Builder API
如果您需要构建 ApplicationContext
层次结构(具有父子关系的多个上下文),或者您更喜欢使用 Fluent Builder API,则可以使用 SpringApplicationBuilder
。
SpringApplicationBuilder
允许您将多个方法调用链接在一起,并包含 parent
和 child
方法,允许您创建层次结构,如下例所示
-
Java
-
Kotlin
new SpringApplicationBuilder().sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);
SpringApplicationBuilder()
.sources(Parent::class.java)
.child(Application::class.java)
.bannerMode(Banner.Mode.OFF)
.run(*args)
创建 ApplicationContext 层次结构时存在一些限制。例如,Web 组件**必须**包含在子上下文中,并且父上下文和子上下文都使用相同的 Environment 。有关完整详细信息,请参阅 SpringApplicationBuilder API 文档。 |
应用程序可用性
在部署到平台上时,应用程序可以使用 Kubernetes 探针等基础设施向平台提供有关其可用性的信息。Spring Boot 包括对常用的“存活性”和“就绪性”可用性状态的开箱即用支持。如果您使用 Spring Boot 的“执行器”支持,则这些状态将作为健康端点组公开。
此外,您还可以通过将 ApplicationAvailability
接口注入到您自己的 Bean 中来获取可用性状态。
存活性状态
应用程序的“存活性”状态指示其内部状态是否允许其正常工作,或者如果当前发生故障,它是否能够自行恢复。损坏的“存活性”状态意味着应用程序处于无法从中恢复的状态,基础设施应重新启动应用程序。
通常,“存活性”状态不应基于外部检查,例如 健康检查。如果确实如此,则故障的外部系统(数据库、Web API、外部缓存)将触发平台上的大量重启和级联故障。 |
Spring Boot 应用程序的内部状态主要由 Spring ApplicationContext
表示。如果应用程序上下文已成功启动,则 Spring Boot 假设应用程序处于有效状态。只要上下文已刷新,应用程序就被视为存活,请参阅 Spring Boot 应用程序生命周期和相关的应用程序事件。
就绪性状态
应用程序的“就绪性”状态指示应用程序是否已准备好处理流量。故障的“就绪性”状态告诉平台现在不应将流量路由到应用程序。这通常发生在启动期间,同时正在处理 CommandLineRunner
和 ApplicationRunner
组件,或者在应用程序决定其太忙而无法处理更多流量的任何时间。
只要应用程序和命令行运行程序已调用,应用程序就被视为已准备就绪,请参阅 Spring Boot 应用程序生命周期和相关的应用程序事件。
应通过 CommandLineRunner 和 ApplicationRunner 组件执行预期在启动期间运行的任务,而不是使用 Spring 组件生命周期回调(例如 @PostConstruct )。 |
管理应用程序可用性状态
应用程序组件可以随时检索当前的可用性状态,方法是注入 ApplicationAvailability
接口并调用其上的方法。更常见的情况是,应用程序希望侦听状态更新或更新应用程序的状态。
例如,我们可以将应用程序的“就绪性”状态导出到文件中,以便 Kubernetes“exec 探针”可以查看此文件
-
Java
-
Kotlin
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.ReadinessState
import org.springframework.context.event.EventListener
import org.springframework.stereotype.Component
@Component
class MyReadinessStateExporter {
@EventListener
fun onStateChange(event: AvailabilityChangeEvent<ReadinessState?>) {
when (event.state) {
ReadinessState.ACCEPTING_TRAFFIC -> {
// create file /tmp/healthy
}
ReadinessState.REFUSING_TRAFFIC -> {
// remove file /tmp/healthy
}
else -> {
// ...
}
}
}
}
我们还可以更新应用程序的状态,当应用程序发生故障且无法恢复时
-
Java
-
Kotlin
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);
}
}
}
import org.springframework.boot.availability.AvailabilityChangeEvent
import org.springframework.boot.availability.LivenessState
import org.springframework.context.ApplicationEventPublisher
import org.springframework.stereotype.Component
@Component
class MyLocalCacheVerifier(private val eventPublisher: ApplicationEventPublisher) {
fun checkLocalCache() {
try {
// ...
} catch (ex: CacheCompletelyBrokenException) {
AvailabilityChangeEvent.publish(eventPublisher, ex, LivenessState.BROKEN)
}
}
}
Spring Boot 提供了 用于“存活性”和“就绪性”的 Kubernetes HTTP 探针以及执行器健康端点。您可以获得有关 在专用部分中将 Spring Boot 应用程序部署到 Kubernetes 的更多指导。
应用程序事件和侦听器
除了通常的 Spring 框架事件(例如 ContextRefreshedEvent
)之外,SpringApplication
还会发送一些其他应用程序事件。
某些事件实际上是在创建 如果希望无论应用程序创建方式如何都自动注册这些侦听器,则可以在项目中添加
|
应用程序事件按以下顺序发送,当您的应用程序运行时
-
在运行开始时但任何处理之前发送
ApplicationStartingEvent
,除了侦听器和初始化器的注册之外。 -
在已知上下文中要使用的
Environment
但在创建上下文之前发送ApplicationEnvironmentPreparedEvent
。 -
在准备
ApplicationContext
并且已调用 ApplicationContextInitializers 但在加载任何 Bean 定义之前发送ApplicationContextInitializedEvent
。 -
在开始刷新之前但加载 Bean 定义之后发送
ApplicationPreparedEvent
。 -
在上下文刷新后但调用任何应用程序和命令行运行程序之前发送
ApplicationStartedEvent
。 -
之后发送
AvailabilityChangeEvent
,并使用LivenessState.CORRECT
指示应用程序被视为存活。 -
在调用任何 应用程序和命令行运行程序 之后发送
ApplicationReadyEvent
。 -
之后发送
AvailabilityChangeEvent
,并使用ReadinessState.ACCEPTING_TRAFFIC
指示应用程序已准备好为请求提供服务。 -
如果启动时出现异常,则发送
ApplicationFailedEvent
。
以上列表仅包含与 SpringApplication
绑定的 SpringApplicationEvent
。除了这些之外,还在 ApplicationPreparedEvent
之后和 ApplicationStartedEvent
之前发布以下事件
-
在
WebServer
准备好后发送WebServerInitializedEvent
。ServletWebServerInitializedEvent
和ReactiveWebServerInitializedEvent
分别是 servlet 和反应式变体。 -
当
ApplicationContext
刷新时发送ContextRefreshedEvent
。
您通常不需要使用应用程序事件,但了解它们的存在会很有帮助。在内部,Spring Boot 使用事件来处理各种任务。 |
事件监听器不应该运行潜在的长时间任务,因为它们默认在同一个线程中执行。请考虑改用应用程序和命令行运行器。 |
应用程序事件是通过使用 Spring 框架的事件发布机制发送的。该机制的一部分确保发布到子上下文中的监听器的事件也会发布到任何祖先上下文中的监听器。因此,如果您的应用程序使用SpringApplication
实例的层次结构,监听器可能会收到同一类型应用程序事件的多个实例。
为了允许您的监听器区分其上下文事件和后代上下文事件,它应该请求注入其应用程序上下文,然后将注入的上下文与事件的上下文进行比较。可以通过实现ApplicationContextAware
或(如果监听器是 Bean)使用@Autowired
来注入上下文。
Web 环境
SpringApplication
会尝试代表您创建正确的ApplicationContext
类型。用于确定WebApplicationType
的算法如下:
-
如果存在 Spring MVC,则使用
AnnotationConfigServletWebServerApplicationContext
。 -
如果不存在 Spring MVC 且存在 Spring WebFlux,则使用
AnnotationConfigReactiveWebServerApplicationContext
。 -
否则,使用
AnnotationConfigApplicationContext
。
这意味着,如果您在同一个应用程序中使用 Spring MVC 和来自 Spring WebFlux 的新的WebClient
,则默认情况下将使用 Spring MVC。您可以通过调用setWebApplicationType(WebApplicationType)
轻松覆盖它。
还可以通过调用setApplicationContextFactory(…)
完全控制使用的ApplicationContext
类型。
在 JUnit 测试中使用SpringApplication 时,通常希望调用setWebApplicationType(WebApplicationType.NONE) 。 |
访问应用程序参数
如果您需要访问传递给SpringApplication.run(…)
的应用程序参数,则可以注入一个org.springframework.boot.ApplicationArguments
Bean。ApplicationArguments
接口提供了对原始String[]
参数以及解析后的option
和non-option
参数的访问,如下例所示:
-
Java
-
Kotlin
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"]
}
}
import org.springframework.boot.ApplicationArguments
import org.springframework.stereotype.Component
@Component
class MyBean(args: ApplicationArguments) {
init {
val debug = args.containsOption("debug")
val files = args.nonOptionArgs
if (debug) {
println(files)
}
// if run with "--debug logfile.txt" prints ["logfile.txt"]
}
}
Spring Boot 还使用 Spring Environment 注册了一个CommandLinePropertySource 。这允许您还可以使用@Value 注解注入单个应用程序参数。 |
使用 ApplicationRunner 或 CommandLineRunner
如果您需要在SpringApplication
启动后运行一些特定代码,则可以实现ApplicationRunner
或CommandLineRunner
接口。这两个接口的工作方式相同,并提供一个run
方法,该方法在SpringApplication.run(…)
完成之前被调用。
此约定非常适合在应用程序启动后但在其开始接受流量之前应运行的任务。 |
CommandLineRunner
接口以字符串数组的形式提供对应用程序参数的访问,而ApplicationRunner
使用前面讨论的ApplicationArguments
接口。以下示例显示了一个带有run
方法的CommandLineRunner
:
-
Java
-
Kotlin
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) {
// Do something...
}
}
import org.springframework.boot.CommandLineRunner
import org.springframework.stereotype.Component
@Component
class MyCommandLineRunner : CommandLineRunner {
override fun run(vararg args: String) {
// Do something...
}
}
如果定义了几个必须按特定顺序调用的CommandLineRunner
或ApplicationRunner
Bean,则还可以额外实现org.springframework.core.Ordered
接口或使用org.springframework.core.annotation.Order
注解。
应用程序退出
每个SpringApplication
都会在 JVM 中注册一个关闭钩子,以确保ApplicationContext
在退出时正常关闭。可以使用所有标准的 Spring 生命周期回调(例如DisposableBean
接口或@PreDestroy
注解)。
此外,如果 Bean 希望在调用SpringApplication.exit()
时返回特定的退出代码,则可以实现org.springframework.boot.ExitCodeGenerator
接口。然后,此退出代码可以传递给System.exit()
以将其作为状态代码返回,如下例所示:
-
Java
-
Kotlin
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)));
}
}
import org.springframework.boot.ExitCodeGenerator
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Bean
import kotlin.system.exitProcess
@SpringBootApplication
class MyApplication {
@Bean
fun exitCodeGenerator() = ExitCodeGenerator { 42 }
}
fun main(args: Array<String>) {
exitProcess(SpringApplication.exit(
runApplication<MyApplication>(*args)))
}
此外,异常也可以实现ExitCodeGenerator
接口。遇到此类异常时,Spring Boot 会返回实现的getExitCode()
方法提供的退出代码。
如果有多个ExitCodeGenerator
,则使用生成的第一个非零退出代码。要控制生成器调用的顺序,请另外实现org.springframework.core.Ordered
接口或使用org.springframework.core.annotation.Order
注解。
管理功能
可以通过指定spring.application.admin.enabled
属性为应用程序启用与管理相关的功能。这会在平台MBeanServer
上公开SpringApplicationAdminMXBean
。您可以使用此功能远程管理您的 Spring Boot 应用程序。此功能对于任何服务包装器实现也可能很有用。
如果您想知道应用程序在哪个 HTTP 端口上运行,请获取键为local.server.port 的属性。 |
应用程序启动跟踪
在应用程序启动期间,SpringApplication
和ApplicationContext
执行许多与应用程序生命周期、Bean 生命周期甚至处理应用程序事件相关的任务。借助ApplicationStartup
,Spring Framework允许您使用StartupStep
对象跟踪应用程序启动序列。可以收集此数据以进行性能分析,或者只是为了更好地了解应用程序启动过程。
在设置SpringApplication
实例时,您可以选择ApplicationStartup
实现。例如,要使用BufferingApplicationStartup
,您可以编写:
-
Java
-
Kotlin
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);
}
}
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup
import org.springframework.boot.runApplication
@SpringBootApplication
class MyApplication
fun main(args: Array<String>) {
runApplication<MyApplication>(*args) {
applicationStartup = BufferingApplicationStartup(2048)
}
}
Spring Framework 提供了第一个可用的实现FlightRecorderApplicationStartup
。它将特定于 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
端点,该端点以 JSON 文档的形式提供此信息。
虚拟线程
如果您在 Java 21 或更高版本上运行,则可以通过将属性spring.threads.virtual.enabled
设置为true
来启用虚拟线程。
在为您的应用程序打开此选项之前,您应该考虑阅读官方的 Java 虚拟线程文档。在某些情况下,应用程序可能会因“固定虚拟线程”而导致吞吐量降低;此页面还说明了如何使用 JDK Flight Recorder 或jcmd
CLI 检测此类情况。
如果启用了虚拟线程,则配置线程池的属性将不再生效。这是因为虚拟线程是在 JVM 范围内的平台线程池上调度,而不是在专用线程池上调度。 |
虚拟线程的一个副作用是它们是守护线程。如果其所有线程都是守护线程,则 JVM 将退出。例如,当您依赖@Scheduled Bean 来保持应用程序活动时,此行为可能会成为问题。如果使用虚拟线程,则调度程序线程是虚拟线程,因此是守护线程,不会使 JVM 保持活动状态。这不仅会影响调度,而且在其他技术中也可能出现这种情况。为了在所有情况下都保持 JVM 运行,建议将属性spring.main.keep-alive 设置为true 。这确保了即使所有线程都是虚拟线程,JVM 也会保持活动状态。 |