SpringApplication

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

The SpringApplication class provides a convenient way to bootstrap a Spring application that is started from a main() method. In many situations, you can delegate to the static SpringApplication.run method, as shown in the following example: include-code::MyApplication[]

当你的应用程序启动时,你应该看到类似于以下输出的内容:

When your application starts, you should see something similar to the following output:

Unresolved include directive in modules/reference/pages/features/spring-application.adoc - include::ROOT:partial$application/spring-application.txt[]

默认情况下,将显示 INFO 日志消息,包括一些相关的启动详细信息,例如启动应用程序的用户。如果你需要 INFO 之外的日志级别,则可以根据 Log Levels 中的说明进行设置。应用程序版本由主应用程序类的包中的实现版本确定。可以通过将 spring.main.log-startup-info 设置为 false 来关闭启动信息日志记录。这也将关闭应用程序的活动配置文件的日志记录。

By default, INFO logging messages are shown, including some relevant startup details, such as the user that launched the application. If you need a log level other than INFO, you can set it, as described in Log Levels. The application version is determined using the implementation version from the main application class’s package. Startup information logging can be turned off by setting spring.main.log-startup-info to false. This will also turn off logging of the application’s active profiles.

要在启动期间添加额外的日志记录,可以在 SpringApplication 的子类中覆盖 logStartupInfo(boolean)

To add additional logging during startup, you can override logStartupInfo(boolean) in a subclass of SpringApplication.

Startup Failure

如果你的应用程序无法启动,注册的 FailureAnalyzers 有机会提供专门的错误消息和具体的解决问题的措施。例如,如果你在端口 8080 上启动 Web 应用程序,并且该端口已被使用,你应该会看到类似于以下消息的内容:

If your application fails to start, registered FailureAnalyzers get a chance to provide a dedicated error message and a concrete action to fix the problem. For instance, if you start a web application on port 8080 and that port is already in use, you should see something similar to the following message:

***************************
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 实现,你可以 add your own

Spring Boot provides numerous FailureAnalyzer implementations, and you can add your own.

如果没有故障分析器能够处理异常,你仍然可以显示全部条件报告,以更好地了解出了什么问题。为此,你需要为 org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener enable the debug propertyenable DEBUG logging

If no failure analyzers are able to handle the exception, you can still display the full conditions report to better understand what went wrong. To do so, you need to enable the debug property or enable DEBUG logging for org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener.

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

For instance, if you are running your application by using java -jar, you can enable the debug property as follows:

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

Lazy Initialization

SpringApplication 允许延迟初始化应用程序。启用延迟初始化后,在需要时创建 bean,而不是在应用程序启动期间创建。因此,启用延迟初始化可以减少应用程序启动所需的时间。在 Web 应用程序中,启用延迟初始化将导致许多与 Web 相关的 bean 在接收到 HTTP 请求之前不会初始化。

SpringApplication allows an application to be initialized lazily. When lazy initialization is enabled, beans are created as they are needed rather than during application startup. As a result, enabling lazy initialization can reduce the time that it takes your application to start. In a web application, enabling lazy initialization will result in many web-related beans not being initialized until an HTTP request is received.

延迟初始化的一个缺点是,它可能会延迟发现应用程序中的问题。如果配置错误的 bean 被延迟初始化,则故障将不再发生在启动期间,并且只有在 bean 初始化时才会变得明显。还必须注意确保 JVM 有足够的内存来容纳应用程序的所有 bean,而不仅仅是在启动期间初始化的 bean。出于这些原因,延迟初始化在默认情况下未启用,建议在启用延迟初始化之前微调 JVM 的堆大小。

A downside of lazy initialization is that it can delay the discovery of a problem with the application. If a misconfigured bean is initialized lazily, a failure will no longer occur during startup and the problem will only become apparent when the bean is initialized. Care must also be taken to ensure that the JVM has sufficient memory to accommodate all of the application’s beans and not just those that are initialized during startup. For these reasons, lazy initialization is not enabled by default and it is recommended that fine-tuning of the JVM’s heap size is done before enabling lazy initialization.

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

