SpringApplication类提供了一个方便的方式来引导Spring应用程序,它就是从main()函数开始。在许多情况下,您可以委托给静态的SpringApplication.run方法,如以下示例所示:

  1. public static void main(String[] args) {
  2. SpringApplication.run(MySpringConfiguration.class, args);
  3. }

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

  1. . ____ _ __ _ _
  2. /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
  3. ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
  4. \\/ ___)| |_)| | | | | || (_| | ) ) ) )
  5. ' |____| .__|_| |_|_| |_\__, | / / / /
  6. =========|_|==============|___/=/_/_/_/
  7. :: Spring Boot :: v2.4.0-SNAPSHOT
  8. 2019-04-31 13:09:54.117 INFO 56603 --- [ main] o.s.b.s.app.SampleApplication : Starting SampleApplication v0.1.0 on mycomputer with PID 56603 (/apps/myapp.jar started by pwebb)
  9. 2019-04-31 13:09:54.166 INFO 56603 --- [ main] ationConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6e5a8246: startup date [Wed Jul 31 00:08:16 PDT 2013]; root of context hierarchy
  10. 2019-04-01 13:09:56.912 INFO 41370 --- [ main] .t.TomcatServletWebServerFactory : Server initialized with port: 8080
  11. 2019-04-01 13:09:57.501 INFO 41370 --- [ main] o.s.b.s.app.SampleApplication : Started SampleApplication in 2.992 seconds (JVM running for 3.658)

默认情况下,显示INFO级别的日志消息,包括一些与启动相关的详细信息,例如启动应用程序的用户。如果您需要除INFO级别以外的其他级别的日志,则可以按日志级别中所述进行设置。应用程序的版本是使用主应用程序类包中的实现版本来确定的。设置spring.main.log-startup-infofalse可以关闭启动信息记录。这还将关闭应用程序的活动配置的记录。

灯泡.svg 要在启动期间添加其他日志,可以在SpringApplication的子类中覆盖logStartupInfo(boolean)方法。

1.1 启动失败

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

  1. ***************************
  2. APPLICATION FAILED TO START
  3. ***************************
  4. Description:
  5. Embedded servlet container failed to start. Port 8080 was already in use.
  6. Action:
  7. Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.

info.svg Spring Boot提供了许多FailureAnalyzer的实现,您可以添加自己的实现

如果没有故障分析器能够处理该异常,您仍然可以显示完整情况报告,以更好地了解出了什么问题。要做到这一点,你需要启用debug属性或启用org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListenerDEBUG级别的日志
例如,如果使用java -jar来运行应用程序,则可以按如下所示启用debug属性:

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

1.2 惰性初始化(延迟初始化)

SpringApplication允许延迟地初始化应用程序。启用惰性初始化后,不是在应用程序启动期间创建bean,而是根据需要创建bean。结果是,启用惰性初始化可以减少应用程序启动所花费的时间。在Web应用程序中,启用惰性初始化将导致许多与Web相关的Bean直到收到HTTP请求后才被初始化。
惰性初始化的缺点是,它可能会延迟发现应用程序问题的时间。如果一个配置错误的Bean被惰性初始化,则启动期间将不再发生故障,并且只有在初始化Bean时问题才会显现出来。还必须注意确保JVM有足够的内存来容纳应用程序的所有bean,而不仅仅是启动期间初始化的bean。由于这些原因,默认情况下不会启用惰性初始化,因此建议在启用惰性初始化之前先对JVM的堆大小进行微调。
可以使用SpringApplicationBuilderlazyInitialization方法或者SpringApplicationsetLazyInitialization方法以编程的方式启用惰性初始化。另外,可以使用spring.main.lazy-initialization属性来启用它,如以下示例所示:
Properties :

  1. spring.main.lazy-initialization=true

Yaml :

  1. spring:
  2. main:
  3. lazy-initialization: true

