23.SpringApplication

SpringApplication类提供了一种快捷方式,用于从main()方法启动Spring应用。多数情况下,你只需要将该任务委托给SpringApplication.run静态方法:

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

当应用启动时,你应该会看到类似下面的东西:

.   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::   v1.4.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] 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实现,你自己实现也很容易。

如果没有可用于处理该异常的失败分析器(failure analyzers),你需要展示完整的auto-configuration报告以便更好的查看出问题的地方,因此你需要启用org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializerdebug属性,或开启DEBUG日志级别

例如,使用java -jar运行应用时,你可以通过如下命令启用debug属性:

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

23.2. 自定义Banner

通过在classpath下添加一个banner.txt或设置banner.location来指定相应的文件可以改变启动过程中打印的banner。如果这个文件有特殊的编码,你可以使用banner.encoding设置它(默认为UTF-8)。除了文本文件,你也可以添加一个banner.gifbanner.jpgbanner.png图片,或设置banner.image.location属性。图片会转换为字符画(ASCII art)形式,并在所有文本banner上方显示。

在banner.txt中可以使用如下占位符:

变量 描述
${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.1.RELEASE
${spring-boot.formatted-version} 当前Spring Boot被格式化后的版本号(被括号包裹且以v作为前缀), 用于显示,例如(v1.4.1.RELEASE)
${Ansi.NAME}(或${AnsiColor.NAME},${AnsiBackground.NAME}, ${AnsiStyle.NAME}) NAME代表一种ANSI编码,具体详情查看AnsiPropertySource
${application.title} MANIFEST.MF中声明的应用title,例如Implementation-Title: MyApp会打印MyApp

如果想以编程的方式产生一个banner,可以使用SpringBootApplication.setBanner(…)方法,并实现org.springframework.boot.Banner接口的printBanner()方法。

你也可以使用spring.main.banner-mode属性决定将banner打印到何处,System.outconsole),配置的logger(log)或都不输出(off)。

打印的banner将注册成一个名为springBootBanner的单例bean。

YAML会将off映射为false,如果想在应用中禁用banner,你需要确保off添加了括号:

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. Externalized 配置,访问SpringApplication Javadoc可获取完整的配置选项列表.

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 javadoc

23.5. Application事件和监听器

除了常见的Spring框架事件,比如ContextRefreshedEventSpringApplication也会发送其他的application事件。

有些事件实际上是在ApplicationContext创建前触发的,所以你不能在那些事件(处理类)中通过@Bean注册监听器,只能通过SpringApplication.addListeners(…)SpringApplicationBuilder.listeners(…)方法注册。如果想让监听器自动注册,而不关心应用的创建方式,你可以在工程中添加一个META-INF/spring.factories文件,并使用org.springframework.context.ApplicationListener作为key指向那些监听器,如下:

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

应用运行时,事件会以下面的次序发送:

  1. 在运行开始,但除了监听器注册和初始化以外的任何处理之前,会发送一个ApplicationStartedEvent
  2. 在Environment将被用于已知的上下文,但在上下文被创建前,会发送一个ApplicationEnvironmentPreparedEvent
  3. 在refresh开始前,但在bean定义已被加载后,会发送一个ApplicationPreparedEvent
  4. 在refresh之后,相关的回调处理完,会发送一个ApplicationReadyEvent,表示应用准备好接收请求了。
  5. 启动过程中如果出现异常,会发送一个ApplicationFailedEvent

通常不需要使用application事件,但知道它们的存在是有用的(在某些场合可能会使用到),比如,在Spring Boot内部会使用事件处理各种任务。

23.6. Web环境

SpringApplication将尝试为你创建正确类型的ApplicationContext,默认情况下,根据你开发的是否为web应用决定使用AnnotationConfigApplicationContextAnnotationConfigEmbeddedWebApplicationContext

用于确定是否为web环境的算法相当简单(判断是否存在某些类),你可以使用setWebEnvironment(boolean webEnvironment)覆盖默认行为。

通过调用setApplicationContextClass(…),你可以完全控制ApplicationContext的类型。

在Junit测试中使用SpringApplication,调用setWebEnvironment(false)是很有意义的。

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"]
    }

}

Spring Boot也会注册一个包含Spring Environment属性的CommandLinePropertySource,这就允许你使用@Value注解注入单个的应用参数。

23.8. 使用ApplicationRunner或CommandLineRunner

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

CommandLineRunner接口能够访问string数组类型的应用参数,而ApplicationRunner使用的是上面描述过的ApplicationArguments接口:

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

@Component
public class MyBean implements CommandLineRunner {

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

}

如果某些定义的CommandLineRunnerApplicationRunner beans需要以特定的顺序调用,你可以实现org.springframework.core.Ordered接口或使用org.springframework.core.annotation.Order注解。

23.9 Application退出

为确保ApplicationContext在退出时被平静的(gracefully)关闭,每个SpringApplication都会注册一个JVM的shutdown钩子,所有标准的Spring生命周期回调(比如DisposableBean接口或@PreDestroy注解)都能使用。

此外,如果想在应用结束时返回特定的退出码(exit code),这些beans可以实现org.springframework.boot.ExitCodeGenerator接口。

23.10 Admin特性

通过设置spring.application.admin.enabled属性可以启用管理相关的(admin-related)特性,这将暴露SpringApplicationAdminMXBean到平台的MBeanServer,你可以使用该特性远程管理Spring Boot应用,这对任何service包装器(wrapper)实现也有用。

通过local.server.port可以获取该应用运行的HTTP端口。启用该特性时需要注意MBean会暴露一个方法去关闭应用。