Lazy initialization can be enabled programmatically using the lazyInitialization method on SpringApplicationBuilder or the setLazyInitialization method on SpringApplication. Alternatively, it can be enabled using the configprop:spring.main.lazy-initialization[] property as shown in the following example:

spring:
  main:
    lazy-initialization: true

如果要在对应用程序其余部分使用延迟初始化的同时禁用某些 bean 的延迟初始化,可以使用 @Lazy(false) 注释明确将其延迟属性设置为 false。

If you want to disable lazy initialization for certain beans while using lazy initialization for the rest of the application, you can explicitly set their lazy attribute to false using the @Lazy(false) annotation.

Customizing the Banner

可以在启动时打印的 banner 可以通过将 banner.txt 文件添加到类路径或将 configprop:spring.banner.location[] 属性设置为此类文件的位置进行更改。如果该文件使用 UTF-8 以外的编码,则可以设置 spring.banner.charset

The banner that is printed on start up can be changed by adding a banner.txt file to your classpath or by setting the configprop:spring.banner.location[] property to the location of such a file. If the file has an encoding other than UTF-8, you can set spring.banner.charset.

在你的 banner.txt 文件中,可以使用 Environment 中可获得的任何键,以及以下任何占位符:

Inside your banner.txt file, you can use any key available in the Environment as well as any of the following placeholders:

Table 1. Banner variables
Variable Description

${application.version}

The version number of your application, as declared in MANIFEST.MF. For example, Implementation-Version: 1.0 is printed as 1.0.

${application.formatted-version}

The version number of your application, as declared in MANIFEST.MF and formatted for display (surrounded with brackets and prefixed with v). For example (v1.0).

${spring-boot.version}

The Spring Boot version that you are using. For example {version-spring-boot}.

${spring-boot.formatted-version}

The Spring Boot version that you are using, formatted for display (surrounded with brackets and prefixed with v). For example (v{version-spring-boot}).

${Ansi.NAME} (or ${AnsiColor.NAME}, ${AnsiBackground.NAME}, ${AnsiStyle.NAME})

Where NAME is the name of an ANSI escape code. See {code-spring-boot-src}/ansi/AnsiPropertySource.java[AnsiPropertySource] for details.

${application.title}

The title of your application, as declared in MANIFEST.MF. For example Implementation-Title: MyApp is printed as MyApp.

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

The SpringApplication.setBanner(…​) method can be used if you want to generate a banner programmatically. Use the org.springframework.boot.Banner interface and implement your own printBanner() method.

你还可以使用 configprop:spring.main.banner-mode[] 属性来确定是否必须在 System.out (console) 上打印横幅,将其发送至已配置的记录器 (log),或根本不生成 (off)。

You can also use the configprop:spring.main.banner-mode[] property to determine if the banner has to be printed on System.out (console), sent to the configured logger (log), or not produced at all (off).

注册了打印标语作为一个单例 bean,名称为:springBootBanner

The printed banner is registered as a singleton bean under the following name: springBootBanner.

application.titleapplication.versionapplication.formatted-version 属性仅可在将 java -jarjava -cp 与 Spring Boot 启动程序结合使用的情况下使用。值无法解决,如果您正在运行一个已解压的 jar 文件,并通过 java -cp <classpath> <mainclass> 启动它,或将您的应用程序作为一个本机镜像来运行的话。

The application.title, application.version, and application.formatted-version properties are only available if you are using java -jar or java -cp with Spring Boot launchers. The values will not be resolved if you are running an unpacked jar and starting it with java -cp <classpath> <mainclass> or running your application as a native image.

构建类路径并在启动应用程序之前使用 application. properties, launch your application as a packed jar using java -jar or as an unpacked jar using java org.springframework.boot.loader.launch.JarLauncher. This will initialize the application. 标语属性。

To use the application. properties, launch your application as a packed jar using java -jar or as an unpacked jar using java org.springframework.boot.loader.launch.JarLauncher. This will initialize the application. banner properties before building the classpath and launching your app.

