1. SpringApplication

2020-03-10  本文已影响0人  E码

1. Spring Boot Features

本章会对 Spring Boot 的内容进行深入的介绍。在这里你可以学习到你想要使用和自定义所需的关键特性。如果你对之前的内容还没有了解,你可以阅读一下 getting-start.html 和 using-spring-boot.html 章节的内容,这样你可以有一个很好的基础来学习本章内容。

1. getting-start.html
    https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/html/getting-started.html#getting-started
2. using-spring-boot.html 
    https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/html/using-spring-boot.html#using-boot

1.1 SpringApplication

SpringApplication 类提供了便捷的途径来引导 Spring 应用程序通过 main() 方法。在许多情况下,你可以委托给静态的 SpirngApplication.run 方法,如下示例所示:

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

应用程序启动后,你可以看到类似下面内容输出:

 .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::   v2.2.5.RELEASE

2019-04-31 13:09:54.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)
2019-04-31 13:09:54.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
2019-04-01 13:09:56.912  INFO 41370 --- [           main] .t.TomcatServletWebServerFactory : Server initialized with port: 8080
2019-04-01 13:09:57.501  INFO 41370 --- [           main] o.s.b.s.app.SampleApplication            : Started SampleApplication in 2.992 seconds (JVM running for 3.658)

默认情况下,系统会打印INFO级别的日志信息,包括一些启动相关的信息。如果你想要调整日志级别,你可以参考 Log Levels 章节描述进行设置。通过设置 spring.main.log-startup-info = false 来关闭启动日志信息。这还将关闭应用程序活动配置文件的日志记录.

1.1.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.

SpringBoot 提供了多种 FailureAnalyzer 的实现,你也可以添加你自己的实现。
https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/html/howto.html#howto-failure-analyzer

如果错误检查器没有捕获到异常,你依然可以显示完整的错误信息方便你理解错误信息。为此,您需要为org.springframework.boot.autoconfigure.logging. logging. condition evaluationreportlogginglistener启用调试属性或启用调试日志记录。

示例,如果你使用 java -jar 命令启动你的程序,可以按照如下方式来启动 debug 属性。

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

1.2 Lazy Initialization

SpringApplication 容许应用程序初始化的延时加载。当延时初始化启用时,bean 的创建是按需创建而不是在启动时全部创建,启用延时初始化可以减少程序启动的时间。在web程序中启用延时初始化后所有的bean都会在 HTTP 请求到达时进行初始化。

延时初始化的一个弊端就是延长问题的发现。如果一个错误的bean延时初始化,这个错误在启动期间不会被发现直到错误的 bean 的初始化。还有就是需要确保 JVM 能够有足够的内存进行 bean 的初始化。由于这些原因,延时初始化默认是关闭的,如果要开启延时初始化建议调整 JVM 的堆大小。

初始化延时可以使用 SpringApplicationBuilder 的 lazyInitialization 或者 使用 SpringApplication 的 setLazyInitialization 方法进行设置。或者使用 spring.main.lazy-initialization 属性进行配置。

spring.main.lazy-initialization=true

如果您希望禁用某些bean的惰性初始化,同时对应用程序的其余部分使用惰性初始化,那么可以使用@Lazy(false)注释显式地将它们的惰性属性设置为false

1.3 Customizing the Banner

banner 可以在程序启动的时候进行打印,你可以在 classpath 中添加 banner.txt 文件或者在属性文件(aapplication.properties)中设置 spring.banner.location 来修改默认的 banner。如果 banner.txt 不是 UTF-8 编码你可以通过 spring.banner.charset 属性进行设置。另外除了文本文件,还可以添加 banner.gif、banner.jpg 或者 banner.png 图片到 classpath 或者设置 spring.banner.image.location 属性。图片会转换成 ASCII 码并且打印到 banner 文本中。

属性如下所示

spring.banner.location
spring.banner.chatset
spring.banner.image.location

在你的 banner.txt 文本内,你可以添加下面任意的占位符。

变量 描述
${application.version} 你应用程序的版本号,在 MANIFSET.MF 中申明。示例: Implementation-Version: 1.0 is printed as 1.0
${application.formatted-version} 应用程序的版本号,根据 MANIFST.MF 和 格式,示例 (v1.0)
${spring-boot.version} SpringBoot 的版本号
${spring-boot.formatted-version} springboot带格式的版本号
{Ansi.NAME} (or{AnsiColor.NAME}, {AnsiBackground.NAME},{AnsiStyle.NAME}) Where NAME is the name of an ANSI escape code. See AnsiPropertySource for details.
${application.title} The title of your application, as declared in MANIFEST.MF. For example Implementation-Title: MyApp is printed as MyApp.

你还可以调用 SpringApplication.setBanner(…) 方法以编程的方式生成 banner。实现 org.springframework.boot.Banner 接口中的 printBanner 方法。

你可以通过 spring.main.banner-mode 来决定 banner 打印到 控制台,日志记录器,或者不打印。

spring.main.banner-mode 有三个值 console,log, off

banner 打印的类被注册成为一个单利模式的bean,被称作 SpringBootBanner。

1.4 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 进行配置。

Externalized Configuration
https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/html/spring-boot-features.html#boot-features-external-config

完整的配置选项清单可以参考相关文档。

https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/api//org/springframework/boot/SpringApplication.html

1.5 Fluent Builder API

If you need to build an ApplicationContext hierarchy (multiple contexts with a parent/child relationship) or if you prefer using a “fluent” builder API, you can use the SpringApplicationBuilder.

The SpringApplicationBuilder lets you chain together multiple method calls and includes parent and child methods that let you create a hierarchy, as shown in the following example:

new SpringApplicationBuilder()
        .sources(Parent.class)
        .child(Application.class)
        .bannerMode(Banner.Mode.OFF)
        .run(args);

There are some restrictions when creating an ApplicationContext hierarchy. For example, Web components must be contained within the child context, and the same Environment is used for both parent and child contexts. See the SpringApplicationBuilder Javadoc for full details.

1.6 Application Events and Listeners

Spring Framework 除了发送常用(如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

你应用程序启动的时候,事件是按照如下顺序进行发送的。

  1. ApplicationStartingEvent - 在程序启动时首先会发送 ApplicationStartingEvent 事件,除了注册监听器和初始化

  2. ApplicationEnvironmentPreparedEvent - 当上下文环境要使用 Environment 时但是上下文环境创建之前将会发送 ApplicationEnvironmentPreparedEvent。

  3. ApplicationContextInializedEvent - 在 ApplicationContext 准备好且 ApplicationContextInitializers 已经被调用但是所有bean加载之前将会发送 ApplicationContextInializedEvent

  4. ApplicationPreparedEvent - 在启动刷新之前、在所有 bean 加载之后发送

  5. ApplicationStartedEvent - 在上下文刷新之后,但在调用任何应用程序和命令行运行程序之前发送

  6. An ApplicationReadyEvent is sent after any application and command-line runners have been called. It indicates that the application is ready to service requests.

  7. An ApplicationFailedEvent is sent if there is an exception on startup.

上述列表的事件只有 SpringApplicationEvent 绑定到了SpringApplicaiton。除此之外,以下事件也会在ApplicationPreparedEvent之后和ApplicationStartedEvent之前发布:

  1. ContextRefreshedEvent 事件当 ApplicationContext 刷新的时候被发送
  2. WebServerInitializedEvent 在 WebServer 准备之后发送。ServletWebServerInitializedEvent和ReactiveWebServerInitializedEvent分别是servlet和reactive变体。

一般情况下你不会使用应用程序的事件,但是知道他们是有好处的。在SpringBoot 内部,它用事件来处理各种任务。

程序事件发送使用的是Spring Framework的事件发行机制。此机制的一部分是确保在任何祖先上下文中发布给侦听器的事件也会发布给侦听器。因此,如果您的应用程序使用了SpringApplication实例的层次结构,则侦听器可能会接收同一类型应用程序事件的多个实例。

为了使您的侦听器能够区分其上下文的事件和后代上下文的事件,它应请求注入其应用程序上下文,然后将注入的上下文与事件的上下文进行比较。 可以通过实现ApplicationContextAware来注入上下文,或者,如果侦听器是bean,则可以使用@Autowired注入上下文。

1.7 Web Environment

SpringApplication 尝试着根据你的行为来创建正确的 ApplicationContext。用于确定WebApplicationType的算法非常简单。

  1. 如果 Spring MVC 出现,AnnotationConfigServletWebServerApplicationContext 就会被创建
  2. 如果 Spring MVC 没有出现且 Spring WebFlux 出现了,AnnotationConfigReactiveWebServerApplicationContext 就会被创建
  3. 如果都没有出现,AnnotationConfigApplicationContext 就会被创建

意思是说如果你使用 Spring MVC 且 使用 WebClient 示例从 Webflux 在同一个程序中,Spring MVC 默认被使用。你可以使用 setWebApplicationType(WebApplicationType) 进行重写。

setWebApplicationType 的值可以是 REACTIVE,NONE,SERVLET

你也可以通过 setApplicationContextClass 来完全控制 ApplicationContext 的类型。

在JUnit测试中使用SpringApplication时,通常需要调用setWebApplicationType(WebApplicationType.NONE)。

1.8 Accessing Application Arguments

如果你需要访问 SpringApplication.run(...) 的参数,你可以使用 a org.springframework.boot.ApplicationArguments bean。ApplicationArguments接口提供对原始字符串[]参数、解析过的选项和非选项参数的访问,如下面的示例所示

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 also registers a CommandLinePropertySource with the Spring Environment. This lets you also inject single application arguments by using the @Value annotation.

1.9 Using the ApplicationRunner or CommandLineRunner

如果你想在 SpringApplication 启动时一次性运行一些指定代码。你可以实现 ApplicationRunner 或者 CommandLineRunner 接口。这两个接口都以同样的方式运行且都提供一个 run 方法,在 SpringApplication.run 方法完成之前调用 run 方法。

The CommandLineRunner interfaces provides access to application arguments as a simple string array, whereas the ApplicationRunner uses the ApplicationArguments interface discussed earlier. The following example shows a CommandLineRunner with a run method:

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

@Component
public class MyBean implements CommandLineRunner {

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

}

如果定义了多个 CommandLineRunner 和 ApplicationRunner 示例而且需要按照指定顺序调用,你可以额外实现 org.springframework.core.Ordered 接口或者使用 org.springframework.core.annotation.Order 注解。

1.10 Application Exit

每一个 SpringApplication 都会向JVM 注册一个关闭回调方法以实现优雅停机。Spring 所有标准的生命周期回调都可以使用(比如 DisposableBean接口或者 @PreDestroy 注解)

另外,如果想要在调用 SpringApplication.exit() 方法后获取指定的代码可以实现 org.springframework.boot.ExitCodeGenerator 接口。

@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)));
    }

}

1.11 Admin Features

It is possible to enable admin-related features for the application by specifying the spring.application.admin.enabled property. This exposes the SpringApplicationAdminMXBean on the platform MBeanServer. You could use this feature to administer your Spring Boot application remotely. This feature could also be useful for any service wrapper implementation.

If you want to know on which HTTP port the application is running, get the property with a key of local.server.port.

上一篇下一篇

猜你喜欢

热点阅读