首页 > 技术文章 > Spring Boot笔记 #04# 核心特性之SpringApplication

xkxf 2022-02-26 18:22 原文

译自:https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.spring-application

1. SpringApplication

SpringApplication类提供了一种方便的方式来引导一个从main()方法启动的Spring应用程序。在很多情况下,你可以委托给静态的SpringApplication.run方法,如下例所示:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyApplication {

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

}

当你的应用程序启动时,你应该会看到类似如下的输出:

@SpringBootApplication
public class MyApplication {

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

}

When your application starts, you should see something similar to the following output:

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

2021-02-03 10:33:25.224  INFO 17321 --- [           main] o.s.b.d.s.s.SpringApplicationExample    : Starting SpringApplicationExample using Java 1.8.0_232 on mycomputer with PID 17321 (/apps/myjar.jar started by pwebb)
2021-02-03 10:33:25.226  INFO 17900 --- [           main] o.s.b.d.s.s.SpringApplicationExample    : No active profile set, falling back to default profiles: default
2021-02-03 10:33:26.046  INFO 17321 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2021-02-03 10:33:26.054  INFO 17900 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-02-03 10:33:26.055  INFO 17900 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.41]
2021-02-03 10:33:26.097  INFO 17900 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-02-03 10:33:26.097  INFO 17900 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 821 ms
2021-02-03 10:33:26.144  INFO 17900 --- [           main] s.tomcat.SampleTomcatApplication         : ServletContext initialized
2021-02-03 10:33:26.376  INFO 17900 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2021-02-03 10:33:26.384  INFO 17900 --- [           main] o.s.b.d.s.s.SpringApplicationExample    : Started SampleTomcatApplication in 1.514 seconds (JVM running for 1.823)

默认情况下,会显示INFO日志消息,包括一些相关的启动细节,比如启动应用程序的用户。如果您需要设置除INFO之外的日志级别,请参见日志级别(Log Levels)进行设置。应用程序版本是使用来自主应用程序类包的实现版本来确定的。可以通过将spring.main.log-startup-info设置为false来关闭启动信息日志记录(Startup information logging)。这也将关闭应用程序的活动概要文件(the application’s active profiles)的日志记录。

要在启动时添加额外的日志记录,你可以在SpringApplication的子类中重写logStartupInfo(boolean)

1.1. Startup Failure

显示完整的条件报告,以更好地理解出错的原因。

例如,如果你使用java -jar运行你的应用程序,你可以启用debug属性,如下所示:

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

1.3. Customizing the Banner

可以通过在类路径中添加一个banner.txt文件或将spring.banner.location属性设置为该文件的位置来更改启动时打印的横幅。如果文件的编码不是UTF-8,可以设置spring.banner.charset。除了文本文件外,还可以向类路径(PS. 放在application.properties同一目录,也就是resources目录下,简单的黑白图片效果很不错,关于资源放在哪可以参考“Maven入门_如何向JAR添加资源&标准目录布局”,当然,springboot项目打包后的目录结构会不一样,详见The Executable Jar Format中添加banner.gif、banner.jpg或banner.png图像文件,或者设置spring.banner.image.location属性。图像被转换成ASCII艺术表示,并打印在任何文本横幅上方。

在你的banner.txt文件中,你可以使用Environment中可用的任何key以及以下任何占位符(参见Table 1. Banner variables

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

你也可以使用spring.main.banner-mode属性来确定是否必须在System.out (console)打印横幅,发送到配置的记录器(log),或根本不产生(off)

打印出来的横幅被注册为一个单例bean,名字如下:springBootBanner

1.4. Customizing SpringApplication

如果SpringApplication的默认值不合你的口味,你可以创建一个本地实例并对其进行定制。例如,要关闭横幅,你可以这样写:

import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(MyApplication.class);
        application.setBannerMode(Banner.Mode.OFF);
        application.run(args);
    }

}

(传递给SpringApplication的构造函数参数是Spring bean的配置源。在大多数情况下,这些是对@Configuration类的引用,但它们也可以是对@Component类的直接引用)

也可以通过使用一个application.properties文件来配置SpringApplication。有关详细信息,请参阅外部化配置( Externalized Configuration)。

有关配置选项的完整列表(a complete list of the configuration options),请参阅SpringApplication Javadoc

1.7. Application Events and Listeners

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

