20190701 spring-boot | part4(1~2)

20190701 spring-boot | part4(1~2)

Spring Boot Reference Guide
2.2.0.BUILD-SNAPSHOT
https://docs.spring.io/spring-boot/docs/2.2.0.BUILD-SNAPSHOT/reference/htmlsingle/#boot-features

Part 4. Spring Boot Features

4.1 Spring 应用

SpringApplication 类提供方便的(convenient)方式引导 Spring 应用从 main() 启动。通常情况下,你可以委托(delegate)静态方法 SpringApplication.run(),如下所示:

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

当你的应用启动后,你可以看到类似以下的输出:

.   ____          _            __ _ _
/\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/  ___)| |_)| | | | | || (_| |  ) ) ) )
'  |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot ::   v2.2.0.BUILD-SNAPSHOT

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 级别的日志记录消息,包含一些有关(relevant)启动的细节,例如启动应用程序的用户。如果你不需要 INFO 级别的日志信息,你可以设置它,有关这的描述在 日志级别

4.1.1 启动失败

如果你的应用启动失败,注册的 FailureAnalyzers 获得激活提供一个错误描述信息和解决问题的具体(concrete)方式。例如:如果你在 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 提供许多的(numerous)FailureAnalyzer 实现,你可以添加你自己的

如果没有故障分析器能够处理异常,你仍然可以一直展示这个条件报告以便于更好的理解发生了什么错误。要这样做,你需要开启 debug 属性或者为 org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener 打开 DEBUG 日志记录

例如,如果你通过 java -jar 运行你的应用程序,你可以开启 debug 属性,如下:

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

4.1.2 懒加载

SpringApplication 允许应用懒加载。当懒加载开启,Beans 是根据需要创建的,而不是应用启动时创建。因此(as a result),开启懒加载可以减少(reduce the time)应用启动的时间。在 Web 应用中,开启懒加载将会导致(will result in)大量与 web 相关的 beans 不会初始化,直到一个请求进来之后。

懒加载的缺点(a downside of)是它会推迟(delay)发现应用程序出现的问题。如果配置不当(misconfigured)的 bean 被懒加载,启动期间将不会失败,只有当 bean 被初始化时问题才会显露出来。创建同样需要确保 JVM 有充足的(sufficient)的内存来容纳(accommodate)所有的应用 bean,并且不仅仅是启动时的 bean。由于这些原因,懒加载默认情况下没有开启,建议在启用惰性初始化之前对 JVM 的堆大小进行微调。

懒加载可以使用 SpringApplicationBuilder 的 lazyInitilization 方法或者 SpringApplication 的 setLazyInitialization 方法编程式(programatically)的打开。或者,它也可以通过使用 spring.main.lazy-initilization 属性开启,如下:

1
spring.main.lazy-initialization=true

如果你想对应用的其余部分使用懒加载初始化而禁用确定的(certain) bean 的懒加载。你可以使用 @Lazt(false) 注解明确的(explicitly)设置他们的懒加载属性为 false。

4.1.3 定制横幅(banner)

横幅将会在应用启动时打印,可以通过添加一个 banner.txt 文件到你的类路径下或者设置 spring.banner.location 属性指定到一个类似的文件来改变它。如果这个文件的编码不是 UTF-8,你可以设置 spring.banner.charset。除了(in addtion to)文本文件,你同样可以添加一个 banner.git,banner.jpg,banner.png 图片文件到你的类路径下,或者设置 spring.banner.location 属性。图像被转换成 ASCII 艺术表示法(art representation),并打印在任何文字横幅之上。

在你的 banner.txt 文件中,你可以使用任意以下的占位符:

变量 描述
${application.version} 你的应用的版本号,在 MANIFEST.MF 中定义。如,Implementation-Version: 1.0 is printed as 1.0.
${application.formatted-version} 你的应用的版本号,在 MANIFEST.MF 中定义并格式化展示(用括号括起来,并用v)。如:(v1.0)
${spring-boot.version} 你使用的 Spring Boot 的版本号。如:2.2.0.BUILD-SNAPSHOT
${spring-boot.formatted-version} 你使用的 Spring Boot 版本号并格式化展示。如:(v2.2.0.BUILD-SNAPSHOT).
${Ansi.NAME} (or ${AnsiColor.NAME},${AnsiBackground.NAME}, ${AnsiStyle.NAME}) 其中,名称是ANSI转义代码的名称。更多细节请看 AnsiPropertySource
${application.title} 你应用的标题,在 MANIFEST.MF 中定义。如: MyApp is printed as MyApp.

