4.1 SpringApplication
SpringApplication类提供了一种方便的方法来引导从main()方法启动的Spring应用程序。 在许多情况下,您可以委托静态SpringApplication.run方法,如以下示例所示:
public static void main(String[] args) {
SpringApplication.run(MySpringConfiguration.class, args);
}
当您的应用程序启动时,您应该看到类似于以下输出的内容:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: v2.1.3.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以外的日志级别,可以按照第4.4.4节“日志级别”中的说明进行设置。
4.1.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实现,您可以添加自己的。
如果没有故障分析器能够处理异常,您仍然可以显示完整的条件报告,以便更好地了解出现了什么问题。 为此,您需要启用debug属性或为org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener启用DEBUG日志记录。
例如,如果使用java -jar运行应用程序,则可以按如下方式启用debug属性:
$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug
4.1.2 自定义Banner
可以通过将banner.txt文件添加到类路径或将spring.banner.location属性设置为此类文件的位置来更改启动时打印的Banner。 如果文件的编码不是UTF-8,则可以设置spring.banner.charset。 除了文本文件,您还可以将banner.gif,banner.jpg或banner.png图像文件添加到类路径或设置spring.banner.image.location属性。 图像将转换为ASCII艺术表示,并打印在任何文本Banner上方。
在banner.txt文件中,您可以使用以下任何占位符:
表23.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.1.3.RELEASE。 |
\${spring-boot.formatted-version} | 您正在使用的Spring Boot版本,格式化显示(用括号括起来并以v为前缀)。 例如(v2.1.3.RELEASE)。 |
\${Ansi.NAME} (或\${AnsiColor.NAME},\${AnsiBackground.NAME}, \${AnsiStyle.NAME}) | 其中NAME是ANSI转义码的名称。 有关详细信息,请参见AnsiPropertySource。 |
\${application.title} | 应用程序的标题,在MANIFEST.MF中声明。 例如,标题:MyApp打印为MyApp。 |
如果要以编程方式生成横幅,可以使用SpringApplication.setBanner(...)方法。 使用org.springframework.boot.Banner接口并实现自己的printBanner()方法。
您还可以使用spring.main.banner-mode属性来确定是否必须在System.out(控制台)上打印横幅,发送到配置的logger(日志),或者根本不生成横幅(关闭)。
打印的横幅在以下名称下注册为单例bean:springBootBanner。
YAML映射为false,因此如果要在应用程序中禁用横幅,请务必添加引号,如以下示例所示:
spring: main: banner-mode: "off"
4.1.3 自定义SpringApplication
如果SpringApplication默认值不符合您的需要,您可以改为创建本地实例并对其进行自定义。 例如,要关闭横幅,您可以写:
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。 有关详细信息,请参见第4.2节 外部化配置。
有关配置选项的完整列表,请参阅SpringApplication Javadoc。
4.1.4 Fluent Builder API
如果需要构建ApplicationContext层次结构(具有父/子关系的多个上下文),或者如果您更喜欢使用“Stream”构建器API,则可以使用SpringApplicationBuilder。
SpringApplicationBuilder允许您将多个方法调用链接在一起,并包含允许您创建层次结构的父方法和子方法,如以下示例所示:
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);
创建ApplicationContext层次结构时存在一些限制。 例如,Web组件必须包含在子上下文中,并且相同的Environment用于父上下文和子上下文。 有关完整的详细信息,请参阅SpringApplicationBuilder Javadoc。
4.1.5 应用程序事件和监听器
除了通常的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:已经知道上下文的Environment,但还未创建上下文
- ApplicationPreparedEvent:在刷新开始之前但是在加载bean定义之后。
- ApplicationStartedEvent:在刷新上下文之后但在调用任何应用程序和命令行运行程序之前。
- ApplicationReadyEvent:在调用任何应用程序和命令行运行程序之后。 它表示应用程序已准备好为请求提供服务。
- ApplicationFailedEvent:如果启动时有异常。
您通常不需要使用应用程序事件,但知道它们存在可能很方便。 在内部,Spring Boot使用事件来处理各种任务。
使用Spring Framework的事件发布机制发送应用程序事件。 此机制的一部分确保发布到子上下文中的侦听器的事件也发布到任何祖先上下文中的侦听器。 因此,如果您的应用程序使用SpringApplication实例的层次结构,则侦听器可能会收到相同类型的应用程序事件的多个实例。
为了允许侦听器区分其上下文的事件和后代上下文的事件,它应该请求注入其应用程序上下文,然后将注入的上下文与事件的上下文进行比较。 可以通过实现ApplicationContextAware来注入上下文,或者,如果监听器是bean,则使用@Autowired来注入。
4.1.6 网络环境
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)。
4.1.7 访问应用程序参数
如果需要访问传递给SpringApplication.run(...)的应用程序参数,可以注入org.springframework.boot.ApplicationArguments bean。 ApplicationArguments接口提供对原始String []参数以及解析选项和非选项参数的访问,如以下示例所示:
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注释注入单个应用程序参数。
4.1.8 使用ApplicationRunner或CommandLineRunner
如果在SpringApplication启动后需要运行某些特定代码,则可以实现ApplicationRunner或CommandLineRunner接口。 两个接口以相同的方式工作,并提供单个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...
}
}
如果定义了必须按特定顺序调用的多个CommandLineRunner或ApplicationRunner bean,则可以另外实现org.springframework.core.Ordered接口或使用org.springframework.core.annotation.Order注释。
4.1.9 退出应用
每个SpringApplication都会向JVM注册一个关闭钩子,以确保ApplicationContext在退出时正常关闭。 可以使用所有标准的Spring生命周期回调(例如DisposableBean接口或@PreDestroy注释)。
此外,如果bean希望在调用SpringApplication.exit()时返回特定的退出代码,则bean可以实现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()方法提供的退出代码。
4.1.10 管理功能
通过指定spring.application.admin.enabled属性,可以为应用程序启用与管理相关的功能。 这会在平台MBeanServer上公开SpringApplicationAdminMXBean。 您可以使用此功能远程管理Spring Boot应用程序。 此功能对于任何服务包装器实现也很有用。
如果您想知道应用程序正在运行的HTTP端口,请使用local.server.port的键获取该属性。
启用此功能时要小心,因为MBean公开了一种关闭应用程序的方法。