(有些事件实际上是在ApplicationContext创建之前被触发的,所以你不能在这些事件上注册一个listener作为@Bean。你可以用SpringApplication.addListeners(…)方法或SpringApplicationBuilder.listeners(…)方法注册它们。

如果您希望自动注册这些侦听器,而不管应用程序是以何种方式创建的,那么您可以添加一个META-INF/spring.factories到你的项目,并通过使用org.springframework.context.ApplicationListener键引用你的listener(s),如下所示:

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

当你的应用程序运行时,应用程序事件按以下顺序发送:

  • x
  • x
  • x
  • x
  • x

(详见:https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.spring-application.application-events-and-listeners

上面的列表只包括绑定到SpringApplication的SpringApplicationEvents。除此之外,以下事件也会在ApplicationPreparedEvent之后和ApplicationStartedEvent之前发布:

  • 一个WebServerInitializedEvent在WebServer准备好之后被发送。ServletWebServerInitializedEventReactiveWebServerInitializedEvent分别是servlet和响应式变量。
  • 当ApplicationContext刷新时,ContextRefreshedEvent被发送。

(您通常不需要使用应用程序事件,但知道它们的存在会很方便。在内部,Spring Boot使用事件来处理各种任务)

(默认情况下,Event listeners在同一线程中执行时,不应运行可能冗长的任务。考虑使用应用程序和命令行运行器。)

应用程序事件(Application events)是通过使用Spring Framework的事件发布机制发送的。该机制的一部分确保在子上下文中(in a child context)发布到侦听器的事件也会发布到任何祖先上下文中(any ancestor contexts)的侦听器。因此,如果应用程序使用SpringApplication实例的层次结构,一个侦听器(a listener)可能会接收到相同类型的应用程序事件的多个实例。

要让侦听器区分上下文的事件和后代上下文的事件,它应该请求注入其应用程序上下文,然后将注入的上下文与事件的上下文进行比较。context可以通过实现ApplicationContextAware注入,如果侦听器是一个bean,也可以通过使用@Autowired注入。

1.8. Web Environment

SpringApplication试图为您创建正确类型的ApplicationContext。用来确定WebApplicationType的算法如下:

  • If Spring MVC is present, an AnnotationConfigServletWebServerApplicationContext is used
  • If Spring MVC is not present and Spring WebFlux is present, an AnnotationConfigReactiveWebServerApplicationContext is used
  • Otherwise, AnnotationConfigApplicationContext is used

这意味着,如果你在同一个应用程序中使用Spring MVC和来自Spring WebFlux的新WebClient,那么默认情况下会使用Spring MVC。你可以通过调用setWebApplicationType(WebApplicationType)轻松覆盖它。

也可以通过调用setApplicationContextClass(…)来完全控制ApplicationContext类型。

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

1.13. Application Startup tracking

在应用程序启动期间,SpringApplicationApplicationContext执行许多与应用程序生命周期、bean生命周期甚至处理应用程序事件相关的任务。使用ApplicationStartup, Spring框架允许你使用StartupStep对象跟踪应用程序的启动顺序。收集这些数据可以用于分析目的,或者只是为了更好地理解应用程序的启动过程。

在设置SpringApplication实例时,您可以选择一个ApplicationStartup实现。例如,要使用BufferingApplicationStartup,你可以这样写:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;

@SpringBootApplication
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(MyApplication.class);
        application.setApplicationStartup(new BufferingApplicationStartup(2048));
        application.run(args);
    }

}

第一个可用的实现FlightRecorderApplicationStartup是由Spring Framework提供的。它将Spring特定的启动事件添加到Java Flight Recorder会话中,用于分析应用程序,并将它们的Spring上下文生命周期与JVM事件(如分配、gc、类加载……)关联起来。配置完成后,你可以通过启用Flight Recorder运行应用程序来记录数据:

$ java -XX:StartFlightRecording:filename=recording.jfr,duration=10s -jar demo.jar

Spring Boot自带BufferingApplicationStartup变量;这个实现是为了buffering启动步骤,并将它们放入外部度量系统中(an external metrics system)。应用程序可以在任何组件中请求BufferingApplicationStartup类型的bean。

Spring Boot还可以配置成暴露一个启动端点(startup endpoint ),该端点以JSON文档的形式提供该信息。

推荐阅读