SpringApplication.setBanner(...) 方法可以使用,如果你想编程式生成一个横幅。使用 org.springframework.boot.Banner 接口并实现你自己的 printBanner() 方法。

您还可以使用 Spring.main.ban-mode 属性来确定(determine)是否必须在 System.out(控制台) 上打印横幅,发送到已配置的记录器(日志),或根本不产生(关闭)。

打印的横幅被注册成一个单例的 bean,如以下命名:springBanner。

1
2
3
4
# yml 映射 off 为 false,请确保添加引号如果你要在你的应用中禁用横幅的话,如下所示:
spring:
main:
banner-mode: "off"

4.1.4 定制 Spring 应用

如果 SpringApplication 默认的配置不符合你的口味(taste),作为替代你可以创建一个本地的实例并定制它。例如:要关闭 banner,你可以这样写:

1
2
3
4
5
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。更多细节请查看 外部配置

关于配置项的完整(complete)列表,请查看 SpringApplication 文档

4.1.5 Fluent 构建 API

如果你想构建具有层次结构的(hierarchy)的 ApplicationContext(多个上下文具有父子关系)或者你喜爱使用 “fluent” 构建 API,你可以使用 SpringApplicationBuilder。

SpringApplicationBuilder 允许你将多个方法调用连接在一起,包括允许你创建具有层级结构的父子方法,如下所示:

1
2
3
4
5
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);

当创建具有层级结构的 ApplicationContext 会有一些限制(restrictions)例如:WEB 组件必须包含在 子上下文里面,并且父和子上下文都使用相同的环境。更多细节请查看 SpringApplicationBuilder 文档

4.1.6 应用事件与监听

除了通常使用的 Spring 框架事件,例如 ContextRefreshedEvent。SpringApplication 还会发送一些额外的事件。

一些事件实际上(actually)是在 ApplicationContext 创建之前触发的,所以你不能注册监听器为一个 @Bean。你可以使用 SpringApplication.addListeners(…​) 方法或者 SpringApplicationBuilder.listeners(…​) 方法注册他们。

如果你想这些监听器可以自动注册,不管(regardless)创建应用的是什么方式,你可以添加一个 META-INF/spring.factories 文件到你的项目并使用 org.springframework.context.ApplicationListener 键来引用你的监听器,如下所示:

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

当应用程序运行时,Application Event 以以下顺序发送:

  1. 应用启动事件(ApplicationStartingEvent)在引用开始启动但在任何处理之前发送,除了(except for)注册监听和初始化器之外。
  2. 应用环境准备事件(ApplicationEnvironmentPreparedEvent)发送的时机是当 Environment 被一个已知的上下文使用但是该上下文创建之前。
  3. 应用上下文初始化事件(ApplicationContextInitializedEvent)当 ApplicationContext 已准备,ApplicationContextInitializers 被调用但是任何定义的 bean 加载之前发送。
  4. 应用准备事件(ApplicationPreparedEvent)只在应用刷新开始之前但定义的 bean 加载之后发送。
  5. 应用开始事件(ApplicationStartedEvent)在上下文刷新之后但是任何应用和命令行执行器调用之前发送。
  6. 应用准备事件(ApplicationReadyEvent)是在任何应用和命令行执行器被调用之后发送的。它表明(indicates)该应用已准备好服务请求。
  7. 应用失败事件(ApplicationFailedEvent)在如果启动启动发生异常时发送。

上面的列表只包括 SpringApplicationEvents,它与 “SpringApplication” 绑定(tied to)在一起。。除了这些,以下事件同样在 ApplicationPreparedEvent 之后,ApplicationStartedEvent 之前发布:

  1. 上下文刷新事件(ContextRefreshedEvent)在 ApplicationContext 被刷新后发送。
  2. web服务器初始化事件(WebServerInitializedEvent)在 web 服务器已准备好。ServletWebServerInitializedEvent 和 ReactiveWebServerInitializedEvent 分别是(respectively)servlet 和 reactive 变体。

你通常不需要使用应用事件,但是知道它们的存在是很方便(handy)的。在内部,SpringBoot 使用事件来处理各种任务。