Customizing SpringApplication

如果 SpringApplication 默认值不符合您的品味,您可以创建一个本地实例,并对其进行自定义。例如,关闭标语,您可以编写:

If the SpringApplication defaults are not to your taste, you can instead create a local instance and customize it. For example, to turn off the banner, you could write:

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

The constructor arguments passed to SpringApplication are configuration sources for Spring beans. In most cases, these are references to @Configuration classes, but they could also be direct references @Component classes.

还可以使用 application.properties 文件来配置 SpringApplication。有关详情,请参阅 Externalized Configuration

It is also possible to configure the SpringApplication by using an application.properties file. See Externalized Configuration for details.

有关配置选项的完整列表,请参阅 SpringApplication Javadoc.

For a complete list of the configuration options, see the SpringApplication Javadoc.

Fluent Builder API

如果您需要构建 ApplicationContext 层次结构(带有父子关系的多个上下文)或如果您更喜欢使用 “fluent” 构建器 API,则可以使用 SpringApplicationBuilder.

If you need to build an ApplicationContext hierarchy (multiple contexts with a parent/child relationship) or if you prefer using a “fluent” builder API, you can use the SpringApplicationBuilder.

SpringApplicationBuilder 让您可以将多个方法调用链接在一起,并且包括允许您创建层次结构的 parentchild 方法,如下例所示:

The SpringApplicationBuilder lets you chain together multiple method calls and includes parent and child methods that let you create a hierarchy, as shown in the following example:

创建 ApplicationContext 层次结构时存在一些限制。例如,Web 组件 must 包含在子上下文中,并且相同的 Environment 用于父上下文和子上下文。有关完整详细信息,请参阅 SpringApplicationBuilder Javadoc.

There are some restrictions when creating an ApplicationContext hierarchy. For example, Web components must be contained within the child context, and the same Environment is used for both parent and child contexts. See the SpringApplicationBuilder Javadoc for full details.

Application Availability

在平台上进行部署时,应用程序可以使用诸如 Kubernetes Probes之类的基础设施向平台提供有关其可用性的信息。Spring Boot 开箱即用地支持常用的 “liveness” 和 “readiness” 可用性状态。如果您正在使用 Spring Boot 的 “actuator” 支持,则这些状态将作为运行状况端点组公开。

When deployed on platforms, applications can provide information about their availability to the platform using infrastructure such as Kubernetes Probes. Spring Boot includes out-of-the box support for the commonly used “liveness” and “readiness” availability states. If you are using Spring Boot’s “actuator” support then these states are exposed as health endpoint groups.

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

In addition, you can also obtain availability states by injecting the ApplicationAvailability interface into your own beans.

Liveness State

应用程序的 “Liveness” 状态告知其内部状态是否允许其正确工作,或者在当前失败时自行恢复。“Liveness” 状态中断表示应用程序处于无法恢复的状态,基础设施应重新启动应用程序。

The “Liveness” state of an application tells whether its internal state allows it to work correctly, or recover by itself if it is currently failing. A broken “Liveness” state means that the application is in a state that it cannot recover from, and the infrastructure should restart the application.

一般来说,“活跃性”状态不应基于外部检查,例如 Health checks.如果这样做,一个失败的外部系统(数据库、Web API、外部缓存)将触发整个平台的大量重启和级联故障。

In general, the "Liveness" state should not be based on external checks, such as Health checks. If it did, a failing external system (a database, a Web API, an external cache) would trigger massive restarts and cascading failures across the platform.

Spring Boot 应用程序的内部状态主要由 Spring ApplicationContext 表示。如果应用程序上下文已成功启动,Spring Boot 假设应用程序处于有效状态。应用程序在上下文刷新后立即被视为活跃,请参阅 Spring Boot application lifecycle and related Application Events.