灯泡.svg 如果要禁用某些bean的惰性初始化,在对应用程序的其余部分使用惰性初始化时,则可以使用@Lazy(false)注解将它们的延迟属性显式设置为false 。

1.3 自定义Banner(横幅)

可以通过将banner.txt文件添加到类路径,或将spring.banner.location属性设置为此类文件的位置,可以更改启动时打印的Banner。如果文件的编码不是UTF-8,则可以设置spring.banner.charset。除了一个文本文件,你还可以添加一个banner.gifbanner.jpgbanner.png图像文件到类路径或spring.banner.image.location属性指向的位置。图像将转换为ASCII艺术作品(译者:使用纯文本来展示图片)并打印在任何文本Banner的上方。
banner.txt文件内部,可以使用以下任意的占位符:

表1.Banner变量

变量 描述
${application.version} 您的应用程序的版本号,在MANIFEST.MF中声明。例如,在文件中声明为Implementation-Version: 1.0,则打印1.0
${application.formatted-version} 您的应用程序的版本号,将在MANIFEST.MF的声明并进行了格式显示(用括号括起来,并带上前缀v)。例如:(v1.0)
${spring-boot.version} 您正在使用的Spring Boot版本。例如2.4.0-SNAPSHOT
${spring-boot.formatted-version} 您正在使用的Spring Boot版本,将显示格式化(用括号括起来,并带有前缀v)。例如:(v2.4.0-SNAPSHOT)
${Ansi.NAME}(或${AnsiColor.NAME}${AnsiBackground.NAME}${AnsiStyle.NAME} NAME处是ANSI转义码的名称。有关详细信息,请参见AnsiPropertySource
${application.title} 您的应用程序的标题,如MANIFEST.MF中声明。例如,在文件中声明为Implementation-Title: MyApp,则打印为MyApp

灯泡.svg 如果要以编程方式生成Banner,则可以使用SpringApplication.setBanner(…)方法。使用该org.springframework.boot.Banner接口并实现您自己的printBanner()方法。

您还可以使用该spring.main.banner-mode属性来决定是否在System.outconsole)上打印Banner、发送到已配置的记录器(log)或根本不制作(off)。
打印的Banner注册为一个名为springBootBanner的单例bean。

1.4 自定义SpringApplication

如果SpringApplication的默认设置不符合您的喜好,则可以创建一个本地实例并对其自定义。例如,要关闭Banner,您可以编写:

  1. public static void main(String[] args) {
  2. SpringApplication app = new SpringApplication(MySpringConfiguration.class);
  3. app.setBannerMode(Banner.Mode.OFF);
  4. app.run(args);
  5. }

info.svg 传递给SpringApplication的构造函数的参数是Spring bean的配置源。在大多数情况下,它们是对@Configuration类的引用,但也可以是对XML配置或应扫描的包的引用。

也可以通过使用application.properties文件来配置SpringApplication。有关详细信息,请参见外部化配置
有关配置选项的完整列表,请参见SpringApplicationJavadoc

1.5 流式构建器API

如果您需要构建ApplicationContext层次结构(具有父子关系的多个上下文),或者您更喜欢使用“流式的”构建器API,则可以使用SpringApplicationBuilder
SpringApplicationBuilder让要链接的多个方法调用,并且包括parentchild其让你创建层次结构,以显示在下面的示例性方法:

  1. new SpringApplicationBuilder()
  2. .sources(Parent.class)
  3. .child(Application.class)
  4. .bannerMode(Banner.Mode.OFF)
  5. .run(args);

info.svg 创建ApplicationContext层次结构时有一些限制。例如,Web组件必须包含在子上下文中,并且父上下文和子上下文都使用相同的Environment。有关完整的详细信息,请参见SpringApplicationBuilderJavadoc

1.6 应用程序可用性