应用事件通过使用 Spring 框架的事件发布机制发送。此机制的一部分(part of)确保事件发布到子上下文的事件时同样也会发送给祖先(ancestor)上线文的监听器。因此(As a result of this),如果你的应用使用具有层次结构的 SpringApplicatoni 实例,监听器可以接受相同类型的应用事件的多个实例。

若要允许监听器区分(distinguish)用于其上下文的事件和针对后代上下文的事件,它应该请求它的应用程序上下文被注入,然后将注入的上下文与事件的上下文进行比较。该上下文可以通过实现 ApplicationContextAware 注入,或者如果监听器是一个 Bean,通过使用 @Authwired。

4.1.7 web 环境

SpringApplication 会尝试(attempts)为您(on your behalf)创建正确类型的应用上下文。用于确定(determine) Web 应用上下文类型的算法相当简单(fairly simple):

  • 如果存在 Spring MVC,使用 AnnotationConfigServletWebServerApplicationContext。
  • 如果 Spring MVC 不存在但 Spring WebFlux 存在,使用 AnnotationConfigReactiveWebServerApplicationContext。
  • 否则,使用 AnnotationConfigApplicationContext。

这意味着如果你从来自同一个(same)应用的 Spring WebFlux 使用 Spring MVC 和新的 WebClient,Spring MVC 将会作为默认使用。你可以通过调用 setWebApplicationType(WebApplicationType) 简单的覆盖它。

同样可以通过调用 setApplicationContextClass(…​) 完成对应用上下文类型的控制。

当在 JUnitTest 中使用 SpringApplication 时通常需要调用 setWebApplicationType(WebApplicationType.NONE)

4.1.8 访问应用参数

如果你需要访问传递给 SpringApplication.run(…​) 的应用参数,你可以注册一个 org.springframework.boot.ApplicationArguments bean。ApplicationArguments 接口提供对原始 String[] 参数以及可选、非可选参数的访问,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 环境中注册了 CommandLinePropertySource。这允许你通过使用 @Value 注解注入单个应用参数。

4.1.9 使用 ApplicationRunner 或者 CommandLineRunner

如果你需要在 Spring 应用启动时运行一些特定代码,你可以实现 ApplicationRunner 或 CommandLineRunner 接口。两者接口都以相同的方式工作,并且都提供了一个单个的 run 方法,只需要在 SpringApplication.run(…​) 完成之前调用。

CommandLineRunner 接口提供对应用参数的访问作为一个简单字符串数组,而 ApplicationRunner 使用前面讨论的 ApplicationArguments 接口。以下样例展示了一个 CommandLineRunner 运行 run 方法:

1
2
3
4
5
6
7
8
9
10
11
import org.springframework.boot.*;
import org.springframework.stereotype.*;

@Component
public class MyBean implements CommandLineRunner {

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

}

如果定义了多个 ApplicationRunnerCommandLineRunner 的Bean,且需要以特定顺序调用。你可以另外(additionally)实现 org.springframework.core.Ordered 接口或者使用 org.springframework.core.annotation.Order 注解。

4.1.10 退出应用

每一个 SpringApplication 都注册了一个宕机钩子到 JVM 以确保在 ApplicationContext 关闭时优雅(gracefully)的退出。可以使用所有标准的 Spring 生命周期回调(例如 DisposableBean 接口或 @predestroy)。

除此之外,beans 可以实现 org.springframework.boot.ExitCodeGenerator 接口如果需要当 SpringApplication.exit() 被调用后返回特定 退出码。这个退出码可以被传递给 System.Exit() 作为一个状态码返回,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
@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 接口可以实现一个异常。当遇到这样的异常时,SpringBoot 返回由实现的 getExitCode() 方法提供的退出代码。

4.1.11 管理功能

可以通过指定 spring.application.admin.enabled 属性为应用开启与管理相关的功能。这将在 MBeanServer 平台上暴露一个 SpringApplicationAdminMXBean。您可以使用此功能远程管理您的 Spring 启动应用程序。这些特性在一些服务包装实现类中同样可用。

如果你想知道应用运行在哪一个端口上,通过 local.server.port 属性可以获得。

启用此特性时要小心(take care),因为MBean公开了关闭应用程序的方法。

4.2 外部化配置

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×