The internal state of Spring Boot applications is mostly represented by the Spring ApplicationContext. If the application context has started successfully, Spring Boot assumes that the application is in a valid state. An application is considered live as soon as the context has been refreshed, see Spring Boot application lifecycle and related Application Events.

Readiness State

应用程序的 “Readiness” 状态告知应用程序是否已准备好处理流量。“Readiness” 状态失败告知平台目前不应将流量路由到应用程序。这种情况通常发生在启动期间 CommandLineRunnerApplicationRunner 组件正在被处理,或在应用程序决定它太忙而无法处理额外流量的任何时候。

The “Readiness” state of an application tells whether the application is ready to handle traffic. A failing “Readiness” state tells the platform that it should not route traffic to the application for now. This typically happens during startup, while CommandLineRunner and ApplicationRunner components are being processed, or at any time if the application decides that it is too busy for additional traffic.

一旦调用应用程序和命令行运行程序,应用程序就会被认为已准备就绪,请参阅 Spring Boot application lifecycle and related Application Events.

An application is considered ready as soon as application and command-line runners have been called, see Spring Boot application lifecycle and related Application Events.

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

Tasks expected to run during startup should be executed by CommandLineRunner and ApplicationRunner components instead of using Spring component lifecycle callbacks such as @PostConstruct.

Managing the Application Availability State

应用程序组件可以通过注入 ApplicationAvailability 接口并调用其上的方法,随时检索当前可用性状态。更常见的是,应用程序需要监听状态更新或更新应用程序的状态。

Application components can retrieve the current availability state at any time, by injecting the ApplicationAvailability interface and calling methods on it. More often, applications will want to listen to state updates or update the state of the application.

例如,我们可以将应用程序的“就绪”状态导出到一个文件中,以便 Kubernetes “exec 探测”可以查看此文件:

For example, we can export the "Readiness" state of the application to a file so that a Kubernetes "exec Probe" can look at this file:

我们还可以更新应用程序的状态(当应用程序中断且无法恢复时):

We can also update the state of the application, when the application breaks and cannot recover:

Application Events and Listeners

除了常见的 Spring 框架事件,如 {@url-spring-framework-javadoc}/org/springframework/context/event/ContextRefreshedEvent.html[ContextRefreshedEvent],SpringApplication 发送一些附加应用程序事件。

In addition to the usual Spring Framework events, such as {url-spring-framework-javadoc}/org/springframework/context/event/ContextRefreshedEvent.html[ContextRefreshedEvent], a SpringApplication sends some additional application events.

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

Some events are actually triggered before the ApplicationContext is created, so you cannot register a listener on those as a @Bean. You can register them with the SpringApplication.addListeners(…​) method or the SpringApplicationBuilder.listeners(…​) method.

如果您希望这些侦听器自动注册,而不管应用程序创建方式如何,您可以将 META-INF/spring.factories 文件添加到您的项目中,并使用 org.springframework.context.ApplicationListener 键引用侦听器,如下例所示:

If you want those listeners to be registered automatically, regardless of the way the application is created, you can add a META-INF/spring.factories file to your project and reference your listener(s) by using the org.springframework.context.ApplicationListener key, as shown in the following example:

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

应用程序事件在您的应用程序运行时按以下顺序发送:

Application events are sent in the following order, as your application runs:

  1. An ApplicationStartingEvent is sent at the start of a run but before any processing, except for the registration of listeners and initializers.

  2. An ApplicationEnvironmentPreparedEvent is sent when the Environment to be used in the context is known but before the context is created.

  3. An ApplicationContextInitializedEvent is sent when the ApplicationContext is prepared and ApplicationContextInitializers have been called but before any bean definitions are loaded.

  4. An ApplicationPreparedEvent is sent just before the refresh is started but after bean definitions have been loaded.

  5. An ApplicationStartedEvent is sent after the context has been refreshed but before any application and command-line runners have been called.

  6. An AvailabilityChangeEvent is sent right after with LivenessState.CORRECT to indicate that the application is considered as live.

  7. An ApplicationReadyEvent is sent after any application and command-line runners have been called.

  8. An AvailabilityChangeEvent is sent right after with ReadinessState.ACCEPTING_TRAFFIC to indicate that the application is ready to service requests.

  9. An ApplicationFailedEvent is sent if there is an exception on startup.