在平台上部署后,应用程序可以使用诸如Kubernetes Probes之类的基础结构向平台提供有关其可用性的信息。Spring Boot对常说的“活动性”和“就绪性”可用性状态提供了开箱即用的支持。如果您使用的是Spring Boot的“执行器(actuator)”支持,则这些状态将显示为运行状况终端组。
另外,您还可以通过将ApplicationAvailability接口注入到您自己的bean中来获取可用性状态。

1.6.1 活动状态

应用程序的“活动”状态表明其内部状态是否允许其正常运行,或者在当前出现故障时自行恢复。损坏的“活动”状态意味着应用程序处于无法恢复的状态,并且基础设施应重新启动应用程序。

info.svg 通常,“活动”状态不应基于外部检查(例如,健康检查)。如果确实如此,则发生故障的外部系统(数据库,Web API,外部缓存)将触发整个平台的大量重启和级联故障。

Spring Boot应用程序的内部状态主要由Spring的ApplicationContext表示。如果应用程序上下文已成功启动,则Spring Boot会假定该应用程序处于有效状态。刷新上下文后,应用程序即被视为处于活动状态,请参阅Spring Boot应用程序生命周期和相关的Application Events

1.6.2 就绪状态

应用程序的“就绪”状态告诉应用程序是否已准备好处理流量。失败的“就绪”状态告诉平台当前不应将流量路由到应用程序。这通常发生在启动过程中,正在处理CommandLineRunnerApplicationRunner组件时,或者当应用程序认为它太忙而无法获得额外的流量的任意时候就会发生这种情况。
一旦调用了应用程序和命令行运行程序,就认为该应用程序已准备就绪,请参阅Spring Boot应用程序生命周期和相关的Application Events

info.svg 启动期间运行的任务被预期应由CommandLineRunnerApplicationRunner组件执行,而不是使用Spring组件生命周期回调(例如@PostConstruct)。

1.6.3 管理应用程序可用性状态

通过注入ApplicationAvailability接口并在接口上调用方法,应用程序组件可以随时检索当前的可用性状态。应用程序通常会希望监听状态的更新或更新应用程序的状态。
例如,我们可以将应用程序的“就绪”状态导出到一个文件,以便Kubernetes的“ exec Probe”可以查看此文件:

  1. @Component
  2. public class ReadinessStateExporter {
  3. @EventListener
  4. public void onStateChange(AvailabilityChangeEvent<ReadinessState> event) {
  5. switch (event.getState()) {
  6. case ACCEPTING_TRAFFIC:
  7. // create file /tmp/healthy
  8. break;
  9. case REFUSING_TRAFFIC:
  10. // remove file /tmp/healthy
  11. break;
  12. }
  13. }
  14. }

当应用程序崩溃且无法恢复时,我们还可以更新应用程序的状态:

  1. @Component
  2. public class LocalCacheVerifier {
  3. private final ApplicationEventPublisher eventPublisher;
  4. public LocalCacheVerifier(ApplicationEventPublisher eventPublisher) {
  5. this.eventPublisher = eventPublisher;
  6. }
  7. public void checkLocalCache() {
  8. try {
  9. //...
  10. }
  11. catch (CacheCompletelyBrokenException ex) {
  12. AvailabilityChangeEvent.publish(this.eventPublisher, ex, LivenessState.BROKEN);
  13. }
  14. }
  15. }

Spring Boot通过Actuator Health Endpoints为“活动性”和“就绪性”提供Kubernetes HTTP探针。您可以在专用部分中获得有关在Kubernetes上部署Spring Boot应用程序的更多指南。

1.7 应用程序事件和监听器

除了通常的Spring Framework事件(例如,ContextRefreshedEvent)外,SpringApplication还会发送一些其他应用程序事件。

