Part IV. SpringBoot特性(Spring Boot features)
本节深入介绍SpringBoot的细节。在这里,您可以了解您可能想要使用和定制的关键特性。如果您还没有这样做,您可能希望阅读“Part II Getting Started”和“Part III Using Spring Boot”,以便对基本知识有一个良好的基础。
23. Spring应用程序(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.servlet.context.AnnotationConfigServletWebServerApplicationContext@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. 启动失败(Startup Failure)
如果应用程序无法启动,注册的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.
Spring Boot提供了许多
FailureAnalyzer
实现,您可以添加自己的。
如果没有故障分析器能够处理异常,您仍然可以显示完整的条件报告,以便更好地理解出错的原因。为此,需要启用debug属性或启用DEBUG loggingorg.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
。
例如,如果您使用java -jar
运行您的应用程序,那么您可以按如下启用debug属性:
$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug
23.2. 自定义 Banner(Customizing the Banner)
可以通过向类路径添加banner.txt
文件或将spring.banner.location
属性设置为此类文件的位置来更改在start up
上打印的Banner。如果文件的编码不是UTF-8,可以设置spring.banner.charset
。除了文本文件之外,还可以将banner.gif
、banner.jpg
或banner.png
图像文件添加到类路径或设置spring.banner.image.location
属性。
在你的banner.txt
文件,您可以使用以下任何一个占位符:
** Table 23.1. Banner variables **
变量 | 描述 |
---|---|
${application.version} |
在MANIFEST.MF 中声明的应用程序的版本号。例如,Implementation-Version: 1.0 打印为1.0 。 |
${application.formatted-version} |
应用程序的版本号,如在MANIFEST.MF 中声明的版本号和用于显示的格式化版本号(用括号括起来,以v为前缀)。 |
${spring-boot.version} |
您正在使用的SpringBoot版本。例如2.1.1.RELEASE。 |
${spring-boot.formatted-version} |
您正在使用的SpringBoot版本,格式化后用于显示(用括号括起来,前缀为v),例如(v2.1.1.RELEASE)。 |
${Ansi.NAME} (or ${AnsiColor.NAME} , ${AnsiBackground.NAME} , ${AnsiStyle.NAME} ) |
其中NAME 是ANSI转义码的名称。有关详细信息,请参见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
)或根本不生成横幅(off
)。
打印的Banner被注册为单例bean,名称如:springBootBanner
YAML映射到false,所以如果您想禁用应用程序中的banner,请确保添加引号,如下面的示例所示:
spring:
main:
banner-mode: "off"
23.3. 定制SpringApplication(Customizing SpringApplication)
如果SpringApplication的默认设置不符合您的口味,那么您可以创建一个本地实例并对其进行定制。例如,要关闭Banner,你可以这样写:
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MySpringConfiguration.class);
app.setBannerMode(Banner.Mode.OFF);
app.run(args);
}
传递给
SpringApplication
的构造函数参数是Spring Bean
的配置源。在大多数情况下,这些是对@Configuration
类的引用,但是它们也可以是对XML配置或应该扫描的包的引用。
也可以通过使用application.properties
配置文件来配置SpringApplication
。有关详细信息,请参见第24章外部化配置。
有关配置选项的完整列表,请参见SpringApplication
Javadoc。
23.4. 使用构造器API(Fluent Builder API)
如果您需要构建一个ApplicationContext
层次结构(具有父/子关系的多个上下文),或者如果您更喜欢使用一个“流畅”的构建器API,那么您可以使用SpringApplicationBuilder
。
SpringApplicationBuilder
允许您将多个方法调用链接在一起,并包括允许您创建层次结构的父方法和子方法,如下面的示例所示:
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);
在创建
ApplicationContext
层次结构时存在一些限制。例如,Web组件必须包含在子上下文中,并且父上下文和子上下文都使用相同的环境。有关详细信息,请参见SpringApplicationBuilder Javadoc
。
23.5. Application Events and Listeners
除了常见的 Spring Framework 事件(如ContextRefreshedEvent
)之外,SpringApplication
还发送一些其他的应用程序事件。
有些事件实际上是在创建
ApplicationContext
之前触发的,因此您不能将侦听器注册为@Bean
。您可以使用SpringApplication.addListeners(…)
方法或SpringApplicationBuilder.listeners(…)
方法注册它们。
如果希望自动注册这些侦听器,不管应用程序是如何创建的,您都可以向项目添加META-INF/spring.factories
文件,并使用org.springframework.context.ApplicationListener
键引用侦听器,如下面的示例所示:
org.springframework.context.ApplicationListener=com.example.project.MyListener
当您的应用程序运行时,应用程序事件按以下顺序触发:
- ApplicationStartingEvent,在程序运行开始时触发,但在其他处理动作之前(除侦听器和初始化程序的注册外);
- ApplicationEnvironmentPreparedEvent,当上下文中使用的环境已知,但在创建上下文之前触发;
- ApplicationPreparedEvent,在刷新启动之前,bean定义加载之后触发;
- ApplicationStartedEvent,在上下文刷新之后,在调用任何应用程序和命令行运行程序之前触发;
- ApplicationReadyEvent,在调用任何应用程序和命令行运行程序之后,都会触发,它表示应用程序已经准备好为请求提供服务;
- ApplicationFailedEvent,启动时出现异常时触发。
您通常不需要使用应用程序事件,但是知道它们的存在是很方便的。在内部,Spring Boot使用事件处理各种任务。
应用程序事件是通过使用Spring Framework的事件发布机制发送的。此机制的一部分确保在子上下文中发布到侦听器的事件也会在任何祖先上下文中发布到侦听器。因此,如果您的应用程序使用SpringApplication
实例的层次结构,侦听器可能会接收到相同类型的应用程序事件的多个实例。
为了让侦听器区分上下文的事件和后代上下文的事件,它应该请求注入其应用程序上下文,然后将注入的上下文与事件的上下文进行比较。可以通过实现ApplicationContextAware
注入上下文,如果侦听器是bean,则可以使用@Autowired
。
23.6. WEB环境(Web Environment)
SpringApplication
尝试为您创建正确类型的ApplicationContext
。用于确定WebApplicationType
的算法相当简单:
- 如果使用Spring MVC,则使用
AnnotationConfigServletWebServerApplicationContext
- 如果Spring MVC不存在,而Spring WebFlux存在,则使用
AnnotationConfigReactiveWebServerApplicationContext
- 否则,将使用
AnnotationConfigApplicationContext
这意味着,如果您在同一个应用程序中使用Spring MVC,并且使用了Spring WebFlux中的WebClient
创建了一个实例,默认情况下将使用Spring MVC。您可以通过调用setWebApplicationType(WebApplicationType)
轻松地覆盖它。
也可以通过调用setApplicationContextClass(…)
来完全控制ApplicationContext
类型。
在JUnit测试中使用
SpringApplication
时,通常需要调用setWebApplicationType(WebApplicationType.NONE)
。
23.7. 访问应用程序参数(Accessing Application Arguments)
如果需要访问传递给SpringApplication.run(…)
的应用程序参数,可以注入org.springframework.boot.ApplicationArguments
bean。ApplicationArguments
接口提供了对原始String[]
参数以及解析option
和non-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"]
}
}
Spring Boot还在SpringEnvironment
中注册了CommandLinePropertySource。这样还可以使用@Value注释注入单个应用程序参数。
23.8. Using the ApplicationRunner or CommandLineRunner
如果您需要在启动SpringApplication
之后运行一些特定的代码,那么您可以实现ApplicationRunner
或CommandLineRunner
接口。这两个接口以相同的方式工作,并提供一个运行方法,该方法在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...
}
}
如果定义了几个CommandLineRunner
或ApplicationRunner
Bean,必须按特定顺序调用,则可以另外实现org.springframework.core.Ordered
接口或使用org.springframework.core.annotation.Order
注解。
23.9. 应用退出(Application Exit)
每个SpringApplication
向JVM注册一个shutdown hook
,以确保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. 管理特性(Admin Features)
通过指定spring.application.admin.enabled
属性,可以为应用程序启用与管理相关的特性。这在MBeanServer
平台上公开了SpringApplicationAdminMXBean
。您可以使用这个特性来远程管理您的SpringBoot
应用程序。这个特性对于任何服务包装器实现都很有用。
如果您想知道应用程序在哪个HTTP端口上运行,请使用
local.server.port
的键获取该属性。** 注意 ** :在启用此功能时要小心,因为MBean公开了一个关闭应用程序的方法。