上述列表仅包括 SpringApplicationEvent`s that are tied to a `SpringApplication。除此之外,还发布了 ApplicationPreparedEvent 之后和 ApplicationStartedEvent 之前的以下事件:

The above list only includes SpringApplicationEvent`s that are tied to a `SpringApplication. In addition to these, the following events are also published after ApplicationPreparedEvent and before ApplicationStartedEvent:

  • A WebServerInitializedEvent is sent after the WebServer is ready. ServletWebServerInitializedEvent and ReactiveWebServerInitializedEvent are the servlet and reactive variants respectively.

  • A ContextRefreshedEvent is sent when an ApplicationContext is refreshed.

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

You often need not use application events, but it can be handy to know that they exist. Internally, Spring Boot uses events to handle a variety of tasks.

默认情况下,事件侦听器不应该运行可能费时的任务,因为它们在同一线程中执行。请考虑使用 application and command-line runners 代替。

Event listeners should not run potentially lengthy tasks as they execute in the same thread by default. Consider using application and command-line runners instead.

Spring Framework 的事件发布机制发送应用程序事件。该机制的一部分确保发布到子上下文中的事件也发布到任何祖先上下文中的事件监听器。因此,如果您的应用程序使用 SpringApplication 实例的层次结构,则侦听器可能会收到同类型应用程序事件的多个实例。

Application events are sent by using Spring Framework’s event publishing mechanism. Part of this mechanism ensures that an event published to the listeners in a child context is also published to the listeners in any ancestor contexts. As a result of this, if your application uses a hierarchy of SpringApplication instances, a listener may receive multiple instances of the same type of application event.

若要使您的侦听器区分其上下文中的事件和后代上下文中的事件,应要求其应用程序上下文注入,然后将注入的上下文与事件的上下文进行比较。可以通过实现 ApplicationContextAware 来注入上下文,或者如果侦听器为一个 bean,则使用 @Autowired

To allow your listener to distinguish between an event for its context and an event for a descendant context, it should request that its application context is injected and then compare the injected context with the context of the event. The context can be injected by implementing ApplicationContextAware or, if the listener is a bean, by using @Autowired.

Web Environment

SpringApplication 会尝试代表您创建正确类型的 ApplicationContext。用于确定 WebApplicationType 的算法如下:

A SpringApplication attempts to create the right type of ApplicationContext on your behalf. The algorithm used to determine a WebApplicationType is the following:

  • If Spring MVC is present, an AnnotationConfigServletWebServerApplicationContext is used

  • If Spring MVC is not present and Spring WebFlux is present, an AnnotationConfigReactiveWebServerApplicationContext is used

  • Otherwise, AnnotationConfigApplicationContext is used

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

This means that if you are using Spring MVC and the new WebClient from Spring WebFlux in the same application, Spring MVC will be used by default. You can override that easily by calling setWebApplicationType(WebApplicationType).

您还可以通过调用 setApplicationContextFactory(…​) 完全控制所使用的 ApplicationContext 类型。

It is also possible to take complete control of the ApplicationContext type that is used by calling setApplicationContextFactory(…​).

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

It is often desirable to call setWebApplicationType(WebApplicationType.NONE) when using SpringApplication within a JUnit test.

Accessing Application Arguments

如果您需要访问传递给 SpringApplication.run(…​) 的应用程序参数,您可以注入 org.springframework.boot.ApplicationArguments bean。ApplicationArguments 接口提供了对原始 String[] 参数以及解析后的 optionnon-option 参数的访问,如下例所示:

If you need to access the application arguments that were passed to SpringApplication.run(…​), you can inject a org.springframework.boot.ApplicationArguments bean. The ApplicationArguments interface provides access to both the raw String[] arguments as well as parsed option and non-option arguments, as shown in the following example:

