SpringApplication
SpringApplication
类提供了一种方便的方法来引导从 main()
方法启动的 Spring 应用程序。在许多情况下,你可以委派给静态 SpringApplication.run
方法,如下例所示:
include-code::MyApplication[]
当你的应用程序启动时,你应该看到类似于以下输出的内容:
Unresolved include directive in modules/ROOT/pages/features/spring-application.adoc - include::ROOT:partial$application/spring-application.txt[]
默认情况下,将显示 INFO
日志消息,包括一些相关的启动详细信息,例如启动应用程序的用户。如果你需要 INFO
之外的日志级别,则可以根据 Log Levels 中的说明进行设置。应用程序版本由主应用程序类的包中的实现版本确定。可以通过将 spring.main.log-startup-info
设置为 false
来关闭启动信息日志记录。这也将关闭应用程序的活动配置文件的日志记录。
要在启动期间添加额外的日志记录,可以在 |
Startup Failure
如果你的应用程序无法启动,注册的 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 提供了众多的 |
如果没有故障分析器能够处理异常,你仍然可以显示全部条件报告,以更好地了解出了什么问题。为此,你需要为 org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
enable the debug
property 或 enable DEBUG
logging。
例如,如果你正在使用 java -jar
运行你的应用程序,你可以按如下方式启用 debug
属性:
$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug
Lazy Initialization
SpringApplication
允许延迟初始化应用程序。启用延迟初始化后,在需要时创建 bean,而不是在应用程序启动期间创建。因此,启用延迟初始化可以减少应用程序启动所需的时间。在 Web 应用程序中,启用延迟初始化将导致许多与 Web 相关的 bean 在接收到 HTTP 请求之前不会初始化。
延迟初始化的一个缺点是,它可能会延迟发现应用程序中的问题。如果配置错误的 bean 被延迟初始化,则故障将不再发生在启动期间,并且只有在 bean 初始化时才会变得明显。还必须注意确保 JVM 有足够的内存来容纳应用程序的所有 bean,而不仅仅是在启动期间初始化的 bean。出于这些原因,延迟初始化在默认情况下未启用,建议在启用延迟初始化之前微调 JVM 的堆大小。
可以使用 SpringApplicationBuilder
上的 lazyInitialization
方法或 SpringApplication
上的 setLazyInitialization
方法以编程方式启用延迟初始化。或者,也可以使用 configprop:spring.main.lazy-initialization[] 属性启用它,如下例所示:
spring: main: lazy-initialization: true
如果要在对应用程序其余部分使用延迟初始化的同时禁用某些 bean 的延迟初始化,可以使用 |
Customizing the Banner
可以在启动时打印的 banner 可以通过将 banner.txt
文件添加到类路径或将 configprop:spring.banner.location[] 属性设置为此类文件的位置进行更改。如果该文件使用 UTF-8 以外的编码,则可以设置 spring.banner.charset
。
在你的 banner.txt
文件中,可以使用 Environment
中可获得的任何键,以及以下任何占位符:
Variable | Description |
---|---|
|
如 |
|
在 |
|
您正在使用的 Spring Boot 版本。例如 |
|
您正在使用的 Spring Boot 版本,格式化以便进行显示(用括号括起来并在前面加上 |
|
其中 |
|
你在 |
如果你想以编程方式生成一个横幅,可以使用 |
你还可以使用 configprop:spring.main.banner-mode[] 属性来确定是否必须在 System.out
(console
) 上打印横幅,将其发送至已配置的记录器 (log
),或根本不生成 (off
)。
注册了打印标语作为一个单例 bean,名称为:springBootBanner
。
|
Customizing SpringApplication
如果 SpringApplication
默认值不符合您的品味,您可以创建一个本地实例,并对其进行自定义。例如,关闭标语,您可以编写:
传递到 |
还可以使用 application.properties
文件来配置 SpringApplication
。有关详情,请参阅 Externalized Configuration。
有关配置选项的完整列表,请参阅 SpringApplication
Javadoc.
Fluent Builder API
如果您需要构建 ApplicationContext
层次结构(带有父子关系的多个上下文)或如果您更喜欢使用 “fluent” 构建器 API,则可以使用 SpringApplicationBuilder
.
SpringApplicationBuilder
让您可以将多个方法调用链接在一起,并且包括允许您创建层次结构的 parent
和 child
方法,如下例所示:
创建 |
Application Availability
在平台上进行部署时,应用程序可以使用诸如 Kubernetes Probes之类的基础设施向平台提供有关其可用性的信息。Spring Boot 开箱即用地支持常用的 “liveness” 和 “readiness” 可用性状态。如果您正在使用 Spring Boot 的 “actuator” 支持,则这些状态将作为运行状况端点组公开。
此外,您还可以通过将 ApplicationAvailability
接口注入到自己的 bean 中来获取可用性状态。
Liveness State
应用程序的 “Liveness” 状态告知其内部状态是否允许其正确工作,或者在当前失败时自行恢复。“Liveness” 状态中断表示应用程序处于无法恢复的状态,基础设施应重新启动应用程序。
一般来说,“活跃性”状态不应基于外部检查,例如 Health checks.如果这样做,一个失败的外部系统(数据库、Web API、外部缓存)将触发整个平台的大量重启和级联故障。 |
Spring Boot 应用程序的内部状态主要由 Spring ApplicationContext
表示。如果应用程序上下文已成功启动,Spring Boot 假设应用程序处于有效状态。应用程序在上下文刷新后立即被视为活跃,请参阅 Spring Boot application lifecycle and related Application Events.
Readiness State
应用程序的 “Readiness” 状态告知应用程序是否已准备好处理流量。“Readiness” 状态失败告知平台目前不应将流量路由到应用程序。这种情况通常发生在启动期间 CommandLineRunner
和 ApplicationRunner
组件正在被处理,或在应用程序决定它太忙而无法处理额外流量的任何时候。
一旦调用应用程序和命令行运行程序,应用程序就会被认为已准备就绪,请参阅 Spring Boot application lifecycle and related Application Events.
应通过 |
Application Events and Listeners
除了常见的 Spring 框架事件,如 {@url-spring-framework-javadoc}/org/springframework/context/event/ContextRefreshedEvent.html[ContextRefreshedEvent
],SpringApplication
发送一些附加应用程序事件。
某些事件实际上在创建
|
应用程序事件在您的应用程序运行时按以下顺序发送:
-
ApplicationStartingEvent
在运行开始时发送,但在任何处理之前,但侦听器和初始化器的注册除外。 -
在已知的用于上下文的
Environment
上,但在创建上下文之前,发送了一个ApplicationEnvironmentPreparedEvent
。 -
当
ApplicationContext
准备就绪且已调用 ApplicationContextInitializers 时,但任何 Bean 定义尚未加载时,将发送一个ApplicationContextInitializedEvent
。 -
刷新开始前,但在 Bean 定义已加载后,发送
ApplicationPreparedEvent
。 -
上下文刷新后,但在任何应用程序和命令行运行器被调用之前,发送一个
ApplicationStartedEvent
。 -
在
LivenessState.CORRECT
的AvailabilityChangeEvent
之后立即发送,以表明应用程序被视为已启动。 -
在任何 application and command-line runners 被调用后,发送一个
AvailabilityChangeEvent
。 -
在
ReadinessState.ACCEPTING_TRAFFIC
的ApplicationReadyEvent
之后立即发送,以表明应用程序已准备好处理请求。 -
如果启动时出现异常,则发送
ApplicationFailedEvent
。
上述列表仅包括 SpringApplicationEvent`s that are tied to a `SpringApplication
。除此之外,还发布了 ApplicationPreparedEvent
之后和 ApplicationStartedEvent
之前的以下事件:
-
在
WebServer
准备好后,发送一个WebServerInitializedEvent
。ServletWebServerInitializedEvent
和ReactiveWebServerInitializedEvent
分别是 Servlet 和响应式变体。 -
刷新
ApplicationContext
时,发送一个ContextRefreshedEvent
。
您通常不需要使用应用程序事件,但知道它们的存在可能很有用。在内部,Spring Boot 使用事件来处理各种任务。 |
默认情况下,事件侦听器不应该运行可能费时的任务,因为它们在同一线程中执行。请考虑使用 application and command-line runners 代替。 |
Spring Framework 的事件发布机制发送应用程序事件。该机制的一部分确保发布到子上下文中的事件也发布到任何祖先上下文中的事件监听器。因此,如果您的应用程序使用 SpringApplication
实例的层次结构,则侦听器可能会收到同类型应用程序事件的多个实例。
若要使您的侦听器区分其上下文中的事件和后代上下文中的事件,应要求其应用程序上下文注入,然后将注入的上下文与事件的上下文进行比较。可以通过实现 ApplicationContextAware
来注入上下文,或者如果侦听器为一个 bean,则使用 @Autowired
。
Web Environment
SpringApplication
会尝试代表您创建正确类型的 ApplicationContext
。用于确定 WebApplicationType
的算法如下:
-
如果存在 Spring MVC,则使用
AnnotationConfigServletWebServerApplicationContext
-
如果不存在 Spring MVC 但存在 Spring WebFlux,则使用
AnnotationConfigReactiveWebServerApplicationContext
-
Otherwise,
AnnotationConfigApplicationContext
is used
这意味着,如果您在同一个应用程序中同时使用 Spring MVC 和 Spring WebFlux 中的 WebClient
,则默认使用 Spring MVC。您可以通过调用 setWebApplicationType(WebApplicationType)
轻松地覆盖这一点。
您还可以通过调用 setApplicationContextFactory(…)
完全控制所使用的 ApplicationContext
类型。
在 JUnit 测试中使用 |
Accessing Application Arguments
如果您需要访问传递给 SpringApplication.run(…)
的应用程序参数,您可以注入 org.springframework.boot.ApplicationArguments
bean。ApplicationArguments
接口提供了对原始 String[]
参数以及解析后的 option
和 non-option
参数的访问,如下例所示:
Spring Boot 还使用 |
Using the ApplicationRunner or CommandLineRunner
如果您需要在 SpringApplication
启动后运行某些特定代码,您可以实现 ApplicationRunner
或 CommandLineRunner
接口。这两个接口的工作方式相同,并提供一个 run
方法,在 SpringApplication.run(…)
完成之前调用该方法。
此协定非常适合在应用程序启动后但开始接受流量之前运行的任务。 |
CommandLineRunner
接口以字符串数组的形式提供对应用程序参数的访问,而 ApplicationRunner
使用前面讨论的 ApplicationArguments
接口。以下示例显示了一个具有 run
方法的 CommandLineRunner
:
如果定义了必须按特定顺序调用的多个 CommandLineRunner
或 ApplicationRunner
bean,则您还可以实现 org.springframework.core.Ordered
接口或使用 org.springframework.core.annotation.Order
注释。
Application Exit
每个 SpringApplication
都在 JVM 中注册了一个关闭挂钩,以确保 ApplicationContext
在退出时正常关闭。可以使用所有标准 Spring 生命周期回调(例如 DisposableBean
接口或 @PreDestroy
注释)。
此外,如果 bean 希望在调用 SpringApplication.exit()
时返回特定的退出代码,则它们可以实现 org.springframework.boot.ExitCodeGenerator
接口。然后,此退出代码可传递给 System.exit()
,以作为状态代码返回,如下例所示:
另外,ExitCodeGenerator
接口可由异常实现。遇到此类异常时,Spring Boot 会返回由实现的 getExitCode()
方法提供的退出代码。
如果有多个 ExitCodeGenerator
,则使用生成的第一个非零退出代码。若要控制调用生成器的顺序,还可以实现 org.springframework.core.Ordered
接口或使用 org.springframework.core.annotation.Order
注释。
Admin Features
可以通过指定 configprop:spring.application.admin.enabled[] 属性来为应用程序启用与管理员相关的功能。此操作会公开平台上的 {code-spring-boot-src}/admin/SpringApplicationAdminMXBean.java[SpringApplicationAdminMXBean
]。你可以使用此功能远程管理你的 Spring Boot 应用程序。对于任何服务包装实现,此功能也很实用。
如果你想了解应用程序正在运行的 HTTP 端口,请使用键 |
Application Startup tracking
在应用程序启动期间,SpringApplication
和 ApplicationContext
执行了与应用程序生命周期、bean 生命周期甚至处理应用程序时间相关的许多任务。通过 {url-spring-framework-javadoc}/org/springframework/core/metrics/ApplicationStartup.html[ApplicationStartup
],Spring Framework {url-spring-framework-docs}/core/beans/context-introduction.html#context-functionality-startup[允许你通过 StartupStep
对象跟踪应用程序启动序列]。此数据可为分析目的收集,或者只是为了更好地了解应用程序启动过程。
在设置 SpringApplication
实例时,你可以选择 ApplicationStartup
实现。例如,要使用 BufferingApplicationStartup
,你可以编写:
第一个可用的实现 FlightRecorderApplicationStartup
由 Spring Framework 提供。它会向 Java Flight Recorder 会话添加特定的 Spring 启动事件,并且旨在分析应用程序以及将它们的 Spring context 生命周期与 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 文档提供。
Virtual threads
如果你在 Java 21 或更高版本上运行,你可以通过将属性 configprop:spring.threads.virtual.enabled[] 设置为 true
来启用虚拟线程。
在为你的应用程序启用此选项之前,你应考虑 reading the official Java virtual threads documentation。在某些情况下,应用程序可能会因为“固定虚拟线程”而导致更低的吞吐量;此页面还说明了如何使用 JDK Flight Recorder 或 jcmd
CLI 检测此类情况。
虚拟线程的一个副作用是它们是守护线程。如果它的所有线程都是守护线程,JVM 将会退出。当你依赖 @Scheduled
bean(例如,保持应用程序运行)时,此行为可能会出现问题。如果你使用虚拟线程,调度线程是一个虚拟线程,因此是一个守护线程,并且无法保持 JVM 运行。这不仅会影响调度,而且可能同样适用于其他技术。为了在所有情况下保持 JVM 运行,建议将属性 configprop:spring.main.keep-alive[] 设置为 true
。这确保了 JVM 将处于活动状态,即使所有线程都是虚拟线程也是如此。