文章作者:Tyan
博客:noahsnail.com | CSDN | 简书
Part IV. Spring Boot特性
这一部分进入Spring Boot细节部分。在这部分你会了解到你想使用和定制的一些重要特性。如果你还没准备好,你可以阅读第二部分“Getting started”和第三部分“Using Spring Boot”,可以对基础知识有个较好的认识。
23. SpringApplication
SpringApplication
提供了一种很方便的方式来引导Spring应用,Spring应用可以从main()
方法中启动。许多情况下你可以委托给静态方法SpringApplication.run
:
public static void main(String[] args) {
SpringApplication.run(MySpringConfiguration.class, args);
}
当你的应用启动时你应该看到类似于下面的东西:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: v1.4.2.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] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@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.TomcatEmbeddedServletContainerFactory : 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
日志信息,包括一些相关的启动细节例如启动应用的用户。
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.
Spring Boot提供了许多
FailureAnalyzer
实现,你可以很容易添加自己的FailureAnalyzer
实现。
如果没有失败分析器能处理这个异常,你仍可以显示完整的自动配置报告,从而更好的理解什么地方出问题了。为了实现这个你需要启用debug
属性或启用org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer
的DEBUG
日志。
例如,如果你使用java -jar
运行应用,你可以用下面的形式启用debug
属性:
$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug
23.2 定制Banner
启动时打印的标语可以通过在classpath中添加一个banner.txt
文件或者将banner.location
设置为banner.txt
文件的位置来修改。如果文件是一种不常见的编码方式,你可以设置banner.charset
(默认是UTF-8
)。除了文本文件之外,你也添加一个banner.gif
,banner.jpg
或banner.png
图像文件到classpath中,或者设置一个banner.image.location
属性。图像将被转换成ASCII艺术表示并打印在文本标语之上。
在banner.txt
内部你可以使用下面的任何占位符:
Table 23.1. Banner变量
Variable | Description |
---|---|
${application.version} | 你的应用的版本号在MANIFEST.MF 中声明。 例如Implementation-Version: 1.0 打印成1.0 . |
${application.formatted-version} | 在MANIFEST.MF 中的声明的应用版本号进行格式化显示(加上前缀v 并用括号包裹)。例如(v1.0) 。 |
${spring-boot.version} | 你使用的Spring Boot版本。例如1.4.2.RELEASE . |
${spring-boot.formatted-version} | 你使用的Spring Boot版本进行格式化显示加上前缀v 并用括号包裹)。例如(v1.4.2.RELEASE) 。 |
${Ansi.NAME} (or ${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
(控制台)上输出,使用配置的日志(log)或一点也不用(off)。
如果你想在你的应用中禁用banner,YAML会将
off
映射为false
,因此要确保添加引用。
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);
}
传给
SpringApplication
的构造函数参数是Spring beans配置源。在大多数情况下将会引用@Configuration
类,但它们也可以引用XML配置或应该扫描的包。
也可以使用application.properties
文件配置SpringApplication
。更多细节请看24章,『外部配置』。
完整的配置选项列表,请看SpringApplication
文档。
23.4 流畅的构建器API
如果你需要构建ApplicationContext
分层(多个具有父/子关系的上下文),或者你更喜欢使用fluent
的构建器API,你可以使用SpringApplicationBuilder
。
SpringApplicationBuilder
允许你链接多个方法调用,包括允许你创建分层的parent
和child
方法。
例如:
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);
当创建
ApplicationContext
分层时有一些限制,例如,子上下文必须包含web组件,父子上下文将使用同一个Environment
。更完整的细节请看SpringApplicationBuilder
文档。
23.5 应用事件和监听器
除了平常的Spring框架事件之外,例如ContextRefreshedEvent
,SpringApplication
会发送一些其它的应用事件。
在
ApplicationContext
创建之前实际上会触发一些事件,因此你不能使用@Bean
来注册这些监听器。你可以通过SpringApplication.addListeners(…)
或SpringApplicationBuilder.listeners(…)
方法来注册这些监听器。
如果你想自动注册这些监听器,不管上下文的创建方式,你可以在你的工程中添加
META-INF/spring.factories
文件,并通过org.springframework.context.ApplicationListener
作为key来引用你的监听器。
org.springframework.context.ApplicationListener=com.example.project.MyListener
当你的应用运行时,应用事件以下面的顺序发送:
- 在运行启动时发送
ApplicationStartedEvent
,除了监听器和初始化器注册之外,在进行任何处理之前发送。 - 当在上下文中使用的
Environment
已知时,发送ApplicationEnvironmentPreparedEvent
,但发送是在上下文创建之前。 - 在再刷新启动之前,但在bean定义加载之后,发送
ApplicationPreparedEvent
。 - 在再刷新之后,发送
ApplicationReadyEvent
,任何相关的回调函数都处理完成之后,意味着应用已经准备处理服务请求了。 - 如果启动时出现异常,发送
ApplicationFailedEvent
.
经常你不需要使用应用事件,但知道它们的存在是便利的。Spring Boot内部使用事件来处理大量的任务。
23.6 Web环境
SpringApplication
会尝试创建代表你的合适的ApplicationContext
类型。默认情况下,会使用AnnotationConfigApplicationContext
或AnnotationConfigEmbeddedWebApplicationContext
,依赖于你是否在开发一个web应用。
使用的决定web environment
的算法是相对简单的(基于现有的一些类)。如果你需要覆写默认值你可以使用setWebEnvironment(boolean webEnvironment)
。
完全控制ApplicationContext
类型也是可能的,通过调用setApplicationContextClass(…)
使用。
当在JUnit测试时使用
SpringApplication
,经常需要调用setWebEnvironment(false)
。
23.7 访问应用参数
如果你需要访问传进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也在Spring
Environment
中注册CommandLinePropertySource
。这也允许你使用@Value
注解注入单个应对参数。
23.8 使用ApplicationRunner或CommandLineRunner
如果你需要在SpringApplication
启动时运行一些特定的代码,你可以实现ApplicationRunner
或CommandLineRunner
接口。这两个接口以同样方式工作,并有一个单独的run
方法,在SpringApplication.run(…)
之前会调用这个run
方法。
CommandLineRunner
接口提供了对应用参数的访问,应用参数作为一个简单的字符串数组,而ApplicationRunner
使用前面描述的ApplicationArguments
接口。
import org.springframework.boot.*
import org.springframework.stereotype.*
@Component
public class MyBean implements CommandLineRunner {
public void run(String... args) {
// Do something...
}
}
另外,如果定义的CommandLineRunner
或ApplicationRunner
beans必须以指定顺序调用,你可以实现org.springframework.core.Ordered
接口或org.springframework.core.annotation.Order
注解。
23.9 应用退出
为了确保ApplicationContext
在关闭时安全退出, 每个SpringApplication
都会在JVM中注册一个关闭钩子。所有的标准Spring生命周期回调函数(例如DisposableBean
接口,或@PreDestroy
注解)都会被使用。
另外,当应用退出时,如果它们想返回一个特定的退出码,beans可以实现org.springframework.boot.ExitCodeGenerator
接口。
23.10 Admin功能
如果应用想启用admin相关的功能,可以指定spring.application.admin.enabled
属性。这会在平台MBeanServer
上暴露SpringApplicationAdminMXBean
。你可以使用这个功能远程的管理你的Spring Boot应用。对于任何服务包裹的实现这是很有用的。
如果你想知道应用运行的HTTP接口,通过关键字
local.server.port
可以得到这个属性。
当启用这个功能时要非常小心,因为MBean会暴露一个关闭应用的方法。