Spring Boot 还使用 Environment 在 Spring 中注册一个 CommandLinePropertySource。这允许您使用 @Value 注释注入单个应用程序参数。

Spring Boot also registers a CommandLinePropertySource with the Spring Environment. This lets you also inject single application arguments by using the @Value annotation.

Using the ApplicationRunner or CommandLineRunner

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

If you need to run some specific code once the SpringApplication has started, you can implement the ApplicationRunner or CommandLineRunner interfaces. Both interfaces work in the same way and offer a single run method, which is called just before SpringApplication.run(…​) completes.

此协定非常适合在应用程序启动后但开始接受流量之前运行的任务。

This contract is well suited for tasks that should run after application startup but before it starts accepting traffic.

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

The CommandLineRunner interfaces provides access to application arguments as a string array, whereas the ApplicationRunner uses the ApplicationArguments interface discussed earlier. The following example shows a CommandLineRunner with a run method:

如果定义了必须按特定顺序调用的多个 CommandLineRunnerApplicationRunner bean,则您还可以实现 org.springframework.core.Ordered 接口或使用 org.springframework.core.annotation.Order 注释。

If several CommandLineRunner or ApplicationRunner beans are defined that must be called in a specific order, you can additionally implement the org.springframework.core.Ordered interface or use the org.springframework.core.annotation.Order annotation.

Application Exit

每个 SpringApplication 都在 JVM 中注册了一个关闭挂钩,以确保 ApplicationContext 在退出时正常关闭。可以使用所有标准 Spring 生命周期回调(例如 DisposableBean 接口或 @PreDestroy 注释)。

Each SpringApplication registers a shutdown hook with the JVM to ensure that the ApplicationContext closes gracefully on exit. All the standard Spring lifecycle callbacks (such as the DisposableBean interface or the @PreDestroy annotation) can be used.

此外,如果 bean 希望在调用 SpringApplication.exit() 时返回特定的退出代码,则它们可以实现 org.springframework.boot.ExitCodeGenerator 接口。然后,此退出代码可传递给 System.exit(),以作为状态代码返回,如下例所示:

In addition, beans may implement the org.springframework.boot.ExitCodeGenerator interface if they wish to return a specific exit code when SpringApplication.exit() is called. This exit code can then be passed to System.exit() to return it as a status code, as shown in the following example:

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

Also, the ExitCodeGenerator interface may be implemented by exceptions. When such an exception is encountered, Spring Boot returns the exit code provided by the implemented getExitCode() method.

如果有多个 ExitCodeGenerator,则使用生成的第一个非零退出代码。若要控制调用生成器的顺序,还可以实现 org.springframework.core.Ordered 接口或使用 org.springframework.core.annotation.Order 注释。

If there is more than one ExitCodeGenerator, the first non-zero exit code that is generated is used. To control the order in which the generators are called, additionally implement the org.springframework.core.Ordered interface or use the org.springframework.core.annotation.Order annotation.

Admin Features

可以通过指定 configprop:spring.application.admin.enabled[] 属性来为应用程序启用与管理员相关的功能。此操作会公开平台上的 {code-spring-boot-src}/admin/SpringApplicationAdminMXBean.java[SpringApplicationAdminMXBean]。你可以使用此功能远程管理你的 Spring Boot 应用程序。对于任何服务包装实现,此功能也很实用。

It is possible to enable admin-related features for the application by specifying the configprop:spring.application.admin.enabled[] property. This exposes the {code-spring-boot-src}/admin/SpringApplicationAdminMXBean.java[SpringApplicationAdminMXBean] on the platform MBeanServer. You could use this feature to administer your Spring Boot application remotely. This feature could also be useful for any service wrapper implementation.

如果你想了解应用程序正在运行的 HTTP 端口,请使用键 local.server.port 获取属性。

If you want to know on which HTTP port the application is running, get the property with a key of local.server.port.

Application Startup tracking

在应用程序启动期间,SpringApplicationApplicationContext 执行了与应用程序生命周期、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 对象跟踪应用程序启动序列]。此数据可为分析目的收集,或者只是为了更好地了解应用程序启动过程。

