7.1. SpringApplication
7.1. Spring应用程序
SpringApplication
类提供了一种方便的方式来引导从main()
方法启动的 Spring 应用程序。在许多情况下,您可以委托给静态SpringApplication.run
方法,如以下示例所示:
当您的应用程序启动时,您应该看到类似于以下输出的内容:
要在启动期间添加额外的日志记录,您可以在
SpringApplication
的子类中重写logStartupInfo(boolean)
。
7.1.1. 启动失败
如果您的应用程序无法启动,注册的FailureAnalyzers
可以提供专门的错误消息和解决问题的具体操作。例如,如果您在8080
端口上启动 Web 应用程序并且该端口已在使用中,您应该会看到类似于以下消息的内容:
例如,如果您使用java -jar
运行应用程序,则可以按如下方式启用debug
属性:
7.1.2. 延迟初始化
SpringApplication
允许应用程序延迟初始化。当启用延迟初始化时,bean 将在需要时创建,而不是在应用程序启动期间创建。因此,启用延迟初始化可以减少应用程序启动所需的时间。在 Web 应用程序中,启用延迟初始化将导致许多与 Web 相关的 Bean 在收到 HTTP 请求之前不会被初始化。
延迟初始化的一个缺点是它可能会延迟发现应用程序的问题。如果延迟初始化配置错误的 bean,则在启动期间将不再发生故障,并且只有在初始化 bean 时问题才会变得明显。还必须注意确保 JVM 有足够的内存来容纳应用程序的所有 Bean,而不仅仅是那些在启动期间初始化的 Bean。由于这些原因,默认情况下不启用延迟初始化,建议在启用延迟初始化之前微调 JVM 的堆大小。
可以使用SpringApplicationBuilder
中的lazyInitialization
方法或SpringApplication
中的setLazyInitialization
方法以编程方式启用延迟初始化。或者,可以使用spring.main.lazy-initialization
属性来启用它,如以下示例所示:
如果要禁用某些 bean 的延迟初始化,同时对应用程序的其余部分使用延迟初始化,则可以使用
@Lazy(false)
注释显式将其延迟属性设置为 false 。
7.1.3. 自定义横幅
可以通过将banner.txt
文件添加到类路径或将spring.banner.location
属性设置为此类文件的位置来更改启动时打印的横幅。如果文件的编码不是 UTF-8,则需要设置spring.banner.charset
.
在banner.txt
文件中,您可以使用Environment
中可用的任何键以及以下任何占位符:
变量
描述
${application.version}
您的应用程序的版本号,如 中声明的那样MANIFEST.MF
。例如,Implementation-Version: 1.0
打印为1.0
.
${application.formatted-version}
您的应用程序的版本号,如 MANIFEST.MF
中声明的和显示格式的(用方括号括起来并以v
为前缀)。例如(v1.0)
。
${spring-boot.version}
您正在使用的 Spring Boot 版本。例如3.2.0
。
${spring-boot.formatted-version}
您正在使用的 Spring Boot 版本,已格式化以供显示(用方括号括起来并以 v
为前缀)。例如(v3.2.0)
。
${Ansi.NAME}
(或者${AnsiColor.NAME}
,${AnsiBackground.NAME}
,${AnsiStyle.NAME}
)
其中 NAME 是 ANSI 转义码的名称。有关详细信息,请参阅 AnsiPropertySource
。
${application.title}
您的应用的标题,如 MANIFEST.MF
中声明的那样。例如Implementation-Title: MyApp
打印为MyApp
.
SpringApplication.setBanner(…)
如果您想以编程方式生成横幅,可以使用 该方法。使用该org.springframework.boot.Banner
接口并实现您自己的printBanner()
方法。
您还可以使用spring.main.banner-mode
属性来确定是否必须在System.out
( console
)打印横幅、将其发送到配置的记录器 ( log
),还是根本不生成横幅 ( off
)。
打印的横幅以以下名称注册为单例 bean:springBootBanner
。
仅当您将
java -jar
或java -cp
与 Spring Boot 启动器一起使用时,application.title
、application.version
和application.formatted-version
属性才可用。如果您运行解压的 jar 并使用java -cp
启动它或将应用程序作为本机映像运行,则不会解析这些值。如果使用
application.
属性文件,则需要使用java -jar
将应用程序作为打包的 jar 启动,或使用java org.springframework.boot.loader.launch.JarLauncher
作为解压的 jar 启动。这将初始化application
。这将会在构建类路径和启动应用程序之前,设置横幅属性。
7.1.4. 定制 SpringApplication
如果SpringApplication
的默认设置不符合您的口味,您可以创建一个本地实例并对其进行自定义。例如,要关闭横幅,您可以编写:
传递给
SpringApplication
构造函数的参数是 Spring bean 的配置源。在大多数情况下,这些是对@Configuration
类的引用,但它们也可以是直接引用@Component
类。
7.1.5. Fluent 构建器 API
如果您需要构建层次结构(具有父/子关系的多个上下文)ApplicationContext
,或者如果您更喜欢使用“流畅”构建器 API,则可以使用SpringApplicationBuilder
.
SpringApplicationBuilder
允许您将多个方法调用链接在一起,并包含可让您创建层次结构的parent
和child
方法,如以下示例所示:
7.1.6. 应用程序可用性
此外,您还可以通过将ApplicationAvailability
接口注入到您自己的bean中来获取可用性状态。
活性状态
应用程序的“活跃”状态表明其内部状态是否允许其正常工作,或者在当前发生故障时自行恢复。损坏的“Liveness”状态意味着应用程序处于无法恢复的状态,基础设施应该重新启动应用程序。
准备状态
应用程序的“就绪”状态表明应用程序是否已准备好处理流量。失败的“就绪”状态告诉平台它现在不应该将流量路由到应用程序。这通常发生在启动期间、处理CommandLineRunner
和ApplicationRunner
组件时,或者在应用程序认为太忙而无法承受额外流量的任何时间。
预计在启动期间运行的任务应该由
CommandLineRunner
和ApplicationRunner
组件执行,而不是使用 Spring 组件生命周期回调,例如@PostConstruct
.
管理应用程序可用性状态
应用程序组件可以通过注入接口ApplicationAvailability
并调用其方法来随时检索当前的可用性状态。更常见的是,应用程序希望监听状态更新或更新应用程序的状态。
例如,我们可以将应用程序的“Readiness”状态导出到一个文件,以便 Kubernetes“exec Probe”可以查看该文件:
当应用程序中断且无法恢复时,我们还可以更新应用程序的状态:
7.1.7. 应用程序事件和侦听器
有些事件实际上是在创建
ApplicationContext
之前触发的,因此您无法将这些事件的侦听器注册为@Bean
. 您可以使用SpringApplication.addListeners(…)
方法或SpringApplicationBuilder.listeners(…)
方法来注册它们。如果您希望自动注册这些侦听器,无论应用程序的创建方式如何,您都可以将文件添加META-INF/spring.factories
到项目中并使用org.springframework.context.ApplicationListener
这个key 引用您的侦听器,如以下示例所示:org.springframework.context.ApplicationListener=com.example.project.MyListener
当您的应用程序运行时,应用程序事件按以下顺序发送:
在运行开始时但在任何处理之前发送
ApplicationStartingEvent
,监听器和初始化程序的注册除外。当已知上下文中要使用的
Environment
时但在创建上下文之前,会发送ApplicationEnvironmentPreparedEvent
。当
ApplicationContext
准备好并且调用 ApplicationContextInitializers 时但在加载任何 bean 定义之前发送ApplicationContextInitializedEvent
。在上下文刷新开始之前、bean 定义加载之后发送
ApplicationPreparedEvent
。在刷新上下文之后但在调用任何应用程序和命令行运行程序之前发送
ApplicationStartedEvent
。在
LivenessState.CORRECT
之后立即发送AvailabilityChangeEvent
,表示该应用程序被视为有效。紧随
ReadinessState.ACCEPTING_TRAFFIC
之后发送AvailabilityChangeEvent
,表示应用程序已准备好处理请求。如果启动时出现异常,则会发送一个
ApplicationFailedEvent
。
上面的列表仅包含与SpringApplication
绑定的 SpringApplicationEvent
s 。除此之外,以下事件也在ApplicationStartedEvent
之前和ApplicationPreparedEvent
之后发布:
WebServer
就绪之后后发送WebServerInitializedEvent
。ServletWebServerInitializedEvent
和ReactiveWebServerInitializedEvent
分别对应 servlet 和响应式变体的发送事件。当
ApplicationContext
刷新时发送ContextRefreshedEvent
。
您通常不需要使用应用程序事件,但知道它们的存在会很方便。在内部,Spring Boot 使用事件来处理各种任务。
应用程序事件是通过使用Spring框架的事件发布机制来发送的。此机制的一部分确保发布到子上下文中的侦听器的事件也发布到任何祖先上下文中的侦听器。因此,如果您的应用程序使用SpringApplication
实例层次结构,侦听器可能会接收同一类型应用程序事件的多个实例。
为了让您的侦听器区分其上下文的事件和后代上下文的事件,它应该请求注入其应用程序上下文,然后将注入的上下文与事件的上下文进行比较。可以通过实现注入上下文ApplicationContextAware
,或者如果侦听器是 bean,则可以使用@Autowired
.
7.1.8. 网络环境
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)
。
7.1.9. 访问应用程序参数
如果您需要访问传递给SpringApplication.run(…)
的应用程序参数,您可以注入一个org.springframework.boot.ApplicationArguments
bean。ApplicationArguments
接口提供对原始String[]
参数以及解析后的option
和non-option
参数的访问,如以下示例所示:
Spring Boot 还向 Spring
Environment
注册了一个CommandLinePropertySource
. 这使您还可以使用@Value
注释注入单个应用程序参数。
7.1.10. 使用 ApplicationRunner 或 CommandLineRunner
如果您需要在SpringApplication
启动后运行某些特定代码,您可以实现ApplicationRunner
或CommandLineRunner
接口。两个接口以相同的方式工作,并提供一个run
方法,该方法在SpringApplication.run(…)
完成之前调用。
该合约非常适合应在应用程序启动后但开始接受流量之前运行的任务。
这些CommandLineRunner
接口以字符串数组的形式提供对应用程序参数的访问,而 ApplicationRunner
则使用前面讨论的ApplicationArguments
接口。以下示例显示了CommandLineRunner
的run
方法:
爪哇
科特林
如果定义了多个CommandLineRunner
或ApplicationRunner
必须按特定顺序调用的 bean,则可以另外实现该org.springframework.core.Ordered
接口或使用org.springframework.core.annotation.Order
注释。
7.1.11. 应用程序退出
每个进程SpringApplication
都会向 JVM 注册一个关闭钩子,以确保ApplicationContext
在退出时正常关闭。可以使用所有标准 Spring 生命周期回调(例如DisposableBean
接口或@PreDestroy
注释)。
此外,如果希望在SpringApplication.exit()
调用时返回特定的退出代码,则bean 可以实现org.springframework.boot.ExitCodeGenerator
接口。然后可以传递此退出代码System.exit()
以将其作为状态代码返回,如以下示例所示:
此外,该ExitCodeGenerator
接口可以通过异常来实现。当遇到此类异常时,Spring Boot 将返回所实现的getExitCode()
方法提供的退出代码。
如果有多个ExitCodeGenerator
,则使用生成的第一个非零退出代码。要控制生成器的调用顺序,请另外实现接口org.springframework.core.Ordered
或使用org.springframework.core.annotation.Order
注释。
7.1.12. 管理功能
如果您想知道应用程序在哪个 HTTP 端口上运行,请获取键为
local.server.port
的属性。
7.1.13. 应用程序启动跟踪
可以在设置SpringApplication
实例时选择实现ApplicationStartup
您。例如,要使用BufferingApplicationStartup
,您可以编写:
第一个可用的实现FlightRecorderApplicationStartup
是由 Spring 框架提供的。它将 Spring 特定的启动事件添加到 Java Flight Recorder 会话中,旨在分析应用程序并将其 Spring 上下文生命周期与 JVM 事件(例如分配、GC、类加载……)相关联。配置完成后,您可以通过在启用飞行记录器的情况下运行应用程序来记录数据:
Spring Boot 附带了该BufferingApplicationStartup
变体;此实现旨在缓冲启动步骤并将其排入外部指标系统。应用程序可以请求BufferingApplicationStartup
任何组件中类型的 bean。
7.1.14. 虚拟线程
如果您在 Java 21 或更高版本上运行,则可以通过将该属性设置spring.threads.virtual.enabled
为true
来启用虚拟线程。
虚拟线程的一个副作用是这些线程是守护线程。如果没有非守护线程,JVM 将退出。当您依赖(例如)
@Scheduled
bean 来保持应用程序处于活动状态时,此行为可能会成为问题。如果您使用虚拟线程,则调度程序线程是虚拟线程,因此是守护程序线程,并且不会使 JVM 保持活动状态。这不仅会影响调度,其他技术也可能出现这种情况!为了使 JVM 在所有情况下都保持运行,建议将该属性设置spring.main.keep-alive
为true
。这可以确保 JVM 保持活动状态,即使所有线程都是虚拟线程。
最后更新于
这有帮助吗?