info.svg 实际上在ApplicationContext创建之前会触发一些事件,因此您无法为这些事件注册为一个作为@Bean的侦听器。您可以使用SpringApplication.addListeners(…)方法或SpringApplicationBuilder.listeners(…)方法注册它们。 如果您希望这些侦听器自动注册,而不管创建应用程序的方式如何,可以将META-INF/spring.factories文件添加到项目中,并使用org.springframework.context.ApplicationListener键引用您的侦听器,如以下示例所示: org.springframework.context.ApplicationListener = com.example.project.MyListener

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

  1. 在运行开始时,除了侦听器和初始化程序的注册除外,进行任何处理之前,发送ApplicationStartingEvent事件。
  2. Environment在已知的上下文中被使用,且在创建这个上下文之前,发送ApplicationEnvironmentPreparedEvent事件。
  3. ApplicationContext准备好,已调用ApplicationContextInitializers之后,但未加载任何bean定义之前,发送ApplicationContextInitializedEvent事件。
  4. 在加载bean定义后,刷新开始之前,发送ApplicationPreparedEvent事件。
  5. 在上下文已被刷新后,任何应用程序和命令行运行器都被调用前,发送ApplicationStartedEvent事件。
  6. 紧随其后发送带有LivenessState.CORRECTAvailabilityChangeEvent事件,以指示该应用程序被视为处于活动状态。
  7. 在任何应用程序和命令行运行器被调用后,发送ApplicationReadyEvent事件。
  8. 随即发送带有ReadinessState.ACCEPTING_TRAFFIC参数的AvailabilityChangeEvent事件,以指示该应用程序已准备就绪,可以处理请求。
  9. 如果在启动时异常,发送ApplicationFailedEvent事件。

上面的列表仅包含与SpringApplication绑定的SpringApplicationEvent。除这些以外,以下事件也可以在发送ApplicationPreparedEvent之后、ApplicationStartedEvent之前发送:

  • WebServer准备就绪后发送 WebServerInitializedEvent事件。ServletWebServerInitializedEventReactiveWebServerInitializedEvent分别代表着servlet和reactive准备就绪。
  • ApplicationContext刷新时发送ContextRefreshedEvent事件。

灯泡.svg 您通常不需要使用应用程序事件,但是很容易知道它们的存在。在内部,Spring Boot使用事件来处理各种任务。

info.svg 默认情况下,事件侦听器不应在同一线程中执行潜在的冗长任务。考虑改用应用程序和命令行运行器

应用程序事件是通过使用Spring Framework的事件发布机制发送的。此机制的一部分确保在子级上下文中发布给侦听器的事件也可以在任何祖先上下文中发布给侦听器。这也导致了,如果您的应用程序使用SpringApplication实例的层次结构,则侦听器可能会收到同一类型的应用程序事件的多个实例。
为了使您的侦听器能够区分其上下文的事件和后代上下文的事件,它应请求注入其应用程序上下文,然后将注入的上下文与事件的上下文进行比较。可以通过实现ApplicationContextAware来注入上下文,或者,如果侦听器是bean,则可以使用@Autowired注入上下文。

1.8 网络环境

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

  • 如果存在Spring MVC,则使用AnnotationConfigServletWebServerApplicationContext
  • 如果不存在Spring MVC但存在Spring WebFlux,则使用AnnotationConfigReactiveWebServerApplicationContext
  • 否则,使用AnnotationConfigApplicationContext

这意味着,如果您在同一应用程序中使用Spring MVC和Spring WebFlux中的新WebClient,则默认情况下将使用Spring MVC。您可以通过调用setWebApplicationType(WebApplicationType)轻松覆盖它。
也可以通过调用setApplicationContextClass(…)完全控制ApplicationContext类型。

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

1.9 访问应用程序参数

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

  1. import org.springframework.boot.*;
  2. import org.springframework.beans.factory.annotation.*;
  3. import org.springframework.stereotype.*;
  4. @Component
  5. public class MyBean {
  6. @Autowired
  7. public MyBean(ApplicationArguments args) {
  8. boolean debug = args.containsOption("debug");
  9. List<String> files = args.getNonOptionArgs();
  10. // if run with "--debug logfile.txt" debug=true, files=["logfile.txt"]
  11. }
  12. }