During the application startup, the SpringApplication and the ApplicationContext perform many tasks related to the application lifecycle, the beans lifecycle or even processing application events. With {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[allows you to track the application startup sequence with StartupStep objects]. This data can be collected for profiling purposes, or just to have a better understanding of an application startup process.

在设置 SpringApplication 实例时,你可以选择 ApplicationStartup 实现。例如,要使用 BufferingApplicationStartup,你可以编写:

You can choose an ApplicationStartup implementation when setting up the SpringApplication instance. For example, to use the BufferingApplicationStartup, you could write:

第一个可用的实现 FlightRecorderApplicationStartup 由 Spring Framework 提供。它会向 Java Flight Recorder 会话添加特定的 Spring 启动事件,并且旨在分析应用程序以及将它们的 Spring context 生命周期与 JVM 事件(例如分配、GC、类加载等)关联起来。进行配置后,你可以通过运行启用了 Flight Recorder 的应用程序来记录数据:

The first available implementation, FlightRecorderApplicationStartup is provided by Spring Framework. It adds Spring-specific startup events to a Java Flight Recorder session and is meant for profiling applications and correlating their Spring context lifecycle with JVM events (such as allocations, GCs, class loading…​). Once configured, you can record data by running the application with the Flight Recorder enabled:

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

Spring Boot 随附了 BufferingApplicationStartup 变体;此实现旨在缓冲启动步骤并将它们放入外部指标系统。应用程序可以在任何组件中请求类型为 BufferingApplicationStartup 的 bean。

Spring Boot ships with the BufferingApplicationStartup variant; this implementation is meant for buffering the startup steps and draining them into an external metrics system. Applications can ask for the bean of type BufferingApplicationStartup in any component.

Spring Boot 还可以配置为公开一个 startup endpoint,它将此信息作为 JSON 文档提供。

Spring Boot can also be configured to expose a startup endpoint that provides this information as a JSON document.

Virtual threads

如果你在 Java 21 或更高版本上运行,你可以通过将属性 configprop:spring.threads.virtual.enabled[] 设置为 true 来启用虚拟线程。

If you’re running on Java 21 or up, you can enable virtual threads by setting the property configprop:spring.threads.virtual.enabled[] to true.

在为你的应用程序启用此选项之前,你应考虑 reading the official Java virtual threads documentation。在某些情况下,应用程序可能会因为“固定虚拟线程”而导致更低的吞吐量;此页面还说明了如何使用 JDK Flight Recorder 或 jcmd CLI 检测此类情况。

Before turning on this option for your application, you should consider reading the official Java virtual threads documentation. In some cases, applications can experience lower throughput because of "Pinned Virtual Threads"; this page also explains how to detect such cases with JDK Flight Recorder or the jcmd CLI.

虚拟线程的一个副作用是它们是守护线程。如果它的所有线程都是守护线程,JVM 将会退出。当你依赖 @Scheduled bean(例如,保持应用程序运行)时,此行为可能会出现问题。如果你使用虚拟线程,调度线程是一个虚拟线程,因此是一个守护线程,并且无法保持 JVM 运行。这不仅会影响调度,而且可能同样适用于其他技术。为了在所有情况下保持 JVM 运行,建议将属性 configprop:spring.main.keep-alive[] 设置为 true。这确保了 JVM 将处于活动状态,即使所有线程都是虚拟线程也是如此。

One side effect of virtual threads is that they are daemon threads. A JVM will exit if all of its threads are daemon threads. This behavior can be a problem when you rely on @Scheduled beans, for example, to keep your application alive. If you use virtual threads, the scheduler thread is a virtual thread and therefore a daemon thread and won’t keep the JVM alive. This not only affects scheduling and can be the case with other technologies too. To keep the JVM running in all cases, it is recommended to set the property configprop:spring.main.keep-alive[] to true. This ensures that the JVM is kept alive, even if all threads are virtual threads.