文章摘要(AI生成)
核心功能本节深入探讨 Spring Boot 的细节。在这里,您可以了解您可能想要使用和自定义的主要功能。如果您还没有这样做,您可能需要阅读“ getting-started.html ”和“ using.html ”部分,这样您就有了良好的基础知识。1. SpringApplication该类Sp
核心功能
本节深入探讨 Spring Boot 的细节。在这里,您可以了解您可能想要使用和自定义的主要功能。如果您还没有这样做,您可能需要阅读“ getting-started.html ”和“ using.html ”部分,这样您就有了良好的基础知识。
1. SpringApplication
该类SpringApplication
提供了一种方便的方法来引导从main()
方法启动的 Spring 应用程序。在许多情况下,您可以委托给静态SpringApplication.run
方法,如下例所示:
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
当您的应用程序启动时,您应该会看到类似于以下输出的内容:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.1.1)
2023-06-22T12:08:14.396Z INFO 22973 --- [ main] o.s.b.d.f.s.MyApplication : Starting MyApplication using Java 17.0.7 with PID 22973 (/opt/apps/myapp.jar started by myuser in /opt/apps/)
2023-06-22T12:08:14.413Z INFO 22973 --- [ main] o.s.b.d.f.s.MyApplication : No active profile set, falling back to 1 default profile: "default"
2023-06-22T12:08:16.739Z INFO 22973 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2023-06-22T12:08:16.765Z INFO 22973 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2023-06-22T12:08:16.766Z INFO 22973 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.10]
2023-06-22T12:08:17.261Z INFO 22973 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2023-06-22T12:08:17.280Z INFO 22973 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2705 ms
2023-06-22T12:08:18.801Z INFO 22973 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2023-06-22T12:08:18.840Z INFO 22973 --- [ main] o.s.b.d.f.s.MyApplication : Started MyApplication in 5.871 seconds (process running for 7.263)
2023-06-22T12:08:18.916Z INFO 22973 --- [ionShutdownHook] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
默认情况下,会显示INFO
日志,包括一些相关的启动详细信息,例如启动应用程序的用户。如果您需要除INFO
之外的日志级别,您可以设置它,如日志级别中所述。应用程序版本是使用主应用程序类包中的实现版本确定的。spring.main.log-startup-info
设置为false
可以关闭启动信息记录。这也将关闭应用程序活动配置文件的日志记录。
要在启动期间添加额外的日志记录,您可以在SpringApplication
的子类中重写logStartupInfo(boolean)
方法
1.1. 启动失败
如果您的应用程序无法启动,注册FailureAnalyzers
将有机会提供专门的错误消息和解决问题的具体措施。例如,如果您在端口上启动 Web 应用程序8080
并且该端口已在使用中,您应该会看到类似于以下消息的内容:
***************************
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
实现,您可以添加自己的.
如果没有故障分析器能够处理异常,您仍然可以显示完整的条件报告以更好地了解问题所在。为此,您需要为org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
启用debug
属性或启用DEBUG
日志记录。
例如,如果您使用java -jar
运行应用程序,则可以按如下方式启用debug
:
$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug
1.2. 延迟初始化
SpringApplication
允许延迟初始化应用程序。当启用延迟初始化时,bean 会在需要时创建,而不是在应用程序启动期间创建。因此,启用延迟初始化可以减少应用程序启动所需的时间。在 Web 应用程序中,启用延迟初始化将导致许多与 Web 相关的 bean 在收到 HTTP 请求之前不会被初始化。
延迟初始化的一个缺点是它会延迟应用程序问题的发现。如果配置错误的 bean 被延迟初始化,则在启动期间将不再发生故障,并且只有在 bean 初始化时问题才会变得明显。还必须注意确保 JVM 有足够的内存来容纳应用程序的所有 bean,而不仅仅是那些在启动期间初始化的 bean。由于这些原因,默认情况下不启用延迟初始化,建议在启用延迟初始化之前对 JVM 的堆大小进行微调。
可以在SpringApplication
使用SpringApplicationBuilder
或setLazyInitialization
的方法lazyInitialization
方法以编程方式启用延迟初始化。或者,可以使用spring.main.lazy-initialization
以下示例中所示的属性启用它:
spring.main.lazy-initialization=true
如果您想在应用程序的其余部分使用延迟初始化的同时禁用某些 bean 的延迟初始化,您可以使用@Lazy(false)
注解将它们的延迟属性显式设置为 false。
1.3. 自定义 Banner
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 版本。例如2.7.3 . |
${spring-boot.formatted-version} |
您正在使用的 Spring Boot 版本,已格式化以供显示(用括号括起来并以v 为前缀)。例如(v2.7.3) . |
${Ansi.NAME} (或${AnsiColor.NAME} , ${AnsiBackground.NAME} , ${AnsiStyle.NAME} ) |
ANSI 转义码NAME 的名称在哪里。详情请参阅AnsiPropertySource 。 |
${application.title} |
应用程序的标题,如MANIFEST.MF . 例如Implementation-Title: MyApp 打印为MyApp . |
如果您想以编程方式生成banner,可以使用SpringApplication.setBanner(…)
方法。使用org.springframework.boot.Banner
接口并实现自定义的printBanner()
方法。
您还可以使用该spring.main.banner-mode
属性来确定是否必须在System.out
( console
) 上、日志上 ( log
) 打印banner或根本不生成 ( off
)。
打印的banner将以下名称:springBootBanner
注册为单例 bean .
${application.version}
和${application.formatted-version}
属性仅在您使用 Spring Boot 启动器时可用。如果您正在运行解压缩的 jar 并以java -cp <classpath> <mainclass>
.这就是为什么我们建议您始终使用java org.springframework.boot.loader.JarLauncher
. application.*
这将在构建类路径和启动应用程序之前初始化横幅变量。
1.4. 自定义 SpringApplication
如果SpringApplication
默认值不符合您的口味,您可以改为创建本地实例并对其进行自定义。例如,要关闭横幅,您可以编写:
@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
类。
也可以SpringApplication
使用application.properties
文件进行配置。有关详细信息,请参阅*外部化配置*。
有关配置选项的完整列表,请参阅SpringApplication
Javadoc。
1.5. 流利构建器 API
如果您需要构建ApplicationContext
层次结构(具有父/子关系的多个上下文),或者如果您更喜欢使用“流利的”构建器 API,则可以使用SpringApplicationBuilder
.
SpringApplicationBuilder
允许您将多个方法调用以及包含parent
以及child
的方法调用,通过创建层次结构的方法链接在一起,如以下示例所示:
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);
创建层次结构ApplicationContext
时有一些限制。例如,Web 组件必须包含在子上下文中,并且有相同的Environment
用于父上下文和子上下文。有关完整的详细信息,请参阅SpringApplicationBuilder
Javadoc。
1.6. 应用程序可用性
当部署在平台上时,应用程序可以使用Kubernetes Probes等基础设施向平台提供有关其可用性的信息。Spring Boot 包括了对常用“liveness”和“readiness”可用性状态的开箱即用支持。如果您使用 Spring Boot 的“执行器”支持,那么这些状态将作为健康端点组公开。
此外,您还可以通过将ApplicationAvailability
接口注入到自己的 bean 中来获取可用性状态。
1.6.1. 活跃状态
应用程序的“活跃度”状态表明其内部状态是否允许其正常工作,或者如果当前失败则自行恢复。损坏的“活动”状态意味着应用程序处于无法恢复的状态,基础设施应重新启动应用程序。
一般来说,“Liveness”状态不应基于外部检查,例如Health 检查。如果是这样,一个失败的外部系统(数据库、Web API、外部缓存)将触发大规模重启和跨平台的级联故障
Spring Boot 应用程序的内部状态主要由 Spring ApplicationContext
表示。如果应用程序上下文已成功启动,Spring Boot 假定应用程序处于有效状态。一旦上下文被刷新,应用程序就被认为是活动的,请参阅Spring Boot 应用程序生命周期和相关的应用程序事件。
1.6.2. 准备状态
应用程序的“就绪”状态表明应用程序是否已准备好处理流量。失败的“就绪”状态告诉平台它现在不应该将流量路由到应用程序。这通常发生在启动期间、处理CommandLineRunner
和ApplicationRunner
组件时,或者在应用程序决定它太忙而无法获得额外流量的任何时候。
一旦调用了应用程序和命令行运行器,就认为应用程序已准备就绪,请参阅Spring Boot 应用程序生命周期和相关的应用程序事件。
在启动期间运行的任务应该由CommandLineRunner
和ApplicationRunner
组件执行,而不是使用 Spring 组件生命周期回调,例如@PostConstruct
.
1.6.3. 管理应用程序可用性状态
应用程序组件可以随时检索当前的可用性状态,方法是注入ApplicationAvailability
接口并在其上调用方法。更多时候,应用程序会想要监听状态更新或更新应用程序的状态。
例如,我们可以将应用程序的“Readiness”状态导出到一个文件中,以便 Kubernetes “exec Probe”可以查看这个文件:
@Component
public class MyReadinessStateExporter {
@EventListener
public void onStateChange(AvailabilityChangeEvent<ReadinessState> event) {
switch (event.getState()) {
case ACCEPTING_TRAFFIC:
// create file /tmp/healthy
break;
case REFUSING_TRAFFIC:
// remove file /tmp/healthy
break;
}
}
}
我们还可以在应用中断且无法恢复时更新应用的状态:
@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 为“Liveness”和“Readiness”提供 Kubernetes HTTP 探测。您可以在专用部分中获得有关在 Kubernetes 上部署 Spring Boot 应用程序的更多指导。
1.7. 应用程序事件和监听器
除了常见的 Spring Framework 事件,例如ContextRefreshedEvent
, aSpringApplication
发送一些额外的应用程序事件。
某些事件实际上ApplicationContext
是在创建之前触发的,因此您不能在这些事件上将侦听器注册为@Bean
. SpringApplication.addListeners(…)
您可以使用方法或方法注册它们SpringApplicationBuilder.listeners(…)
。如果您希望自动注册这些侦听器,无论应用程序的创建方式如何,您都可以将META-INF/spring.factories
文件添加到您的项目并使用org.springframework.context.ApplicationListener
密钥引用您的侦听器,如以下示例所示:org.springframework.context.ApplicationListener=com.example.project.MyListener
当您的应用程序运行时,应用程序事件按以下顺序发送:
- 在运行开始时但在任何处理之前发送
ApplicationStartingEvent
,除了侦听器和初始化程序的注册。 - 当在上下文中使用的
Environment
已知但在创建上下文之前发送ApplicationEnvironmentPreparedEvent
。 - 当
ApplicationContext
准备好并调用 ApplicationContextInitializers 但在加载任何 bean 定义之前发送ApplicationContextInitializedEvent
。 - 在刷新开始之前但在加载 bean 定义之后发送
ApplicationPreparedEvent
。 - 在上下文刷新之后但在调用任何应用程序和命令行运行程序之前发送
ApplicationStartedEvent
。 - 在
LivenessState.CORRECT
之后立即发送AvailabilityChangeEvent
,表明应用程序被认为是活动的。 - 在调用任何应用程序和命令行运行程序后发送
ApplicationReadyEvent
。 - 在
ReadinessState.ACCEPTING_TRAFFIC
之后立即发送AvailabilityChangeEvent
,表示应用程序已准备好为请求提供服务。 - 如果启动时出现异常,则发送一个
ApplicationFailedEvent
。
上面的列表仅包括与 SpringApplication
绑定的SpringApplicationEvent
。除此之外,在ApplicationPreparedEvent
之后和ApplicationStartedEvent
之前还发布了以下事件:
- 在
WebServer
准备好 后发送WebServerInitializedEvent
。ServletWebServerInitializedEvent
和ReactiveWebServerInitializedEvent
分别是 servlet 和响应式变体。 - 在
ApplicationContext
刷新时发送ContextRefreshedEvent
。
您通常不需要使用应用程序事件,但知道它们的存在会很方便。在内部,Spring Boot 使用事件来处理各种任务。
默认情况下,事件侦听器不应运行可能冗长的任务,因为它们默认在同一线程中执行。考虑改用应用程序和命令行运行器。
应用程序事件是使用 Spring Framework 的事件发布机制发送的。该机制的一部分确保在子上下文中发布给侦听器的事件也发布给任何祖先上下文中的侦听器。因此,如果您的应用程序使用SpringApplication
实例层次结构,则侦听器可能会接收到相同类型的应用程序事件的多个实例。
为了让您的侦听器能够区分其上下文的事件和后代上下文的事件,它应该请求注入其应用程序上下文,然后将注入的上下文与事件的上下文进行比较。可以通过实现ApplicationContextAware
来注入上下文,除此之外,如果侦听器是 bean,则可以使用@Autowired
.
1.8. 网络环境
SpringApplication
尝试代表您创建正确的ApplicationContext
类型。用于确定WebApplicationType
的算法如下:
- 如果存在 Spring MVC,则使用
AnnotationConfigServletWebServerApplicationContext
- 如果 Spring MVC 不存在而 Spring WebFlux 存在,则使用
AnnotationConfigReactiveWebServerApplicationContext
- 否则,使用
AnnotationConfigApplicationContext
这意味着如果您WebClient
在同一个应用程序中使用 Spring MVC 和Spring WebFlux ,则默认情况下将使用 Spring MVC。您可以通过调用setWebApplicationType(WebApplicationType)
轻松覆盖它。
也可以通过调用setApplicationContextClass(…)
来完全控制使用的类型ApplicationContext
。
在 JUnit 测试中 setWebApplicationType(WebApplicationType.NONE)
使用时 通常需要调用。SpringApplication
1.9. 访问应用程序参数
如果您需要访问传递给SpringApplication.run(…)
的应用程序参数,您可以注入一个org.springframework.boot.ApplicationArguments
bean。该ApplicationArguments
接口提供对原始String[]
参数的访问以及option
和non-option
参数的解析,如以下示例所示:
@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
注解注入单个应用程序参数。
1.10. 使用 ApplicationRunner 或 CommandLineRunner
如果您需要在SpringApplication
启动后运行某些特定代码,您可以实现ApplicationRunner
或CommandLineRunner
接口。两个接口以相同的方式工作并提供一个run
方法,该方法在SpringApplication.run(…)
完成之前调用。
该合约非常适合应在应用程序启动之后但开始接受流量之前运行的任务。
接口CommandLineRunner
以字符串数组的形式提供对应用程序参数的访问,而ApplicationRunner
使用前面讨论的接口ApplicationArguments
。以下示例显示了一个CommandLineRunner
带有run
方法的实现:
@Component
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) {
// Do something...
}
}
如果定义了CommandLineRunner
或ApplicationRunner
必须按特定顺序调用的多个,则可以另外实现接口org.springframework.core.Ordered
或org.springframework.core.annotation.Order
使用注解。
1.11. 应用程序退出
每个SpringApplication
都向 JVM 注册一个关闭钩子,以确保在ApplicationContext
退出时优雅地关闭。可以使用所有标准的 Spring 生命周期回调(例如DisposableBean
接口或@PreDestroy
注解)。
此外,如果希望在被SpringApplication.exit()
调用时返回特定的退出代码,它们可以实现org.springframework.boot.ExitCodeGenerator
接口。然后可以将此退出代码传递给System.exit()
以将其作为状态代码返回,如以下示例所示:
@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
有多个,则使用生成的第一个非零退出代码。要控制调用生成器的顺序,请另外实现org.springframework.core.Ordered
接口或使用org.springframework.core.annotation.Order
注释。
1.12. 管理员功能
可以通过指定spring.application.admin.enabled
属性为应用程序启用与管理相关的功能。这暴露了SpringApplicationAdminMXBean
平台上的MBeanServer
. 您可以使用此功能远程管理您的 Spring Boot 应用程序。此功能也可用于任何服务包装器实现。
如果您想知道应用程序在哪个 HTTP 端口上运行,请使用local.server.port
.
1.13. 应用程序启动跟踪
在应用程序启动期间,SpringApplication
和ApplicationContext
执行了许多与应用程序生命周期、bean 生命周期甚至处理应用程序事件相关的任务。通过ApplicationStartup
,Spring Framework允许您使用StartupStep
对象跟踪应用程序的启动顺序。可以出于分析目的收集这些数据,或者只是为了更好地了解应用程序启动过程。
您可以在设置SpringApplication
实例时选择实现ApplicationStartup
。例如,要使用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 也可以配置为公开一个以 JSON 文档形式提供此信息的[startup
端点。](
评论区