灯泡.svg Spring Boot也注册了一个带有SpringEnvironmentCommandLinePropertySource。这样,您还可以通过使用@Value注解类注入单个应用程序参数。

1.10 使用ApplicationRunner或CommandLineRunner

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

info.svg 该约定非常适合应在应用程序启动后、开始接受流量之前运行的任务。

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

  1. import org.springframework.boot.*;
  2. import org.springframework.stereotype.*;
  3. @Component
  4. public class MyBean implements CommandLineRunner {
  5. public void run(String... args) {
  6. // Do something...
  7. }
  8. }

如果定义了几个必须在一个特定的顺序被调用CommandLineRunnerApplicationRunnerbean,您可以实现org.springframework.core.Ordered接口或使用org.springframework.core.annotation.Order注解。

1.11 应用程序退出

每个SpringApplication都向JVM注册了一个关闭钩子,以确保退出时ApplicationContext优雅的关闭。可以使用所有标准的Spring生命周期回调(例如,DisposableBean接口或@PreDestroy注解)。
另外,如果希望在SpringApplication.exit()调用时返回特定的退出代码,则bean可以实现org.springframework.boot.ExitCodeGenerator接口。然后可以将此退出代码传递到System.exit(),将其作为返回的状态码,如以下示例所示:

  1. @SpringBootApplication
  2. public class ExitCodeApplication {
  3. @Bean
  4. public ExitCodeGenerator exitCodeGenerator() {
  5. return () -> 42;
  6. }
  7. public static void main(String[] args) {
  8. System.exit(SpringApplication.exit(SpringApplication.run(ExitCodeApplication.class, args)));
  9. }
  10. }

而且,ExitCodeGenerator接口可以通过异常来实现。当遇到这样的异常时,Spring Boot返回由实现的getExitCode()方法提供的退出代码。

1.12 管理员功能

通过指定spring.application.admin.enabled属性,可以为应用程序启用与管理员相关的功能。这将在平台MBeanServer上暴露SpringApplicationAdminMXBean。您可以使用此功能来远程管理Spring Boot应用程序。此功能对于任何服务包装器实现都可能有用。

灯泡.svg 如果您想知道应用程序在哪个HTTP端口上运行,请通过local.server.port键获取属性。

1.13 应用程序启动追踪

在应用程序启动期间,SpringApplicationApplicationContext执行许多与应用程序生命周期、bean生命周期甚至处理应用程序事件有关的任务。,Spring Framework允许您通过使用ApplicationStartup跟踪带有StartupStep的应用程序的启动顺序。收集这些数据,可以进行概要分析,或者只是为了更好地了解应用程序的启动过程。
您可以在设置SpringApplication实例时选择一种ApplicationStartup实现。例如,要使用BufferingApplicationStartup,您可以编写:

  1. public static void main(String[] args) {
  2. SpringApplication app = new SpringApplication(MySpringConfiguration.class);
  3. app.setApplicationStartup(new BufferingApplicationStartup(2048));
  4. app.run(args);
  5. }

Spring Framework提供了第一个可用应用程序追踪器的实现,FlightRecorderApplicationStartup。它将特定于Spring的启动事件添加到Java Flight Recorder会话中,旨在对应用程序进行分析并将其Spring上下文的生命周期与JVM事件相关联(例如,内存分配,GC,类加载…)。配置完成后,您可以在启用了Flight Recorder的情况下通过运行应用程序来记录数据:

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

Spring Boot带有BufferingApplicationStartup变体;此实现旨在缓存启动步骤,并将其传递到外部度量系统。应用程序可以在任何组件中请求BufferingApplicationStartup类型的Bean 。此外,Spring Boot Actuator将暴露一个startup端点(将此信息以JSON格式暴露)