23. SpringApplication

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

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

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

.   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::   v2.1.1.RELEASE

2013-07-31 00:08:16.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)
2013-07-31 00:08:16.166  INFO 56603 --- [           main] ationConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.ser[emailprotected]6e5a8246: startup date [Wed Jul 31 00:08:16 PDT 2013]; root of context hierarchy
2014-03-04 13:09:54.912  INFO 41370 --- [           main] .t.TomcatServletWebServerFactory : Server initialized with port: 8080
2014-03-04 13:09:56.501  INFO 41370 --- [           main] o.s.b.s.app.SampleApplication            : Started SampleApplication in 2.992 seconds (JVM running for 3.658)

默认情况下,显示INFO条日志记录消息,包括一些相关的启动详细信息,例如启动该应用程序的用户。如果您需要INFO以外的其他日志级别,则可以按照第 26.4 节“日志级别”中的说明进行设置,

23.1 启动失败

如果您的应用程序无法启动,则已注册的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's listening on port 8080 or configure this application to listen on another port.

Note

Spring Boot 提供了众多的FailureAnalyzer实现,您可以添加自己的

如果没有故障分析器能够处理该异常,您仍然可以显示完整情况报告,以更好地了解出了什么问题。为此,您需要org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener 启用调试属性启用调试日志记录

例如,如果您使用java -jar运行应用程序,则可以启用debug属性,如下所示:

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

23.2 自定义 banner

可以通过将banner.txt文件添加到 Classpath 或将spring.banner.location属性设置为此类文件的位置来更改启动时打印的 banner。如果文件的编码不是 UTF-8,则可以设置spring.banner.charset。除了文本文件之外,您还可以将banner.gifbanner.jpgbanner.png图像文件添加到 Classpath 或设置spring.banner.image.location属性。图像将转换为 ASCII 艺术作品并打印在任何文本 banner 上方。

banner.txt文件中,您可以使用以下任何占位符:

表 23.1 标语变量

VariableDescription
${application.version}MANIFEST.MF中声明的应用程序的版本号。例如,Implementation-Version: 1.0被打印为1.0
${application.formatted-version}您的应用程序的版本号,以MANIFEST.MF声明,并设置为显示格式(用方括号括起来并以v作为前缀)。例如(v1.0)
${spring-boot.version}您正在使用的 Spring Boot 版本。例如2.1.1.RELEASE
${spring-boot.formatted-version}您正在使用的 Spring Boot 版本,已格式化以用于显示(用方括号括起来,并以v作为前缀)。例如(v2.1.1.RELEASE)
${Ansi.NAME}(或${AnsiColor.NAME}${AnsiBackground.NAME}${AnsiStyle.NAME})其中NAME是 ANSI 转义代码的名称。有关详情,请参见AnsiPropertySource
${application.title}MANIFEST.MF中声明的应用程序标题。例如Implementation-Title: MyApp被打印为MyApp

Tip

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

您还可以使用spring.main.banner-mode属性来确定 banner 是否必须打印在System.out(console)上,发送到配置的 Logger(log)或根本不打印(off)。

打印的 banner 以以下名称注册为单例 bean:springBootBanner

Note

YAML 将offMap 到false,因此,如果要在应用程序中禁用 banner,请确保添加引号,如以下示例所示:

spring:
	main:
		banner-mode: "off"

23.3 自定义 SpringApplication

如果您不喜欢默认的SpringApplication,则可以创建一个本地实例并对其进行自定义。例如,要关闭 banner,您可以编写:

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

Note

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

也可以通过使用application.properties文件来配置SpringApplication。有关详细信息,请参见* 第 24 章,外部化配置 *。

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

23.4 Fluent Builder API

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

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

new SpringApplicationBuilder()
		.sources(Parent.class)
		.child(Application.class)
		.bannerMode(Banner.Mode.OFF)
		.run(args);

Note

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

23.5 应用程序事件和侦听器

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

Note

有些事件实际上是在创建ApplicationContext之前触发的,因此您不能将这些事件注册为@Bean。您可以使用SpringApplication.addListeners(…)方法或SpringApplicationBuilder.listeners(…)方法注册它们。

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

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

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

  • ApplicationStartingEvent在运行开始时但在进行任何处理之前(侦听器和初始化器的注册除外)发送。

  • 当知道要在上下文中使用的Environment时但在创建上下文之前发送ApplicationEnvironmentPreparedEvent

  • 在刷新开始之前但在加载 bean 定义之后发送ApplicationPreparedEvent

  • 在刷新上下文之后但在调用任何应用程序和命令行运行程序之前发送ApplicationStartedEvent

  • 调用任何应用程序和命令行运行程序后,将发送ApplicationReadyEvent。它指示应用程序已准备就绪,可以处理请求。

  • 如果启动时出现异常,则会发送ApplicationFailedEvent

Tip

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

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

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

23.6 Web 环境

SpringApplication尝试代表您创建正确的ApplicationContext类型。确定WebApplicationType的算法非常简单:

  • 如果存在 Spring MVC,则使用AnnotationConfigServletWebServerApplicationContext

  • 如果不存在 Spring MVC 且存在 Spring WebFlux,则使用AnnotationConfigReactiveWebServerApplicationContext

  • 否则,使用AnnotationConfigApplicationContext

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

也可以完全控制通过调用setApplicationContextClass(…)所使用的ApplicationContext类型。

Tip

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

23.7 访问应用程序参数

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

import org.springframework.boot.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.stereotype.*;

@Component
public class MyBean {

	@Autowired
	public MyBean(ApplicationArguments args) {
		boolean debug = args.containsOption("debug");
		List<String> files = args.getNonOptionArgs();
		// if run with "--debug logfile.txt" debug=true, files=["logfile.txt"]
	}

}

Tip

Spring Boot 还向 Spring Environment注册了一个CommandLinePropertySource。这样,您还可以使用@ValueComments 注入单个应用程序参数。

23.8 使用 ApplicationRunner 或 CommandLineRunner

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

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

import org.springframework.boot.*;
import org.springframework.stereotype.*;

@Component
public class MyBean implements CommandLineRunner {

	public void run(String... args) {
		// Do something...
	}

}

如果定义了几个必须按特定 Sequences 调用的CommandLineRunnerApplicationRunner bean,则可以另外实现org.springframework.core.Ordered接口或使用org.springframework.core.annotation.OrderComments。

23.9 申请退出

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

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

@SpringBootApplication
public class ExitCodeApplication {

	@Bean
	public ExitCodeGenerator exitCodeGenerator() {
		return () -> 42;
	}

	public static void main(String[] args) {
		System.exit(SpringApplication
				.exit(SpringApplication.run(ExitCodeApplication.class, args)));
	}

}

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

23.10 Management 员功能

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

Tip

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

Warning

启用此功能时要小心,因为 MBean 公开了一种关闭应用程序的方法。