这一节深入研究了Spring Boot的细节。在这里,您可以了解您可能想要使用和定制的关键功能。如果您还没有这样做,您可能需要阅读“快速入门”和“使用Spring Boot开发”部分,这样您就有了很好的基础知识。

1. SpringApplication

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

Java
Kotlin
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); } } 
           
           

当您的应用程序启动时,您应该看到类似以下输出的内容:

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

2022-11-24T17:03:48.214Z  INFO 20764 --- [           main] o.s.b.d.f.s.MyApplication                : Starting MyApplication using Java 17.0.5 with PID 20764 (/opt/apps/myapp.jar started by myuser in /opt/apps/)
2022-11-24T17:03:48.219Z  INFO 20764 --- [           main] o.s.b.d.f.s.MyApplication                : No active profile set, falling back to 1 default profile: "default"
2022-11-24T17:03:50.511Z  INFO 20764 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2022-11-24T17:03:50.524Z  INFO 20764 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2022-11-24T17:03:50.524Z  INFO 20764 --- [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.1]
2022-11-24T17:03:50.623Z  INFO 20764 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2022-11-24T17:03:50.625Z  INFO 20764 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2269 ms
2022-11-24T17:03:51.380Z  INFO 20764 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2022-11-24T17:03:51.418Z  INFO 20764 --- [           main] o.s.b.d.f.s.MyApplication                : Started MyApplication in 3.872 seconds (process running for 5.008)
2022-11-24T17:03:51.506Z  INFO 20764 --- [ionShutdownHook] o.apache.catalina.core.StandardService   : Stopping service [Tomcat]

默认情况下,会显示信息日志记录消息,包括一些相关的启动详细信息,例如启动应用程序的用户。如果您需要信息以外的日志级别,您可以设置它,如日志级别中所述。应用程序版本是使用主应用程序类的包中的实现版本确定的。可以通过将spring.main.log-startup-info设置为FALSE来关闭启动信息记录。这还将关闭应用程序的活动配置文件的记录。

To add additional logging during startup, you can override logStartupInfo(boolean) in a subclass of SpringApplication.

1.1. Startup Failure

如果您的应用程序无法启动,注册的FailureAnalyzer有机会提供专门的错误消息和修复问题的具体操作。例如,如果您在端口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 is listening on port 8080 or configure this application to listen on another port.
Spring Boot provides numerous FailureAnalyzer implementations, and you can add your own.

如果没有故障分析器能够处理异常,您仍然可以显示完整的条件报告,以更好地了解哪里出了问题。为此,您需要为org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener.启用调试属性或启用调试日志记录

例如,如果您正在使用Java-jar运行应用程序,则可以按如下方式启用调试属性:

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

1.2. Lazy Initialization

SpringApplication允许延迟初始化应用程序。启用延迟初始化时,将在需要时创建Bean,而不是在应用程序启动期间创建。因此,启用延迟初始化可以减少启动应用程序所需的时间。在Web应用程序中,启用延迟初始化将导致许多与Web相关的Bean在收到HTTP请求之前不会被初始化。

延迟初始化的一个缺点是它会延迟应用程序问题的发现。如果延迟初始化错误配置的Bean,则在启动过程中不会再出现故障,只有在初始化Bean时,问题才会变得明显。还必须注意确保JVM有足够的内存来容纳应用程序的所有Bean,而不仅仅是那些在启动期间初始化的Bean。由于这些原因,默认情况下不启用延迟初始化,建议在启用延迟初始化之前对JVM的堆大小进行微调。

可以使用SpringApplicationBuilder上的lazyInitialization方法或SpringApplication上的setLazyInitialization方法以编程方式启用延迟初始化。或者,也可以使用spring.main.lazy-Initialization属性启用它,如下例所示:

Properties
Yaml
spring.main.lazy-initialization=true
            
            
If you want to disable lazy initialization for certain beans while using lazy initialization for the rest of the application, you can explicitly set their lazy attribute to false using the @Lazy(false) annotation.

1.3. Customizing the Banner

通过将banner.txt文件添加到类路径或将spring.banner.Location属性设置为此类文件的位置,可以更改启动时打印的横幅。如果文件的编码不是UTF-8,则可以设置spring.banner.charset

banner.txt文件中,您可以使用环境中的任何键以及以下任何占位符:

Table 1. Banner variables
Variable Description

${Applation.Version}

应用程序的版本号,在MANIFEST.MF中声明。例如,Implementation-Version:1.0打印为1.0

${Applation.Formatted-Version}

应用程序的版本号,在MANIFEST.MF中声明,并为显示而格式化(用括号括起来,并以v为前缀)。例如(v1.0)

${Spring-boot.version}

您正在使用的Spring Boot版本。例如3.0.0

${Spring-boot.Formatted-Version}

您正在使用的Spring Boot版本,经过格式化以便于显示(用括号括起来,并以v为前缀)。例如(v3.0.0)

${Ansi.NAME}(或${AnsiColor.NAME}${AnsiBackack.NAME}${AnsiStyle.NAME})

其中name是ANSI转义代码的名称。详情请参见AnsiPropertySource

${APPLICATION.TITLE}

应用程序的标题,在MANIFEST.MF中声明。例如,Implementation-title:MyApp打印为MyApp

The SpringApplication.setBanner(…​) method can be used if you want to generate a banner programmatically. Use the org.springframework.boot.Banner interface and implement your own printBanner() method.

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

打印的横幅被注册为一个单独的Bean,名称如下:springBootBanner

仅当您使用的是Spring Boot启动器时,才能使用${Application.version}${Application.Formatted-Version}属性。如果您正在运行一个解压的JAR并以Java-cp<;classpath>;<;mainclass>;启动,则不会解析这些值。

这就是为什么我们建议您始终使用Java org.springframework.boot.loader.JarLauncher.启动未打包的JAR这将在构建类路径和启动应用程序之前初始化应用程序.*标题变量。

1.4. Customizing SpringApplication

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

Java
Kotlin
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); } } 
            
            
The constructor arguments passed to SpringApplication are configuration sources for Spring beans. In most cases, these are references to @Configuration classes, but they could also be direct references @Component classes.

还可以使用应用程序属性文件配置SpringApplication。详情请参见外部化配置

有关配置选项的完整列表,请参阅SpringApplicationJava。

1.5. Fluent Builder API

如果您需要构建ApplicationContext层次结构(具有父/子关系的多个上下文),或者如果您更喜欢使用流畅的构建器API,则可以使用SpringApplicationBuilder

SpringApplicationBuilder允许您将多个方法调用链接在一起,并包括允许您创建层次结构的方法,如下例所示:

Java
Kotlin
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 Availability

当部署在平台上时,应用程序可以使用诸如Kubernetes Probe之类的基础设施向平台提供有关其可用性的信息。Spring Boot包括对常用的“活跃度”和“就绪”可用性状态的开箱即用支持。如果您使用的是Spring Boot的“执行器”支持,那么这些状态将作为健康终结点组公开。

此外,您还可以通过将ApplicationAvailability接口注入您自己的Bean来获取可用性状态。

1.6.1. Liveness State

应用程序的“活动”状态告诉它,它的内部状态是否允许它正常工作,或者如果它当前出现故障,它是否可以自行恢复。中断的“活跃度”状态意味着应用程序处于无法恢复的状态,基础设施应重新启动应用程序。

In general, the "Liveness" state should not be based on external checks, such as Health checks. If it did, a failing external system (a database, a Web API, an external cache) would trigger massive restarts and cascading failures across the platform.

Spring Boot应用程序的内部状态主要由SpringApplicationContext表示。如果应用程序上下文已成功启动,则Spring Boot假定应用程序处于有效状态。一旦上下文被刷新,应用程序就被认为是活动的,请参阅Spring Boot应用程序生命周期和相关应用程序事件

1.6.2. Readiness State

应用程序的“就绪”状态告知应用程序是否已准备好处理流量。失败的“就绪”状态告诉平台,它暂时不应该将流量路由到应用程序。这通常发生在启动期间、正在处理CommandLineRunnerApplicationRunner组件时,或者在应用程序确定太忙而无法进行额外通信的任何时候。

一旦调用了应用程序和命令行运行程序,就认为应用程序已经就绪,请参阅Spring Boot应用程序生命周期和相关的应用程序事件

Tasks expected to run during startup should be executed by CommandLineRunner and ApplicationRunner components instead of using Spring component lifecycle callbacks such as @PostConstruct.

1.6.3. Managing the Application Availability State

通过注入ApplicationAvailability接口并调用接口上的方法,应用程序组件可以随时检索当前的可用性状态。更常见的情况是,应用程序希望监听状态更新或更新应用程序的状态。

例如,我们可以将应用程序的“就绪”状态导出到一个文件,以便Kubernetes“EXEC探测器”可以查看该文件:

Java
Kotlin
import org.springframework.boot.availability.AvailabilityChangeEvent; import org.springframework.boot.availability.ReadinessState; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @Component public class MyReadinessStateExporter { @EventListener public void onStateChange(AvailabilityChangeEvent<ReadinessState> event) { switch (event.getState()) { case ACCEPTING_TRAFFIC: // create file /tmp/healthy break; case REFUSING_TRAFFIC: // remove file /tmp/healthy break; } } } 
             
             

我们还可以在应用程序中断且无法恢复时更新应用程序的状态:

Java
Kotlin
import org.springframework.boot.availability.AvailabilityChangeEvent; import org.springframework.boot.availability.LivenessState; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Component; @Component public class MyLocalCacheVerifier { private final ApplicationEventPublisher eventPublisher; public MyLocalCacheVerifier(ApplicationEventPublisher eventPublisher) { this.eventPublisher = eventPublisher; } public void checkLocalCache() { try { // ... } catch (CacheCompletelyBrokenException ex) { AvailabilityChangeEvent.publish(this.eventPublisher, ex, LivenessState.BROKEN); } } } 
             
             

Spring Boot为Kubernetes HTTP探测器提供了Actuator Health Endpoint的“活跃性”和“就绪性”。有关在Kubernetes上部署Spring Boot应用程序的更多指导,请参阅专用部分。

1.7. Application Events and Listeners

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

有些事件实际上是在ApplicationContext创建之前触发的,因此不能在这些事件上将监听器注册为@Bean。您可以使用SpringApplication.addListeners(…)注册它们​)方法或SpringApplicationBuilder.listeners(…​) 方法。

如果希望自动注册这些侦听器,而不考虑应用程序的创建方式,则可以将<代码>META-INF/spring.Factory文件添加到您的项目中,并使用org.springframework.context.ApplicationListener键引用您的侦听器,如下例所示:

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

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

  1. ApplicationStartingEvent在运行开始时但在任何处理之前发送,侦听器和初始值设定项的注册除外。

  2. 当知道要在上下文中使用的<ApplicationEnvironmentPreparedEvent>环境时,在创建上下文之前发送代码。

  3. 当准备好<ApplicationContextInitializedEvent>ApplicationContext并且调用了ApplicationContextInitializers时,在加载任何Bean定义之前发送一个Bean。

  4. ApplicationPreparedEvent在开始刷新之前但在加载Bean定义之后发送。

  5. ApplicationStartedEvent是在刷新上下文之后、调用任何应用程序和命令行运行程序之前发送的。

  6. LivenessState.CORRECT之后发送AvailablityChangeEvent,以指示该应用程序被视为活动应用程序。

  7. 在调用了任何应用程序和命令行运行器之后,将发送ApplicationReadyEvent

  8. ReadinessState.ACCEPTING_TRAFFORM之后发送AvailablityChangeEvent,以指示应用程序已准备好为请求提供服务。

  9. 如果启动时出现异常,则发送ApplicationFailedEvent

以上列表仅包括绑定到SpringApplicationSpringApplicationEvent。除此之外,还会在ApplicationPreparedEvent之后、ApplicationStartedEvent之前发布以下事件:

  • WebServer就绪后发送WebServerInitializedEventServletWebServerInitializedEventReactiveWebServerInitializedEvent分别是Servlet和反应型变量。

  • 刷新ApplicationContext时发送ContextRereshedEvent

You often need not use application events, but it can be handy to know that they exist. Internally, Spring Boot uses events to handle a variety of tasks.
Event listeners should not run potentially lengthy tasks as they execute in the same thread by default. Consider using application and command-line runners instead.

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

为了允许侦听器区分其上下文的事件和子代上下文的事件,它应该请求注入其应用程序上下文,然后将注入的上下文与事件的上下文进行比较。可以通过实现ApplicationConextAware来注入上下文,或者如果监听器是一个Bean,则使用@AuTower

1.8. Web Environment

SpringApplication尝试代表您创建正确类型的ApplicationContext。确定WebApplicationType的算法如下:

  • 如果存在Spring MVC,则使用AnnotationConfigServletWebServerApplicationContext

  • 如果不存在Spring MVC而存在Spring WebFlux,则使用AnnotationConfigReactiveWebServerApplicationContext

  • 否则,将使用AnnotationConfigApplicationContext

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

还可以完全控制通过调用setApplicationConextClass(…)使用的<代码>应用程序上下文 类型​)

It is often desirable to call setWebApplicationType(WebApplicationType.NONE) when using SpringApplication within a JUnit test.

1.9. Accessing Application Arguments

如果需要访问传递给SpringApplication.run(…)的应用程序参数代码) ,您可以注入一个Bean。ApplicationArguments接口提供对原始字符串[]参数以及已解析的选项非选项参数的访问,如下例所示:

Java
Kotlin
import java.util.List; import org.springframework.boot.ApplicationArguments; import org.springframework.stereotype.Component; @Component public class MyBean { public MyBean(ApplicationArguments args) { boolean debug = args.containsOption("debug"); List<String> files = args.getNonOptionArgs(); if (debug) { System.out.println(files); } // if run with "--debug logfile.txt" prints ["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.10. Using the ApplicationRunner or CommandLineRunner

如果在SpringApplication启动后需要运行某些特定代码,可以实现ApplicationRunnerCommandLineRunner接口。这两个接口以相同的方式工作,并提供单个<代码>Run 方法,该方法在<代码>SpringApplication.run(…)之前调用​)完成。

This contract is well suited for tasks that should run after application startup but before it starts accepting traffic.

CommandLineRunner接口提供对字符串数组形式的应用程序参数的访问,而ApplicationRunner接口使用前面讨论的ApplicationArguments接口。下面的示例显示具有Run方法的CommandLineRunner

Java
Kotlin
import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; @Component public class MyCommandLineRunner implements CommandLineRunner { @Override public void run(String... args) { // Do something... } } 
            
            

如果定义了几个必须以特定顺序调用的CommandLineRunnerApplicationRunnerBean,则可以另外实现org.springFramework.core.Orded接口或使用org.springframework.core.annotation.Order注释。

1.11. Application Exit

每个SpringApplication都向JVM注册一个关闭挂钩,以确保ApplicationContext在退出时正常关闭。所有标准的Spring生命周期回调(例如DisposableBean接口或@PreDestroy注释)都可以使用。

此外,如果在调用<org.springframework.boot.ExitCodeGenerator>SpringApplication.it()时希望返回特定的退出代码,Bean可能会实现代码接口。然后,可以将此退出代码传递给System.exit(),以将其作为状态代码返回,如下例所示:

Java
Kotlin
import org.springframework.boot.ExitCodeGenerator; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; @SpringBootApplication public class MyApplication { @Bean public ExitCodeGenerator exitCodeGenerator() { return () -> 42; } public static void main(String[] args) { System.exit(SpringApplication.exit(SpringApplication.run(MyApplication.class, args))); } } 
            
            

此外,ExitCodeGenerator接口可以由异常实现。当遇到这样的异常时,Spring Boot返回已实现的getExitCode()方法提供的退出代码。

如果超过ExitCodeGenerator,则使用生成的第一个非零退出代码。要控制调用生成器的顺序,请另外实现org.springFramework.core.Orded接口或使用org.springframework.core.annotation.Order注释。

1.12. Admin Features

可以通过指定spring.Applation.admin.Enabled属性为应用程序启用与管理相关的功能。这将在平台上公开 SpringApplicationAdminMXBean>MBeanServer。您可以使用此功能远程管理您的Spring Boot应用程序。此功能对于任何服务包装器实现也很有用。

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

1.13. Application Startup tracking

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

您可以在设置SpringApplication实例时选择ApplicationStartup实现。例如,要使用BufferingApplicationStartup,您可以编写:

Java
Kotlin
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框架提供的。它将特定于Spring的启动事件添加到Java飞行记录器会话中,用于分析应用程序并将它们的Spring上下文生命周期与JVM事件(如分配、GC、类加载…)关联起来​)。配置后,您可以通过在启用飞行记录器的情况下运行应用程序来记录数据:

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

Spring Boot附带了BufferingApplicationStartup变量;该实现用于缓冲启动步骤并将它们排入外部指标系统。应用程序可以在任何组件中请求BufferingApplicationStartup类型的Bean。

Spring Boot还可以配置为公开启动端点,该端点以JSON文档的形式提供此信息。

2. Externalized Configuration

Spring Boot允许您将配置外部化,这样您就可以在不同的环境中使用相同的应用程序代码。您可以使用各种外部配置源,包括Java属性文件、YAML文件、环境变量和命令行参数。

属性值可以通过使用@Value注释直接注入到您的Bean中,通过Spring的Environment抽象访问,或者通过@ConfigurationProperties绑定到结构化对象

Spring Boot使用了一个非常特殊的PropertySource顺序,旨在允许合理地重写值。以后的特性源可以替代以前的特性源中定义的值。信息来源按以下顺序考虑:

  1. 默认属性(通过设置SpringApplication.setDefaultProperties).指定

  2. @Configuration类上的@PropertySource批注。请注意,在刷新应用程序上下文之前,此类属性源不会添加到环境。这太晚了,无法配置在刷新开始之前读取的某些属性,如Logging.*spring.main.*

  3. 配置数据(如Applation.Properties文件)。

  4. 仅在Ranom.*中具有属性的RandomValuePropertySource

  5. 操作系统环境变量。

  6. Java系统属性(System.getProperties())。

  7. 来自Java:comp/env的JNDI属性。

  8. ServletContext初始化参数。

  9. ServletConfig初始化参数。

  10. 来自SPUNG_APPLICATION_JSON的属性(嵌入在环境变量或系统属性中的内联JSON)。

  11. 命令行参数。

  12. 测试上的属性属性。在@SpringBootTest测试批注上提供,用于测试应用程序的特定片段

  13. @TestPropertySource注释。

  14. 当DevTools处于活动状态时,DevTools全局设置属性位于$HOME/.config/SpringBoot目录中。

配置数据文件按以下顺序考虑:

  1. 打包在JAR中的应用程序属性(应用程序属性和YAML变量)。

  2. 特定于配置文件的应用程序属性打包在您的JAR(application-{profile}.properties和Yaml变体中)。

  3. 应用程序属性在打包的JAR之外(Application.Properties和YAML变体)。

  4. 特定于配置文件的应用程序属性在打包的JAR(application-{profile}.properties和Yaml变体之外)。

It is recommended to stick with one format for your entire application. If you have configuration files with both .properties and .yml format in the same location, .properties takes precedence.

为了提供一个具体的示例,假设您开发了一个使用name属性的@Component,如下例所示:

Java
Kotlin
import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class MyBean { @Value("${name}") private String name; // ... } 
           
           

在您的应用程序类路径上(例如,在您的JAR中),您可以拥有一个为name提供合理的默认属性值的Application.Properties文件。当在新环境中运行时,可以在您的JAR外部提供一个覆盖名称Application.Properties文件。对于一次性测试,您可以使用特定的命令行开关(例如,Java-jar app.jar--name=“Spring”)启动。

The env and configprops endpoints can be useful in determining why a property has a particular value. You can use these two endpoints to diagnose unexpected property values. See the "Production ready features" section for details.

2.1. Accessing Command Line Properties

默认情况下,SpringApplication将任何命令行选项参数(即以--开头的参数,如--server.port=9000)转换为属性,并将它们添加到Spring环境。如前所述,命令行特性始终优先于基于文件的特性源。

如果不希望将命令行属性添加到环境,可以使用SpringApplication.setAddCommandLineProperties(false).禁用它们

2.2. JSON Application Properties

环境变量和系统属性通常有一些限制,这意味着某些属性名称不能使用。为了帮助实现这一点,Spring Boot允许您将属性块编码到单个JSON结构中。

当您的应用程序启动时,任何spring.applation.jsonSpring_APPLICATION_JSON属性都将被解析并添加到Environment

例如,SPUNG_APPLICATION_JSON属性可以作为环境变量在UN*X外壳的命令行中提供:

$ SPRING_APPLICATION_JSON='{"my":{"name":"test"}}' java -jar myapp.jar
            
            

在前面的示例中,您在SpringEnvironment中得到了my.name=test

同样的JSON也可以作为系统属性提供:

$ java -Dspring.application.json='{"my":{"name":"test"}}' -jar myapp.jar
            
            

或者,您可以使用命令行参数提供JSON:

$ java -jar myapp.jar --spring.application.json='{"my":{"name":"test"}}'
            
            

如果要部署到标准应用程序服务器,还可以使用名为java:comp/env/spring.application.json.的jndi变量

Although null values from the JSON will be added to the resulting property source, the PropertySourcesPropertyResolver treats null properties as missing values. This means that the JSON cannot override properties from lower order property sources with a null value.

2.3. External Application Properties

当您的应用程序启动时,Spring Boot将自动从以下位置查找并加载Application.PropertiesApplation.yaml文件:

  1. 从类路径

    1. 类路径根

    2. 类路径/config

  2. 从当前目录

    1. 当前目录

    2. 当前目录中的config/子目录

    3. config/子目录的直接子目录

该列表按优先级排序(较低项的值优先于较早项的值)。加载文件中的文档将作为PropertySources添加到Spring环境

如果您不喜欢应用程序作为配置文件名,可以通过指定spring.config.name环境属性切换到另一个文件名。例如,要查找myproject t.propertiesmyproject t.yaml文件,您可以按如下方式运行应用程序:

$ java -jar myproject.jar --spring.config.name=myproject
            
            

您还可以通过使用spring.config.Location环境属性来引用显式位置。此属性接受要检查的一个或多个位置的逗号分隔列表。

以下示例显示如何指定两个不同的文件:

$ java -jar myproject.jar --spring.config.location=\ optional:classpath:/default.properties,\ optional:classpath:/override.properties
            
            
Use the prefix optional: if the locations are optional and you do not mind if they do not exist.
spring.config.name, spring.config.location, and spring.config.additional-location are used very early to determine which files have to be loaded. They must be defined as an environment property (typically an OS environment variable, a system property, or a command-line argument).

如果spring.config.Location包含目录(而不是文件),则它们应该以/结尾。在运行时,它们将在加载之前附加由spring.config.name生成的名称。直接导入在spring.config.Location中指定的文件。

Both directory and file location values are also expanded to check for profile-specific files. For example, if you have a spring.config.location of classpath:myconfig.properties, you will also find appropriate classpath:myconfig-<profile>.properties files are loaded.

在大多数情况下,您添加的每个spring.config.Location项都将引用单个文件或目录。位置按照定义的顺序进行处理,较晚的位置可以覆盖较早位置的值。

如果您有一个复杂的位置设置,并且您使用特定于配置文件的配置文件,那么您可能需要提供进一步的提示,以便Spring Boot知道应该如何对它们进行分组。位置组是所有被视为同一级别的位置的集合。例如,您可能希望对所有类路径位置进行分组,然后对所有外部位置进行分组。位置组中的项目应使用分隔。有关更多详细信息,请参阅“配置文件特定文件部分中的示例。

使用spring.config.Location配置的位置替换默认位置。例如,如果使用值配置spring.config.Location:可选:classpath:/Custom-config/,可选:file:./Custom-config/,则考虑的完整位置集为:

  1. optional:classpath:custom-config/

  2. 可选:文件:./定制配置/

如果您更喜欢添加其他位置,而不是替换它们,则可以使用spring.config.additional-location.从其他位置加载的特性可以覆盖默认位置中的特性。例如,如果使用值<spring.config.additional-location>配置:类路径:/自定义配置/,可选:文件:./自定义配置/ ,则考虑的完整位置集为:

  1. optional:classpath:/;optional:classpath:/config/

  2. optional:file:./;optional:file:./config/;optional:file:./config/*/

  3. optional:classpath:custom-config/

  4. 可选:文件:./定制配置/

这种搜索顺序允许您在一个配置文件中指定默认值,然后有选择地覆盖另一个配置文件中的这些值。您可以在其中一个默认位置的Application.Properties(或使用spring.config.name选择的任何其他基本名称)中为您的应用程序提供默认值。然后,可以在运行时使用位于其中一个自定义位置的不同文件覆盖这些缺省值。

If you use environment variables rather than system properties, most operating systems disallow period-separated key names, but you can use underscores instead (for example, SPRING_CONFIG_NAME instead of spring.config.name). See Binding From Environment Variables for details.
If your application runs in a servlet container or application server, then JNDI properties (in java:comp/env) or servlet context initialization parameters can be used instead of, or as well as, environment variables or system properties.

2.3.1. Optional Locations

默认情况下,当指定的配置数据位置不存在时,Spring Boot将抛出一个ConfigDataLocationNotFoundException,并且您的应用程序不会启动。

如果您想指定一个位置,但不介意它不总是存在,您可以使用可选:前缀。您可以将该前缀与spring.config.Location spring.config.additional-location>和href=“0”>spring.config.import属性一起使用,也可以与

例如,<optional:file:./myconfig.properties>的spring.config.import值允许应用程序启动,即使myconfig.properties文件丢失也是如此。

如果您希望忽略所有代码并始终继续启动您的应用程序,您可以使用<ConfigDataLocationNotFoundExceptions>spring.config.on-Not-Found属性。使用SpringApplication.setDefaultProperties(…将该值设置为<代码>忽略 ​)或使用系统/环境变量。

2.3.2. Wildcard Locations

如果配置文件位置包含最后一个路径段的*字符,则将其视为通配符位置。加载配置时会展开通配符,以便也会检查直接子目录。当存在多个配置属性源时,通配符位置在Kubernetes等环境中特别有用。

例如,如果您有一些Redis配置和一些MySQL配置,您可能希望将这两部分配置分开,同时要求这两部分都存在于一个Application.Properties文件中。这可能会导致两个单独的应用程序属性文件安装在不同的位置,如/config/redis/application.properties/config/mysql/application.properties.在这种情况下,通配符位置为config/*/将导致处理这两个文件。

默认情况下,Spring Boot在默认搜索位置包含config/*/。这意味着将搜索JAR之外的/config目录的所有子目录。

您可以通过spring.config.Locationspring.config.additional-location属性自己使用通配符位置。

A wildcard location must contain only one * and end with */ for search locations that are directories or */<filename> for search locations that are files. Locations with wildcards are sorted alphabetically based on the absolute path of the file names.
Wildcard locations only work with external directories. You cannot use a wildcard in a classpath: location.

2.3.3. Profile Specific Files

除了应用程序属性文件,Spring Boot还将尝试使用命名约定应用程序-{配置文件}加载特定于配置文件的文件。例如,如果您的应用程序激活了一个名为prod的配置文件并使用YAML文件,那么Application.ymlapplication-prod.yml都将被考虑。

特定于配置文件的属性从与标准应用程序相同的位置加载。属性,特定于配置文件的文件总是覆盖非特定的文件。如果指定了多个配置文件,则应用最后获胜策略。例如,如果配置文件prod、livespring.profiles.active属性指定,则application-prod.properties中的值可以被application-live.properties中的值覆盖。

例如,继续上面的prod,live示例,我们可能有以下文件:

/cfg
  application-live.properties
/ext
  application-live.properties
  application-prod.properties

当我们有classpath:/cfg/,classpath:/ext/spring.config.Location时,我们在处理所有/ext文件之前处理所有/cfg文件:

  1. /cfg/application-live.properties

  2. /ext/app-prod.Properties

  3. /ext/application-live.properties

当我们使用classpath:/cfg/;classpath:/ext/时(使用分隔符),我们在同一级别处理/cfg/ext

  1. /ext/app-prod.Properties

  2. /cfg/application-live.properties

  3. /ext/application-live.properties

Environment有一组默认配置文件(默认情况下为[Default]),如果未设置活动配置文件,则使用这些配置文件。换句话说,如果没有显式激活配置文件,则考虑来自应用程序默认的属性。

Properties files are only ever loaded once. If you have already directly imported a profile specific property files then it will not be imported a second time.

2.3.4. Importing Additional Data

应用程序属性可以使用spring.config.import属性从其他位置导入进一步的配置数据。在发现导入时对其进行处理,并将其视为紧接在声明导入的文档下面插入的附加文档。

例如,您的类路径应用程序属性文件中可能包含以下内容:

Properties
Yaml
spring.application.name=myapp
spring.config.import=optional:file:./dev.properties
             
             

这将触发导入当前目录中的dev.properties文件(如果存在这样的文件)。来自导入的dev.Properties的值将优先于触发导入的文件。在上面的示例中,dev.properties可以将spring.Applation.name重新定义为不同的值。

无论申报多少次,导入都只会导入一次。在属性/YAML文件中的单个文档中定义导入的顺序并不重要。例如,下面的两个示例产生相同的结果:

Properties
Yaml
spring.config.import=my.properties
my.property=value
             
             
Properties
Yaml
my.property=value
spring.config.import=my.properties
             
             

在上述两个示例中,来自my.properties文件的值将优先于触发其导入的文件。

可以在单个spring.config.import项下指定多个位置。将按照定义的顺序处理位置,以后的导入优先。

When appropriate, Profile-specific variants are also considered for import. The example above would import both my.properties as well as any my-<profile>.properties variants.

Spring Boot包括可插拔的API,允许支持各种不同的位置地址。默认情况下,您可以导入Java Properties、YAML和“配置树

第三方JAR可以提供对其他技术的支持(不要求文件必须是本地的)。例如,您可以想象配置数据来自外部存储,如Consul、ApacheZooKeeper或Netflix Archaius。

如果您希望支持您自己的位置,请参见org.springframework.boot.context.config包中的<代码>ConfigDataLocationResolver和ConfigDataLoader类。

2.3.5. Importing Extensionless Files

有些云平台无法为卷装载文件添加文件扩展名。要导入这些无扩展文件,您需要给Spring Boot一个提示,以便它知道如何加载它们。您可以通过将扩展提示放在方括号中来完成此操作。

例如,假设您有一个希望作为YAML导入的/etc/config/myconfig文件。您可以使用以下内容从应用程序导入它:

Properties
Yaml
spring.config.import=file:/etc/config/myconfig[.yaml]
             
             

2.3.6. Using Configuration Trees

在云平台(如Kubernetes)上运行应用程序时,您经常需要读取平台提供的配置值。将环境变量用于此类目的并不少见,但这样做可能会有缺点,特别是在应该对值保密的情况下。

作为环境变量的替代方案,许多云平台现在允许您将配置映射到已装载的数据卷。例如,Kubernetes可以卷装载ConfigMaps秘密

可以使用两种常见的卷装载模式:

  1. 一个文件包含一组完整的属性(通常写为YAML)。

  2. 多个文件被写入目录树,其中文件名成为“关键字”,内容成为“值”。

对于第一种情况,您可以使用上述中描述的spring.config.import直接导入YAML或Properties文件。对于第二种情况,您需要使用configtree:前缀,以便Spring Boot知道它需要将所有文件公开为属性。

例如,假设Kubernetes挂载了以下卷:

etc/
  config/
    myapp/
      username
      password

用户名文件的内容将是配置值,而密码的内容将是机密。

要导入这些属性,您可以将以下内容添加到Application.PropertiesApplication.yaml文件中:

Properties
Yaml
spring.config.import=optional:configtree:/etc/config/
             
             

然后,您可以按照通常的方式从Environment访问或注入myapp.usernamemyapp.password属性。

The folders under the config tree form the property name. In the above example, to access the properties as username and password, you can set spring.config.import to optional:configtree:/etc/config/myapp.
Filenames with dot notation are also correctly mapped. For example, in the above example, a file named myapp.username in /etc/config would result in a myapp.username property in the Environment.
Configuration tree values can be bound to both string String and byte[] types depending on the contents expected.

如果要从同一父文件夹导入多个配置树,则可以使用通配符快捷方式。任何以/*/结尾的configtree:位置都会将所有直接子对象作为配置树导入。

例如,给定以下卷:

etc/
  config/
    dbconfig/
      db/
        username
        password
    mqconfig/
      mq/
        username
        password

您可以使用configtree:/etc/config/*/作为导入位置:

Properties
Yaml
spring.config.import=optional:configtree:/etc/config/*/
             
             

这将添加db.usernamedb.passwordmq.usernamemq.password属性。

Directories loaded using a wildcard are sorted alphabetically. If you need a different order, then you should list each location as a separate import

配置树也可以用于Docker机密。当Docker群服务被授予访问秘密的权限时,该秘密被装载到容器中。例如,如果将名为db.password的密码挂载在/run/secrets/位置,则可以使用以下命令使db.password可用于Spring环境:

Properties
Yaml
spring.config.import=optional:configtree:/run/secrets/
             
             

2.3.7. Property Placeholders

Applation.PropertiesApplation.yml中的值在使用时会通过现有的Environment进行筛选,因此您可以引用以前定义的值(例如,从系统属性或环境变量)。标准${name}属性占位符语法可以在值内的任何位置使用。属性占位符还可以使用指定默认值,以将默认值与属性名称分开,例如${name:Default}

下例显示了带有和不带有默认值的占位符的用法:

Properties
Yaml
app.name=MyApp
app.description=${app.name} is a Spring Boot application written by ${username:Unknown}
             
             

假设用户名属性没有在其他地方设置,app.Description的值将是MyApp是由未知的编写的Spring Boot应用程序。

您应该始终使用占位符中的属性名称的规范形式(仅使用小写字母的烤肉串大小写)来引用属性名称。这将允许Spring Boot使用与松散绑定@ConfigurationProperties相同的逻辑。

例如,${demo.Item-Price}将从Applation.Properties文件中获取demo.Item-Pricedemo.itemPrice表单,以及从系统环境中获取demo_ITEMPRICE表单。如果您使用${demo.itemPrice},则不会考虑demo.itemPricedemo_ITEMPRICE

You can also use this technique to create “short” variants of existing Spring Boot properties. See the howto.html how-to for details.

2.3.8. Working With Multi-Document Files

Spring Boot允许您将单个物理文件拆分成多个逻辑文档,每个逻辑文档都是独立添加的。文件是按照从上到下的顺序处理的。以后的文档可以覆盖以前的文档中定义的属性。

对于applation.yml文件,使用标准的YAML多文档语法。三个连续的连字符表示一个文档的结束,以及下一个文档的开始。

例如,下面的文件有两个逻辑文档:

spring:
  application:
    name: "MyApp"
---
spring:
  application:
    name: "MyCloudApp"
  config:
    activate:
      on-cloud-platform: "kubernetes"
             
             

对于Applation.Properties文件,使用特殊的#-!-注释来标记文档拆分:

spring.application.name=MyApp
#---
spring.application.name=MyCloudApp
spring.config.activate.on-cloud-platform=kubernetes
             
             
Property file separators must not have any leading whitespace and must have exactly three hyphen characters. The lines immediately before and after the separator must not be same comment prefix.
Multi-document property files are often used in conjunction with activation properties such as spring.config.activate.on-profile. See the next section for details.
Multi-document property files cannot be loaded by using the @PropertySource or @TestPropertySource annotations.

2.3.9. Activation Properties

有时,仅在满足某些条件时激活一组给定的属性非常有用。例如,您可能具有仅在特定配置文件处于活动状态时才相关的属性。

您可以有条件地使用spring.config.active.*来激活属性文档。

以下激活属性可用:

Table 2. activation properties
Property Note

配置文件中

文档必须匹配才能处于活动状态的配置文件表达式。

云平台上

必须检测到的CloudPlatform文档才能处于活动状态。

例如,下面的代码指定第二个文档仅当在Kubernetes上运行时才处于活动状态,并且仅当“Prod”或“Staging”配置文件处于活动状态时才处于活动状态:

Properties
Yaml
myprop=always-set
#---
spring.config.activate.on-cloud-platform=kubernetes
spring.config.activate.on-profile=prod | staging
myotherprop=sometimes-set
             
             

2.4. Encrypting Properties

Spring Boot没有为加密属性值提供任何内置支持,但是,它确实提供了修改SpringEnvironment中包含的值所需的钩点。Environment PostProcessor接口允许您在应用程序启动之前操作Environment。有关详细信息,请参阅howto.html

如果您需要一种安全的方式来存储凭据和密码,Spring Cloud文件库项目支持在HashiCorp文件库中存储外部化配置。

2.5. Working With YAML

YAML是JSON的超集,因此是指定分层配置数据的方便格式。只要类路径上有SnakeYAML库,SpringApplication类就会自动支持YAML作为属性的替代。

If you use “Starters”, SnakeYAML is automatically provided by spring-boot-starter.

2.5.1. Mapping YAML to Properties

需要将YAML文档从其分层格式转换为可与Spring环境一起使用的平面结构。例如,考虑以下YAML文档:

environments:
  dev:
    url: "https://dev.example.com"
    name: "Developer Setup"
  prod:
    url: "https://another.example.com"
    name: "My Cool App"
             
             

为了从环境访问这些属性,它们将按如下方式展开:

environments.dev.url=https://dev.example.com
environments.dev.name=Developer Setup
environments.prod.url=https://another.example.com
environments.prod.name=My Cool App
             
             

同样,YAML列表也需要扁平化。它们被表示为带有[index]取消引用的属性键。例如,考虑以下YAML:

my:
 servers:
 - "dev.example.com"
 - "another.example.com"
             
             

前面的示例将转换为以下属性:

my.servers[0]=dev.example.com
my.servers[1]=another.example.com
             
             
Properties that use the [index] notation can be bound to Java List or Set objects using Spring Boot’s Binder class. For more details see the “Type-safe Configuration Properties” section below.
YAML files cannot be loaded by using the @PropertySource or @TestPropertySource annotations. So, in the case that you need to load values that way, you need to use a properties file.

2.5.2. Directly Loading YAML

Spring框架提供了两个方便的类,可用于加载YAML文档。YamlPropertiesFactoryBean将YAML作为Properties加载,而YamlMapFactoryBean将YAML作为Map加载。

如果希望将YAML作为SpringPropertySource加载,也可以使用YamlPropertySourceLoader类。

2.6. Configuring Random Values

RandomValuePropertySource对于注入随机值(例如,注入机密或测试用例)很有用。它可以生成整数、长整型、uuid或字符串,如下例所示:

Properties
Yaml
my.secret=${random.value}
my.number=${random.int}
my.bignumber=${random.long}
my.uuid=${random.uuid}
my.number-less-than-ten=${random.int(10)}
my.number-in-range=${random.int[1024,65536]}
            
            

语法是OPEN VALUE(,max)CLOSE,其中OPEN,CLOSE是任意字符,VALUE,MAX是整数。如果提供了max,则是最小值,max是最大值(独占)。

2.7. Configuring System Environment Properties

Spring Boot支持为环境属性设置前缀。如果系统环境由多个具有不同配置要求的Spring Boot应用程序共享,这将非常有用。可以在SpringApplication上直接设置系统环境属性的前缀。

例如,如果将前缀设置为输入,则在系统环境中,诸如emote.timeout之类的属性也将被解析为input.emote.timeout

2.8. Type-safe Configuration Properties

使用@Value(“${Property}”)注释注入配置属性有时可能很麻烦,尤其是在您使用多个属性或数据本质上是分层的情况下。Spring Boot提供了另一种处理属性的方法,该方法允许强类型的Bean管理和验证应用程序的配置。

2.8.1. JavaBean Properties Binding

可以绑定声明标准JavaBean属性的Bean,如下例所示:

Java
Kotlin
import java.net.InetAddress; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties("my.service") public class MyProperties { private boolean enabled; private InetAddress remoteAddress; private final Security security = new Security();  // getters / setters...  public boolean isEnabled() { return this.enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public InetAddress getRemoteAddress() { return this.remoteAddress; } public void setRemoteAddress(InetAddress remoteAddress) { this.remoteAddress = remoteAddress; } public Security getSecurity() { return this.security; }  public static class Security { private String username; private String password; private List<String> roles = new ArrayList<>(Collections.singleton("USER"));  // getters / setters...  public String getUsername() { return this.username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return this.password; } public void setPassword(String password) { this.password = password; } public List<String> getRoles() { return this.roles; } public void setRoles(List<String> roles) { this.roles = roles; }  } } 
             
             

前面的POJO定义了以下属性:

  • my.service.Enabled,默认为False

  • my.service.Remote-Address,其类型可以从字符串强制。

  • my.service.security.username,具有嵌套的“Security”对象,其名称由属性的名称确定。特别是,那里根本没有使用该类型,并且可能是SecurityProperties

  • my.service.security.password

  • my.service.security.Roles,其中字符串集合默认为用户

The properties that map to @ConfigurationProperties classes available in Spring Boot, which are configured through properties files, YAML files, environment variables, and other mechanisms, are public API but the accessors (getters/setters) of the class itself are not meant to be used directly.

这种安排依赖于缺省的空构造函数,而getter和setter通常是强制的,因为绑定是通过标准的Java Beans属性描述符进行的,就像在Spring MVC中一样。在下列情况下,可以省略定位器:

  • 只要映射被初始化,它们就需要一个getter,但不一定是setter,因为它们可以被绑定器改变。

  • 可以通过索引(通常使用YAML)或使用单个逗号分隔值(属性)访问集合和数组。在后一种情况下,必须使用setter。我们建议始终为这类类型添加setter。如果初始化集合,请确保它不是不可变的(如上例所示)。

  • 如果初始化了嵌套的POJO属性(如前面示例中的Security字段),则不需要setter。如果希望绑定器使用其默认构造函数动态创建实例,则需要一个setter。

有些人使用Project Lombok自动添加getter和setter。确保Lombok不会为这种类型生成任何特定的构造函数,因为容器会自动使用它来实例化对象。

最后,只考虑标准的Java Bean属性,不支持绑定静态属性。

2.8.2. Constructor Binding

上一节中的示例可以以不变的方式重写,如下例所示:

Java
Kotlin
import java.net.InetAddress; import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.bind.DefaultValue; @ConfigurationProperties("my.service") public class MyProperties {  // fields...  private final boolean enabled; private final InetAddress remoteAddress; private final Security security;  public MyProperties(boolean enabled, InetAddress remoteAddress, Security security) { this.enabled = enabled; this.remoteAddress = remoteAddress; this.security = security; }  // getters...  public boolean isEnabled() { return this.enabled; } public InetAddress getRemoteAddress() { return this.remoteAddress; } public Security getSecurity() { return this.security; }  public static class Security {  // fields...  private final String username; private final String password; private final List<String> roles;  public Security(String username, String password, @DefaultValue("USER") List<String> roles) { this.username = username; this.password = password; this.roles = roles; }  // getters...  public String getUsername() { return this.username; } public String getPassword() { return this.password; } public List<String> getRoles() { return this.roles; }  } } 
             
             

在此设置中,单个参数化构造器的存在意味着应该使用构造器绑定。这意味着绑定器将找到一个具有您希望绑定的参数的构造函数。如果您的类有多个构造函数,@ConstructorBinding注释可用于指定用于构造函数绑定的构造函数。要为具有单个参数化构造器的类选择不绑定构造器,构造器必须用@Autwire注释。如果您使用的是Java 16或更高版本,则可以对记录使用构造函数绑定。除非您的记录有多个构造函数,否则不需要使用@ConstructorBinding

构造函数绑定类的嵌套成员(如上面示例中的Security)也将通过它们的构造函数进行绑定。

可以在构造函数参数和记录组件上使用@DefaultValue指定默认值。将应用转换服务将批注的字符串值强制为缺少属性的目标类型。

参考前面的示例,如果没有属性绑定到SecurityMyProperties实例将包含安全性值。要使其包含Security的非空实例,即使在没有绑定任何属性的情况下(使用Kotlin时,这将要求将Security用户名密码参数声明为可以为空,因为它们没有默认值),请使用空的@DefaultValue批注:

Java
Kotlin
public MyProperties(boolean enabled, InetAddress remoteAddress, @DefaultValue Security security) {
    this.enabled = enabled;
    this.remoteAddress = remoteAddress;
    this.security = security;
}

             
             
To use constructor binding the class must be enabled using @EnableConfigurationProperties or configuration property scanning. You cannot use constructor binding with beans that are created by the regular Spring mechanisms (for example @Component beans, beans created by using @Bean methods or beans loaded by using @Import)
To use constructor binding in a native image the class must be compiled with -parameters. This will happen automatically if you use Spring Boot’s Gradle plugin or if you use Maven and spring-boot-starter-parent.
The use of java.util.Optional with @ConfigurationProperties is not recommended as it is primarily intended for use as a return type. As such, it is not well-suited to configuration property injection. For consistency with properties of other types, if you do declare an Optional property and it has no value, null rather than an empty Optional will be bound.

2.8.3. Enabling @ConfigurationProperties-annotated Types

Spring Boot提供了绑定@ConfigurationProperties类型并将它们注册为Bean的基础设施。您可以逐个类地启用配置属性,也可以启用与组件扫描类似的配置属性扫描。

有时,使用@ConfigurationProperties注释的类可能不适合扫描,例如,如果您正在开发自己的自动配置或希望有条件地启用它们。在这些情况下,使用@EnableConfigurationProperties注释指定要处理的类型列表。这可以在任何@Configuration类上完成,如下例所示:

Java
Kotlin
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(SomeProperties.class) public class MyConfiguration { } 
             
             

要使用配置属性扫描,请将@ConfigurationPropertiesScan批注添加到您的应用程序。通常,它被添加到用@SpringBootApplication注释的主应用程序类中,但也可以添加到任何@Configuration类中。默认情况下,扫描将从声明注释的类的包进行。如果要定义要扫描的特定程序包,可以执行以下示例所示的操作:

Java
Kotlin
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.ConfigurationPropertiesScan; @SpringBootApplication @ConfigurationPropertiesScan({ "com.example.app", "com.example.another" }) public class MyApplication { } 
             
             

当使用配置属性扫描或通过@EnableConfigurationProperties注册@ConfigurationPropertiesBean时,该Bean具有常规名称:<;Prefix>;-<;fqn&>;,其中<;Prefix>;@ConfigurationProperties注释中指定的环境键前缀,<;fqn>;是该Bean的完全限定名称。如果注释不提供任何前缀,则只使用Bean的完全限定名称。

上例中的Bean名称为com.example.app-com.example.app.SomeProperties.

我们建议@ConfigurationProperties只处理环境,特别是不要从上下文注入其他Bean。对于特殊情况,可以使用setter注入,也可以使用框架提供的任何*Aware接口(如果需要访问Environment,则可以使用Environment Aware)。如果您仍然希望使用构造函数注入其他Bean,则配置属性Bean必须使用@Component进行注释,并使用基于Java Bean的属性绑定。

2.8.4. Using @ConfigurationProperties-annotated Types

这种配置风格特别适用于SpringApplication外部YAML配置,如下例所示:

my:
  service:
    remote-address: 192.168.1.1
    security:
      username: "admin"
      roles:
      - "USER"
      - "ADMIN"
             
             

要使用@ConfigurationPropertiesBean,您可以像注入任何其他Bean一样注入它们,如下例所示:

Java
Kotlin
import org.springframework.stereotype.Service; @Service public class MyService { private final MyProperties properties; public MyService(MyProperties properties) { this.properties = properties; } public void openConnection() { Server server = new Server(this.properties.getRemoteAddress()); server.start(); // ... } // ... } 
             
             
Using @ConfigurationProperties also lets you generate metadata files that can be used by IDEs to offer auto-completion for your own keys. See the appendix for details.

2.8.5. Third-party Configuration

除了使用@ConfigurationProperties注释类之外,您还可以在公共@Bean方法上使用它。当您想要将属性绑定到您无法控制的第三方组件时,这样做可能特别有用。

要从Environment属性配置Bean,请将@ConfigurationProperties添加到其Bean注册中,如下例所示:

Java
Kotlin
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration(proxyBeanMethods = false) public class ThirdPartyConfiguration { @Bean @ConfigurationProperties(prefix = "another") public AnotherComponent anotherComponent() { return new AnotherComponent(); } } 
             
             

另一个前缀定义的任何JavaBean属性都映射到那个AnotherComponentBean上,其方式类似于前面的SomeProperties示例。

2.8.6. Relaxed Binding

Spring Boot使用一些宽松的规则将Environment属性绑定到@ConfigurationPropertiesBean,因此Environment属性名称和Bean属性名称之间不需要完全匹配。这很有用的常见示例包括以破折号分隔的环境属性(例如,上下文路径绑定到上下文路径)和大写环境属性(例如,端口绑定到端口)。

例如,考虑以下@ConfigurationProperties类:

Java
Kotlin
import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix = "my.main-project.person") public class MyPersonProperties { private String firstName; public String getFirstName() { return this.firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } } 
             
             

在前面的代码中,可以使用以下属性名称:

Table 3. relaxed binding
Property Note

my.main-project.person.first-name

烤肉串大小写,建议在.properties.yml文件中使用。

my.main-project t.Pers.FirstName

标准的驼峰大小写语法。

my.main-project.person.first_name

下划线表示法,这是在.properties.yml文件中使用的另一种格式。

MY_MAINPROJECT_PERSON_FIRSTNAME

大写格式,使用系统环境变量时建议使用。

The prefix value for the annotation must be in kebab case (lowercase and separated by -, such as my.main-project.person).
Table 4. relaxed binding rules per property source
Property Source Simple List

属性文件

驼色大小写、烤肉串大小写或下划线记法

使用[]或逗号分隔值的标准列表语法

YAML文件

驼色大小写、烤肉串大小写或下划线记法

标准YAML列表语法或逗号分隔值

环境变量

以下划线为分隔符的大写格式(请参阅从环境变量绑定)。

用下划线括起来的数值(请参阅从环境变量绑定)

系统属性

驼色大小写、烤肉串大小写或下划线记法

使用[]或逗号分隔值的标准列表语法

We recommend that, when possible, properties are stored in lower-case kebab format, such as my.person.first-name=Rod.
Binding Maps

绑定到Map属性时,可能需要使用特殊的括号表示法,以便保留原始的值。如果键没有被[]括起来,则删除所有不是字母数字、-.的字符。

例如,考虑将以下属性绑定到Map<;字符串

Properties
Yaml
my.map.[/key1]=value1
my.map.[/key2]=value2
my.map./key3=value3
              
              
For YAML files, the brackets need to be surrounded by quotes for the keys to be parsed properly.

上面的属性将绑定到映射,其中/key1/key2key3作为映射中的键。已从key3中删除斜杠,因为它没有用方括号括起来。

绑定到标量值时,其中包含.的键不需要用[]括起来。标量值包括枚举和java.lang包中除对象之外的所有类型。将a.b=c绑定到Map<;字符串&>将保留键中的.,并返回带有条目{“A.B”=“c”}的Map。对于任何其他类型,如果包含.,则需要使用方括号表示法。例如,将a.b=c绑定到Map<;字符串,对象&>将返回条目{“a”={“b”=“c”}}的Map,而[A.B]=c将返回条目{“A.B”=“c”}的Map。

Binding From Environment Variables

大多数操作系统对可用于环境变量的名称实施了严格的规则。例如,Linux外壳变量只能包含字母(azAZ)、数字(09)或下划线字符(_)。按照惯例,Unix外壳变量的名称也是大写的。

Spring Boot松散的绑定规则尽可能地设计为与这些命名限制兼容。

要将规范格式的属性名称转换为环境变量名称,可以遵循以下规则:

  • 将点(.)替换为下划线(_)。

  • 删除所有破折号(-)。

  • 转换为大写。

例如,配置属性spring.main.log-startup-info将是一个名为Spring_main_LOGSTARTUPINFO的环境变量。

绑定到对象列表时也可以使用环境变量。若要绑定到列表,应在变量名中用下划线将元素编号括起来。

例如,配置属性my.service[0].Other将使用名为MY_SERVICE_0_OTHER的环境变量。

2.8.7. Merging Complex Types

当在多个位置配置列表时,覆盖的工作方式是替换整个列表。

例如,假定MyPojo对象的名称描述属性在默认情况下为。下面的示例公开MyProperties中的MyPojo对象的列表:

Java
Kotlin
import java.util.ArrayList; import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties("my") public class MyProperties { private final List<MyPojo> list = new ArrayList<>(); public List<MyPojo> getList() { return this.list; } } 
             
             

请考虑以下配置:

Properties
Yaml
my.list[0].name=my name
my.list[0].description=my description
#---
spring.config.activate.on-profile=dev
my.list[0].name=my another name
             
             

如果dev配置文件处于非活动状态,则MyProperties.list包含一个MyPojo条目,如前所述。但是,如果启用了dev配置文件,列表仍然仅包含一个条目(名称为My Another Name,描述为NULL)。此配置不会将第二个MyPojo实例添加到列表中,也不会合并这些项。

当在多个配置文件中指定列表时,将使用具有最高优先级的配置文件(且仅使用该配置文件)。请考虑以下示例:

Properties
Yaml
my.list[0].name=my name
my.list[0].description=my description
my.list[1].name=another name
my.list[1].description=another description
#---
spring.config.activate.on-profile=dev
my.list[0].name=my another name
             
             

在前面的示例中,如果dev配置文件处于活动状态,则MyProperties.list包含一个MyPojo条目(名称为My Another Name,描述为NULL)。对于YAML,逗号分隔的列表和YAML列表都可以用于完全覆盖列表的内容。

对于Map属性,您可以绑定从多个来源提取的属性值。但是,对于多个源中的同一属性,将使用具有最高优先级的属性。下面的示例公开MyProperties中的Map<;字符串MyPojo&>

Java
Kotlin
import java.util.LinkedHashMap; import java.util.Map; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties("my") public class MyProperties { private final Map<String, MyPojo> map = new LinkedHashMap<>(); public Map<String, MyPojo> getMap() { return this.map; } } 
             
             

请考虑以下配置:

Properties
Yaml
my.map.key1.name=my name 1
my.map.key1.description=my description 1
#---
spring.config.activate.on-profile=dev
my.map.key1.name=dev name 1
my.map.key2.name=dev name 2
my.map.key2.description=dev description 2
             
             

如果dev配置文件处于非活动状态,则MyProperties.map包含一个键为key1的条目(名称为My Name 1,描述为My Description 1)。但是,如果启用了dev配置文件,map将包含两个条目,其中键key1(名称为dev name 1,描述为My Description 1)和key2(名称为dev name 2,描述为dev Description 2)。

The preceding merging rules apply to properties from all property sources, and not just files.

2.8.8. Properties Conversion

当Spring Boot绑定到@ConfigurationPropertiesBean时,它试图将外部应用程序属性强制为正确的类型。如果您需要自定义类型转换,您可以提供ConversionServiceBean(具有名为ConversionService的Bean)或自定义属性编辑器(通过CustomEditorConfigurerBean)或自定义Converters(将Bean定义注释为@ConfigurationPropertiesBinding).

As this bean is requested very early during the application lifecycle, make sure to limit the dependencies that your ConversionService is using. Typically, any dependency that you require may not be fully initialized at creation time. You may want to rename your custom ConversionService if it is not required for configuration keys coercion and only rely on custom converters qualified with @ConfigurationPropertiesBinding.
Converting Durations

Spring Boot专门支持表示持续时间。如果您公开java.time.Duration属性,则应用程序属性中的以下格式可用:

  • 常规表示形式(使用毫秒作为默认单位,除非已指定@DurationUnit)

  • 由使用的标准ISO-8601格式

  • 将值和单位耦合在一起的更易读的格式(10s表示10秒)

请考虑以下示例:

Java
Kotlin
import java.time.Duration; import java.time.temporal.ChronoUnit; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.convert.DurationUnit; @ConfigurationProperties("my") public class MyProperties { @DurationUnit(ChronoUnit.SECONDS) private Duration sessionTimeout = Duration.ofSeconds(30); private Duration readTimeout = Duration.ofMillis(1000);  // getters / setters...  public Duration getSessionTimeout() { return this.sessionTimeout; } public void setSessionTimeout(Duration sessionTimeout) { this.sessionTimeout = sessionTimeout; } public Duration getReadTimeout() { return this.readTimeout; } public void setReadTimeout(Duration readTimeout) { this.readTimeout = readTimeout; } } 
              
              

要将会话超时指定为30秒,30PT30S30s都是等效的。读取超时500ms可以指定为以下任何形式:500PT0.5S500ms

您也可以使用任何受支持的单位。它们是:

  • ns,表示纳秒

  • us微秒

  • ms表示毫秒

  • %s秒数

  • m分钟

  • h小时

  • d天数

默认单位为毫秒,可以使用@DurationUnit覆盖,如上面的示例所示。

如果您更喜欢使用构造函数绑定,则可以公开相同的属性,如下例所示:

Java
Kotlin
import java.time.Duration; import java.time.temporal.ChronoUnit; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.bind.DefaultValue; import org.springframework.boot.convert.DurationUnit; @ConfigurationProperties("my") public class MyProperties {  // fields...  private final Duration sessionTimeout; private final Duration readTimeout;  public MyProperties(@DurationUnit(ChronoUnit.SECONDS) @DefaultValue("30s") Duration sessionTimeout, @DefaultValue("1000ms") Duration readTimeout) { this.sessionTimeout = sessionTimeout; this.readTimeout = readTimeout; }  // getters...  public Duration getSessionTimeout() { return this.sessionTimeout; } public Duration getReadTimeout() { return this.readTimeout; } } 
              
              
If you are upgrading a Long property, make sure to define the unit (using @DurationUnit) if it is not milliseconds. Doing so gives a transparent upgrade path while supporting a much richer format.
Converting Periods

除了持续时间,Spring Boot还可以使用java.time.Period类型。可以在应用程序属性中使用以下格式:

  • 常规的int表示形式(使用天数作为默认单位,除非已指定@PerioUnit)

  • Java.time.Period使用的标准ISO-8601格式

  • 将值和单位对耦合在一起的更简单的格式(1y3d表示1年零3天)

SIMPLE格式支持以下单位:

  • y多年

  • m几个月

  • w数周

  • d天数

The java.time.Period type never actually stores the number of weeks, it is a shortcut that means “7 days”.
Converting Data Sizes

Spring框架具有以字节表示大小的DataSize值类型。如果公开DataSize属性,则应用程序属性中的以下格式可用:

  • 常规表示形式(使用字节作为默认单位,除非已指定@DataSizeUnit)

  • 将值和单位耦合在一起的可读性更强的格式(10MB表示10MB)

请考虑以下示例:

Java
Kotlin
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.convert.DataSizeUnit; import org.springframework.util.unit.DataSize; import org.springframework.util.unit.DataUnit; @ConfigurationProperties("my") public class MyProperties { @DataSizeUnit(DataUnit.MEGABYTES) private DataSize bufferSize = DataSize.ofMegabytes(2); private DataSize sizeThreshold = DataSize.ofBytes(512);  // getters/setters...  public DataSize getBufferSize() { return this.bufferSize; } public void setBufferSize(DataSize bufferSize) { this.bufferSize = bufferSize; } public DataSize getSizeThreshold() { return this.sizeThreshold; } public void setSizeThreshold(DataSize sizeThreshold) { this.sizeThreshold = sizeThreshold; } } 
              
              

若要将缓冲区大小指定为10MB,1010MB是等效的。256字节的大小阈值可以指定为256256B

您也可以使用任何受支持的单位。它们是:

  • B表示字节

  • KB(千字节)

  • MB表示MB

  • GB表示GB

  • TB表示TB

默认单位是字节,可以使用@DataSizeUnit覆盖,如上面的示例所示。

如果您更喜欢使用构造函数绑定,则可以公开相同的属性,如下例所示:

Java
Kotlin
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.bind.DefaultValue; import org.springframework.boot.convert.DataSizeUnit; import org.springframework.util.unit.DataSize; import org.springframework.util.unit.DataUnit; @ConfigurationProperties("my") public class MyProperties {  // fields...  private final DataSize bufferSize; private final DataSize sizeThreshold;  public MyProperties(@DataSizeUnit(DataUnit.MEGABYTES) @DefaultValue("2MB") DataSize bufferSize, @DefaultValue("512B") DataSize sizeThreshold) { this.bufferSize = bufferSize; this.sizeThreshold = sizeThreshold; }  // getters...  public DataSize getBufferSize() { return this.bufferSize; } public DataSize getSizeThreshold() { return this.sizeThreshold; } } 
              
              
If you are upgrading a Long property, make sure to define the unit (using @DataSizeUnit) if it is not bytes. Doing so gives a transparent upgrade path while supporting a much richer format.

2.8.9. @ConfigurationProperties Validation

只要用Spring的@valated批注来批注类,Spring Boot就会尝试验证@ConfigurationProperties类。您可以直接在配置类上使用JSR-303javax.valify约束批注。为此,请确保类路径上存在兼容的JSR-303实现,然后向字段添加约束注释,如下例所示:

Java
Kotlin
import java.net.InetAddress; import jakarta.validation.constraints.NotNull; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.validation.annotation.Validated; @ConfigurationProperties("my.service") @Validated public class MyProperties { @NotNull private InetAddress remoteAddress;  // getters/setters...  public InetAddress getRemoteAddress() { return this.remoteAddress; } public void setRemoteAddress(InetAddress remoteAddress) { this.remoteAddress = remoteAddress; } } 
             
             
You can also trigger validation by annotating the @Bean method that creates the configuration properties with @Validated.

为了确保始终触发对嵌套属性的验证,即使没有找到任何属性,关联的字段也必须使用@Valid进行注释。下面的示例基于前面的MyProperties示例:

Java
Kotlin
import java.net.InetAddress; import jakarta.validation.Valid; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.validation.annotation.Validated; @ConfigurationProperties("my.service") @Validated public class MyProperties { @NotNull private InetAddress remoteAddress; @Valid private final Security security = new Security();  // getters/setters...  public InetAddress getRemoteAddress() { return this.remoteAddress; } public void setRemoteAddress(InetAddress remoteAddress) { this.remoteAddress = remoteAddress; } public Security getSecurity() { return this.security; }  public static class Security { @NotEmpty private String username;  // getters/setters...  public String getUsername() { return this.username; } public void setUsername(String username) { this.username = username; }  } } 
             
             

您还可以通过创建名为configurationPropertiesValidator.的Bean定义来添加自定义Spring<代码>验证器 @Bean方法应声明为静态。配置属性验证器是在应用程序生命周期的早期创建的,如果将@Bean方法声明为静态方法,则无需实例化@Configuration类即可创建Bean。这样做可以避免早期实例化可能导致的任何问题。

The spring-boot-actuator module includes an endpoint that exposes all @ConfigurationProperties beans. Point your web browser to /actuator/configprops or use the equivalent JMX endpoint. See the "Production ready features" section for details.

2.8.10. @ConfigurationProperties vs. @Value

@Value注释是核心容器功能,它不提供与类型安全配置属性相同的功能。下表总结了@ConfigurationProperties@Value支持的功能:

Feature @ConfigurationProperties @Value

松绑

有限(请参阅下面的说明)

元数据支持

不是

规格评估

不是

如果您确实想要使用@Value,我们建议您使用其规范形式(仅使用小写字母的kebab-case)来引用属性名称。这将允许Spring Boot使用与松散绑定@ConfigurationProperties相同的逻辑。

例如,@Value(“${demo.Item-Price}”)将从应用程序.Properties文件中获取demo.Item-Pricedemo.itemPrice表单,以及从系统环境中获取demo_ITEMPRICE。如果您使用@Value(“${demo.itemPrice}”),则不会考虑demo.itemPricedemo_ITEMPRICE

如果您为自己的组件定义了一组配置键,我们建议您将它们分组到用@ConfigurationProperties注释的POJO中。这样做将为您提供结构化的、类型安全的对象,您可以将其注入到您自己的Bean中。

Spel应用程序属性文件中的表达式在分析这些文件并填充环境时不会被处理。但是,可以在@Value中编写Spel表达式。如果应用程序属性文件中的属性的值是Spel表达式,则在通过@Value消费时将对其求值。

3. Profiles

Spring Profile提供了一种分离应用程序配置部分的方法,并使其仅在某些环境中可用。任何@Component@Configuration@ConfigurationProperties都可以在加载时标记为@Profile进行限制,如下例所示:

Java
Kotlin
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; @Configuration(proxyBeanMethods = false) @Profile("production") public class ProductionConfiguration { // ... } 
           
           
If @ConfigurationProperties beans are registered through @EnableConfigurationProperties instead of automatic scanning, the @Profile annotation needs to be specified on the @Configuration class that has the @EnableConfigurationProperties annotation. In the case where @ConfigurationProperties are scanned, @Profile can be specified on the @ConfigurationProperties class itself.

您可以使用spring.profiles.activeEnvironment属性指定哪些配置文件处于活动状态。您可以用本章前面介绍的任何方式指定该属性。例如,您可以将其包含在应用程序中。属性,如下例所示:

Properties
Yaml
spring.profiles.active=dev,hsqldb
           
           

您还可以使用以下开关在命令行中指定它:--spring.profiles.active=dev,hsqldb

如果没有任何配置文件处于活动状态,则启用默认配置文件。默认配置文件的名称为Default,可以使用spring.profiles.DefaultEnvironment属性进行调整,如下例所示:

Properties
Yaml
spring.profiles.default=none
           
           

spring.profiles.activespring.profiles.default只能在非配置文件特定的文档中使用。这意味着它们不能包含在由spring.config.activate.on-profile.激活的特定于配置文件的文件或文档中

例如,第二个文档配置无效:

Properties
Yaml
# this document is valid
spring.profiles.active=prod
#---
# this document is invalid
spring.config.activate.on-profile=prod
spring.profiles.active=metrics
           
           

3.1. Adding Active Profiles

spring.profiles.active属性遵循与其他属性相同的排序规则:最高的PropertySource获胜。这意味着您可以在Application.Properties中指定活动配置文件,然后使用命令行开关替换它们。

有时,让向活动配置文件添加而不是替换它们的属性很有用。spring.profiles.clude属性可用于在由spring.profiles.active属性激活的配置文件之上添加活动配置文件。SpringApplication入口点还具有用于设置其他配置文件的Java API。请参阅SpringApplication中的setAdditionalProfiles()方法。

例如,当运行具有以下属性的应用程序时,即使使用--spring.profiles.active开关运行,公共配置文件和本地配置文件也将被激活:

Properties
Yaml
spring.profiles.include[0]=common
spring.profiles.include[1]=local
            
            
Similar to spring.profiles.active, spring.profiles.include can only be used in non-profile specific documents. This means it cannot be included in profile specific files or documents activated by spring.config.activate.on-profile.

如果给定的配置文件处于活动状态,则下一节中介绍的配置文件组也可用于添加活动配置文件。

3.2. Profile Groups

有时,您在应用程序中定义和使用的配置文件粒度太细,使用起来很麻烦。例如,您可能有proddbprodmq配置文件,用于独立启用数据库和消息传递功能。

为了帮助实现这一点,Spring Boot允许您定义配置文件组。配置文件组允许您为相关的配置文件组定义逻辑名称。

例如,我们可以创建由proddbprodmq配置文件组成的Product组。

Properties
Yaml
spring.profiles.group.production[0]=proddb
spring.profiles.group.production[1]=prodmq
            
            

现在可以使用--spring.profiles.active=production启动我们的应用程序,以一次激活<代码>生产 、<代码>产品 和<代码>产品 配置文件。

3.3. Programmatically Setting Profiles

您可以通过调用SpringApplication.setAdditionalProfiles(…以编程方式设置活动配置文件​)。还可以使用Spring的ConfigurableEnvironment接口激活配置文件。

3.4. Profile-specific Configuration Files

通过@ConfigurationProperties引用的文件和Application.yml的配置文件特定变体都被视为文件并加载。有关详细信息,请参阅配置文件特定文件。

4. Logging

Spring Boot使用Commons Logging进行所有内部日志记录,但底层日志实现是开放的。提供了Java Util日志、Log4j2Logback的默认配置。在每种情况下,记录器都预先配置为使用控制台输出,还可以使用可选的文件输出。

默认情况下,如果您使用starters,则使用Logback进行日志记录。还包括适当的Logback路由,以确保使用Java Util日志记录、Commons日志记录、Log4J或SLF4J的依赖库都能正常工作。

There are a lot of logging frameworks available for Java. Do not worry if the above list seems confusing. Generally, you do not need to change your logging dependencies and the Spring Boot defaults work just fine.
When you deploy your application to a servlet container or application server, logging performed with the Java Util Logging API is not routed into your application’s logs. This prevents logging performed by the container or other applications that have been deployed to it from appearing in your application’s logs.

4.1. Log Format

Spring Boot的默认日志输出类似于以下示例:

2022-11-24T17:02:47.423Z  INFO 18487 --- [           main] o.s.b.d.f.s.MyApplication                : Starting MyApplication using Java 17.0.5 with PID 18487 (/opt/apps/myapp.jar started by myuser in /opt/apps/)
2022-11-24T17:02:47.428Z  INFO 18487 --- [           main] o.s.b.d.f.s.MyApplication                : No active profile set, falling back to 1 default profile: "default"
2022-11-24T17:02:49.682Z  INFO 18487 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2022-11-24T17:02:49.709Z  INFO 18487 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2022-11-24T17:02:49.710Z  INFO 18487 --- [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.1]
2022-11-24T17:02:49.877Z  INFO 18487 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2022-11-24T17:02:49.880Z  INFO 18487 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2384 ms
2022-11-24T17:02:50.499Z  INFO 18487 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2022-11-24T17:02:50.524Z  INFO 18487 --- [           main] o.s.b.d.f.s.MyApplication                : Started MyApplication in 4.578 seconds (process running for 5.179)

将输出以下项目:

  • 日期和时间:毫秒精度,易于分类。

  • 日志级别:错误警告信息调试跟踪

  • 进程ID。

  • 用于区分实际日志消息开头的-分隔符。

  • 线程名称:括在方括号中(可能会被截断以用于控制台输出)。

  • 记录器名称:这通常是源类名称(通常缩写)。

  • 日志消息。

Logback does not have a FATAL level. It is mapped to ERROR.

4.2. Console Output

默认日志配置在写入消息时将消息回显到控制台。默认情况下,会记录错误级别、警告级别和信息级别的消息。您还可以通过使用--DEBUG标志启动应用程序来启用“调试”模式。

$ java -jar myapp.jar --debug
            
            
You can also specify debug=true in your application.properties.

当启用调试模式时,一些核心记录器(嵌入式容器、休眠和Spring Boot)被配置为输出更多信息。启用调试模式不会将应用程序配置为以调试级别记录所有消息。

或者,您可以通过使用--trace标志(或Application.Properties中的trace=true)启动应用程序来启用“跟踪”模式。这样做可以为一系列核心记录器(嵌入式容器、Hibernate模式生成和整个Spring产品组合)启用跟踪日志记录。

4.2.1. Color-coded Output

如果您的终端支持ANSI,则使用颜色输出来提高可读性。您可以将spring.output.ansi.Enabled设置为支持的值以覆盖自动检测。

使用%clr转换字配置颜色编码。在其最简单的形式中,转换器根据对数级别为输出着色,如下例所示:

%clr(%5p)
             
             

下表描述了日志级别到颜色的映射:

Level Color

致命

红色

错误

红色

警告

黄色

信息

绿色

调试

绿色

跟踪

绿色

或者,您可以通过将颜色或样式作为选项提供给转换来指定应该使用的颜色或样式。例如,要将文本设置为黄色,请使用以下设置:

%clr(%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX}){yellow}
             
             

支持以下颜色和样式:

  • 蓝色

  • 青色

  • 晕倒

  • 绿色

  • 洋红色

  • 红色

  • 黄色

4.3. File Output

默认情况下,Spring Boot只记录到控制台,不写入日志文件。如果除了控制台输出之外还要编写日志文件,则需要设置logging.file.namelogging.file.Path属性(例如,在您的应用程序.Properties中)。

下表显示了如何一起使用Logging.*属性:

Table 5. Logging properties
logging.file.name logging.file.path Example Description

(无)

(无)

仅控制台日志记录。

特定文件

(无)

my.log

写入指定的日志文件。名称可以是确切的位置,也可以是相对于当前目录的位置。

(无)

特定目录

/var/log

spring.log写入指定目录。名称可以是确切的位置,也可以是相对于当前目录的位置。

日志文件在达到10 MB时会循环,并且与控制台输出一样,默认情况下会记录错误级别、警告级别和信息级别的消息。

Logging properties are independent of the actual logging infrastructure. As a result, specific configuration keys (such as logback.configurationFile for Logback) are not managed by spring Boot.

4.4. File Rotation

如果您正在使用Logback,则可以使用您的Application.PropertiesApplication.yaml文件来微调日志轮换设置。对于所有其他日志记录系统,您需要直接自己配置循环设置(例如,如果使用Log4j2,则可以添加log4j2.xmllog4j2-spring.xml文件)。

支持以下循环策略属性:

Name Description

logging.logback.rollingpolicy.file-name-pattern

用于创建日志存档的文件名模式。

logging.logback.rollingpolicy.clean-history-on-start

是否应在应用程序启动时进行日志归档清理。

logging.logback.rollingpolicy.max-file-size

存档前日志文件的最大大小。

logging.logback.rollingpolicy.total-size-cap

删除之前可以占用的最大日志档案大小。

logging.logback.rollingpolicy.max-history

要保留的归档日志文件的最大数量(默认为7)。

4.5. Log Levels

所有受支持的日志记录系统都可以通过使用logging.level.<;logger-name>;=<;level>;在Spring环境(例如,在Application.Properties中)设置记录器级别,其中级别是TRACE、DEBUG、INFO、WARN、ERROR、FATAL或OFF之一。记录器可以使用logging.vel.root进行配置。

以下示例显示了Applation.Properties中的潜在日志记录设置:

Properties
Yaml
logging.level.root=warn
logging.level.org.springframework.web=debug
logging.level.org.hibernate=error
            
            

还可以使用环境变量设置日志记录级别。例如,LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_WEB=DEBUG会将org.springFrawork.web设置为调试

The above approach will only work for package level logging. Since relaxed binding always converts environment variables to lowercase, it is not possible to configure logging for an individual class in this way. If you need to configure logging for a class, you can use the SPRING_APPLICATION_JSON variable.

4.6. Log Groups

能够将相关的记录器分组在一起,以便可以同时配置它们,这通常很有用。例如,您可能通常会更改所有Tomcat相关记录器的日志记录级别,但您很难记住顶级包。

为了帮助实现这一点,Spring Boot允许您在Spring环境中定义日志记录组。例如,您可以通过将“tomcat”组添加到应用程序中来定义它。属性

Properties
Yaml
logging.group.tomcat=org.apache.catalina,org.apache.coyote,org.apache.tomcat
            
            

定义后,您可以使用一行更改组中所有记录器的级别:

Properties
Yaml
logging.level.tomcat=trace
            
            

Spring Boot包括以下可开箱即用的预定义日志记录组:

Name Loggers

万维网

org.springFrawork.core.codecorg.springFrawork.httporg.springFrawork.weborg.springframework.boot.actuate.endpoint.weborg.springframework.boot.web.servlet.ServletContextInitializerBeans

SQL

org.springFrawork.jdbc.coreorg.hibernate.SQLorg.jooq.tools.LoggerListener

4.7. Using a Log Shutdown Hook

为了在应用程序终止时释放日志记录资源,提供了一个关闭钩子,它将在JVM退出时触发日志系统清理。除非您的应用程序部署为WAR文件,否则会自动注册此Shutdown挂钩。如果您的应用程序具有复杂的上下文层次结构,则关闭挂钩可能无法满足您的需要。如果没有,请禁用关机挂钩并调查底层日志记录系统直接提供的选项。例如,Logback提供了上下文选择器,允许在其自己的上下文中创建每个Logger。您可以使用logging.Register-Shutdown-Hook属性禁用关闭挂钩。将其设置为False将禁用注册。您可以在Application.PropertiesApplation.yaml文件中设置该属性:

Properties
Yaml
logging.register-shutdown-hook=false
            
            

4.8. Custom Log Configuration

可以通过在类路径上包含适当的库来激活各种日志记录系统,还可以通过在类路径的根目录或由以下SpringEnvironment属性指定的位置提供适当的配置文件来进一步定制日志系统:logging.config

您可以使用org.springframework.boot.logging.LoggingSystem系统属性强制Spring Boot使用特定的日志记录系统。该值应该是LoggingSystem实现的完全限定类名。您还可以使用None值来完全禁用Spring Boot的日志记录配置。

Since logging is initialized before the ApplicationContext is created, it is not possible to control logging from @PropertySources in Spring @Configuration files. The only way to change the logging system or disable it entirely is through System properties.

根据您的日志记录系统,将加载以下文件:

Logging System Customization

登录

logback-spring.xmllogback-spring.groovylogback.xmllogback.groovy

Log4j2

log4j2-spring.xmllog4j2.xml

JDK(Java Util日志记录)

logging.properties

When possible, we recommend that you use the -spring variants for your logging configuration (for example, logback-spring.xml rather than logback.xml). If you use standard configuration locations, Spring cannot completely control log initialization.
There are known classloading issues with Java Util Logging that cause problems when running from an 'executable jar'. We recommend that you avoid it when running from an 'executable jar' if at all possible.

为了帮助进行定制,将其他一些属性从Spring环境传输到系统属性,如下表所述:

Spring Environment System Property Comments

logging.exception-conversion-word

LOG_EXCEPTION_CONVERSION_WORD

记录异常时使用的转换字。

logging.file.name

日志文件

如果已定义,它将在默认日志配置中使用。

logging.file.path

LOG_PATH

如果已定义,它将在默认日志配置中使用。

logging.pattern.控制台

控制台日志模式

要在控制台上使用的日志模式(标准输出)。

logging.pattern.date格式

LOG_DATEFORMAT_Patterns

日志日期格式的附加器模式。

logging.charset.控制台

CONSOLE_LOG_CHARSET

用于控制台日志记录的字符集。

logging.pattern.file

FILE_LOG_Pattern

要在文件中使用的日志模式(如果启用了LOG_FILE)。

logging.charset.file

FILE_LOG_CHARSET

用于文件日志记录的字符集(如果启用了LOG_FILE)。

logging.pattern.Level

LOG_LEVEL_Pattern

呈现日志级别时使用的格式(默认%5p)。

PID

PID

当前进程ID(如果可能且尚未定义为操作系统环境变量时已发现)。

如果使用Logback,还会传输以下属性:

Spring Environment System Property Comments

logging.logback.rollingpolicy.file-name-pattern

LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN

转存日志文件名的模式(默认为${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz).

logging.logback.rollingpolicy.clean-history-on-start

LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START

是否在启动时清除存档日志文件。

logging.logback.rollingpolicy.max-file-size

LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE

最大日志文件大小。

logging.logback.rollingpolicy.total-size-cap

LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP

要保留的日志备份的总大小。

logging.logback.rollingpolicy.max-history

LOGBACK_ROLLINGPOLICY_MAX_HISTORY

要保留的最大归档日志文件数。

所有受支持的日志记录系统在解析其配置文件时都可以参考系统属性。示例请参考Spring-boot.jar中的默认配置:

如果希望在日志属性中使用占位符,则应该使用Spring Boot的语法,而不是底层框架的语法。值得注意的是,如果您使用Logback,您应该使用作为属性名称及其缺省值之间的分隔符,而不是使用:-

您可以通过仅覆盖LOG_LEVEL_PROPERATE(或logging.pattern.Levelwith Logback)将MDC和其他即席内容添加到日志行。例如,如果您使用logging.pattern.Level=user:%X{user}%5p,则默认日志格式包含“user”的MDC条目(如果存在),如下例所示。

2019-08-30 12:30:04.031 user:someone INFO 22174 --- [  nio-8080-exec-0] demo.Controller
Handling authenticated request

4.9. Logback Extensions

Spring Boot包括许多对Logback的扩展,可以帮助进行高级配置。您可以在Logback-spring.xml配置文件中使用这些扩展。

Because the standard logback.xml configuration file is loaded too early, you cannot use extensions in it. You need to either use logback-spring.xml or define a logging.config property.
The extensions cannot be used with Logback’s configuration scanning. If you attempt to do so, making changes to the configuration file results in an error similar to one of the following being logged:
ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:71 - no applicable action for [springProperty], current ElementPath is [[configuration][springProperty]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:71 - no applicable action for [springProfile], current ElementPath is [[configuration][springProfile]]

4.9.1. Profile-specific Configuration

<;springProfile>;标记允许您选择包含或排除基于活动的Spring配置文件的配置部分。配置文件节在<;configuration>;元素中的任何位置都受支持。使用name属性指定哪个配置文件接受配置。<;springProfile>;标记可以包含配置文件名称(例如分段)或配置文件表达式。配置文件表达式允许表达更复杂的配置文件逻辑,例如Products&;(EU-Central|EU-West)。有关详细信息,请查看Spring框架参考指南。下面的清单显示了三个示例配置文件:

<springProfile name="staging">
    <!-- configuration to be enabled when the "staging" profile is active -->
</springProfile>

<springProfile name="dev | staging">
    <!-- configuration to be enabled when the "dev" or "staging" profiles are active -->
</springProfile>

<springProfile name="!production">
    <!-- configuration to be enabled when the "production" profile is not active -->
</springProfile>
             
             

4.9.2. Environment Properties

<;springProperty>;标记允许您公开SpringEnvironment中的属性,以便在Logback中使用。如果您想要访问Logback配置中的应用程序属性文件中的值,那么这样做会很有用。该标记的工作方式类似于Logback的标准<;Property>;标记。但是,不是直接指定,而是指定属性的(从Environment)。如果需要将属性存储在本地范围之外的其他位置,则可以使用范围属性。如果需要回退值(如果Environment中未设置该属性),则可以使用defaultValue属性。以下示例显示如何公开属性以在Logback中使用:

<springProperty scope="context" name="fluentHost" source="myapp.fluentd.host" defaultValue="localhost"/>
<appender name="FLUENT" class="ch.qos.logback.more.appenders.DataFluentAppender">
    <remoteHost>${fluentHost}</remoteHost>
    ...
</appender>
             
             
The source must be specified in kebab case (such as my.property-name). However, properties can be added to the Environment by using the relaxed rules.

4.10. Log4j2 Extensions

Spring Boot包括许多对Log4j2的扩展,可以帮助进行高级配置。您可以在任何log4j2-spring.xml配置文件中使用这些扩展。

Because the standard log4j2.xml configuration file is loaded too early, you cannot use extensions in it. You need to either use log4j2-spring.xml or define a logging.config property.
The extensions supersede the Spring Boot support provided by Log4J. You should make sure not to include the org.apache.logging.log4j:log4j-spring-boot module in your build.

4.10.1. Profile-specific Configuration

<;SpringProfile>;标记允许您选择包含或排除基于活动的Spring配置文件的配置部分。配置文件节在<;configuration>;元素中的任何位置都受支持。使用name属性指定哪个配置文件接受配置。<;SpringProfile&>标记可以包含配置文件名称(例如分段)或配置文件表达式。配置文件表达式允许表达更复杂的配置文件逻辑,例如Products&;(EU-Central|EU-West)。有关详细信息,请查看Spring框架参考指南。下面的清单显示了三个示例配置文件:

<SpringProfile name="staging">
    <!-- configuration to be enabled when the "staging" profile is active -->
</SpringProfile>

<SpringProfile name="dev | staging">
    <!-- configuration to be enabled when the "dev" or "staging" profiles are active -->
</SpringProfile>

<SpringProfile name="!production">
    <!-- configuration to be enabled when the "production" profile is not active -->
</SpringProfile>
             
             

4.10.2. Environment Properties Lookup

如果您想在Log4j2配置中引用来自您的SpringEnvironment的属性,您可以使用前缀Spring:查找。如果您想要访问Log4j2配置中的应用程序属性文件中的值,那么这样做会很有用。

下面的示例显示如何设置名为ApplationName的Log4j2属性,该属性从Spring环境读取spring.applation.name

<Properties>
    <Property name="applicationName">${spring:spring.application.name}</property>
</Properties>
             
             
The lookup key should be specified in kebab case (such as my.property-name).

4.10.3. Log4j2 System Properties

Log4j2支持许多可用于配置各种项目的系统属性。例如,log4j2.skipJansi系统属性可用于配置ConsoleAppender是否将尝试在Windows上使用JANSI输出流。

Log4j2初始化后加载的所有系统属性都可以从SpringEnvironment获取。例如,您可以将log4j2.skipJansi=FALSE添加到Application.Properties文件中,以使ConsoleAppender在Windows上使用JANSI。

The Spring Environment is only considered when system properties and OS environment variables do not contain the value being loaded.
System properties that are loaded during early Log4j2 initialization cannot reference the Spring Environment. For example, the property Log4j2 uses to allow the default Log4j2 implementation to be chosen is used before the Spring Environment is available.

5. Internationalization

Spring Boot支持本地化消息,因此您的应用程序可以迎合不同语言偏好的用户。默认情况下,Spring Boot在类路径的根目录下查找是否存在消息资源包。

The auto-configuration applies when the default properties file for the configured resource bundle is available (messages.properties by default). If your resource bundle contains only language-specific properties files, you are required to add the default. If no properties file is found that matches any of the configured base names, there will be no auto-configured MessageSource.

可以使用spring.Messages命名空间配置资源包的基本名称以及其他几个属性,如下例所示:

Properties
Yaml
spring.messages.basename=messages,config.i18n.messages
spring.messages.fallback-to-system-locale=false
           
           
spring.messages.basename supports comma-separated list of locations, either a package qualifier or a resource resolved from the classpath root.

有关更多支持的选项,请参阅MessageSourceProperties

6. JSON

Spring Boot提供了与三个JSON映射库的集成:

  • GSON

  • 杰克逊

  • JSON-B

Jackson是首选的和默认的库。

6.1. Jackson

提供了Jackson的自动配置,Jackson是Spring-Boot-starter-json的一部分。当Jackson在类路径上时,会自动配置一个ObjectMapperBean。为定制对象映射器的配置提供了几个配置属性。

6.1.1. Custom Serializers and Deserializers

如果您使用Jackson来序列化和反序列化JSON数据,您可能希望编写您自己的JsonSerializerJsonDisializer类。定制序列化程序通常通过模块注册到Jackson,但是Spring Boot提供了一个替代的@JsonComponent注释,使直接注册SpringBean变得更容易。

您可以将@JsonComponent注释直接用于JsonSerializerJsonOverializerKeyDisializer实现。您还可以在包含序列化程序/反序列化程序作为内部类的类上使用它,如下例所示:

Java
Kotlin
import java.io.IOException; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.ObjectCodec; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import org.springframework.boot.jackson.JsonComponent; @JsonComponent public class MyJsonComponent { public static class Serializer extends JsonSerializer<MyObject> { @Override public void serialize(MyObject value, JsonGenerator jgen, SerializerProvider serializers) throws IOException { jgen.writeStartObject(); jgen.writeStringField("name", value.getName()); jgen.writeNumberField("age", value.getAge()); jgen.writeEndObject(); } } public static class Deserializer extends JsonDeserializer<MyObject> { @Override public MyObject deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException { ObjectCodec codec = jsonParser.getCodec(); JsonNode tree = codec.readTree(jsonParser); String name = tree.get("name").textValue(); int age = tree.get("age").intValue(); return new MyObject(name, age); } } } 
             
             

ApplicationContext中的所有@JsonComponentBean都自动注册到Jackson。因为@JsonComponent是用@Component元注释的,所以通常的组件扫描规则适用。

Spring Boot还提供了JsonObjectSerializerJsonObjectDeserializer基类,这些基类在序列化对象时提供了标准Jackson版本的有用替代方案。有关详细信息,请参阅Java中的JsonObjectSerializerJsonObjectDeserializer

上面的示例可以重写为使用JsonObjectSerializer/JsonObjectDeserializer,如下所示:

Java
Kotlin
import java.io.IOException; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.ObjectCodec; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.SerializerProvider; import org.springframework.boot.jackson.JsonComponent; import org.springframework.boot.jackson.JsonObjectDeserializer; import org.springframework.boot.jackson.JsonObjectSerializer; @JsonComponent public class MyJsonComponent { public static class Serializer extends JsonObjectSerializer<MyObject> { @Override protected void serializeObject(MyObject value, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeStringField("name", value.getName()); jgen.writeNumberField("age", value.getAge()); } } public static class Deserializer extends JsonObjectDeserializer<MyObject> { @Override protected MyObject deserializeObject(JsonParser jsonParser, DeserializationContext context, ObjectCodec codec, JsonNode tree) throws IOException { String name = nullSafeValue(tree.get("name"), String.class); int age = nullSafeValue(tree.get("age"), Integer.class); return new MyObject(name, age); } } } 
             
             

6.1.2. Mixins

Jackson支持可用于将其他注释混合到已在目标类上声明的注释中的混合。Spring Boot的Jackson自动配置将扫描应用程序包中使用@JsonMixin注释的类,并将它们注册到自动配置的对象映射器中。注册由Spring Boot的JsonMixinModule执行。

6.2. Gson

提供了GSON的自动配置。当gson位于类路径上时,将自动配置gsonBean。提供了几个spring.gson.*配置属性用于自定义配置。若要获得更多控制,可以使用一个或多个GsonBuilderCustomizerBean。

6.3. JSON-B

提供了JSON-B的自动配置。当JSON-B API和实现位于类路径上时,将自动配置一个JsonbBean。首选的JSON-B实现是为其提供依赖项管理的Eclipse Yasson。

7. Task Execution and Scheduling

在上下文中没有ExecutorBean的情况下,Spring Boot自动配置一个ThreadPoolTaskExecutor,它具有合理的默认值,可以自动与异步任务执行(@EnableAsync)和Spring MVC异步请求处理相关联。

如果您在上下文中定义了自定义Executor,常规任务执行(即@EnableAsync)将透明地使用它,但不会配置Spring MVC支持,因为它需要AsyncTaskExecutor实现(名为ApplationTaskExecutor)。根据您的目标排列,您可以将Executor更改为ThreadPoolTaskExecutor,或者同时定义包装您的自定义ExecutorThreadPoolTaskExecutorAsyncConfigurer

自动配置的TaskExecutorBuilder允许您轻松创建复制自动配置默认操作的实例。

线程池使用8个核心线程,可以根据负载增长和缩小。可以使用spring.task.ecution命名空间对这些默认设置进行微调,如下例所示:

Properties
Yaml
spring.task.execution.pool.max-size=16
spring.task.execution.pool.queue-capacity=100
spring.task.execution.pool.keep-alive=10s
           
           

这会将线程池更改为使用有界队列,以便当队列已满(100个任务)时,线程池将增加到最多16个线程。池的缩小更为激进,因为线程在空闲10秒(而不是默认的60秒)时被回收。

如果需要关联到计划的任务执行(例如使用@EnableScheduling),也可以自动配置ThreadPoolTaskScheduler。线程池默认使用一个线程,可以使用spring.task.Scheduling命名空间对其设置进行微调,如下例所示:

Properties
Yaml
spring.task.scheduling.thread-name-prefix=scheduling-
spring.task.scheduling.pool.size=2
           
           

如果需要创建自定义执行器或调度程序,则可以在上下文中使用TaskExecutorBuilderBean和TaskSchedulerBuilderBean。

8. Testing

Spring Boot在测试应用程序时提供了许多实用程序和注释来帮助您。测试支持由两个模块提供:Spring-boot-test包含核心项,Spring-ot-test-autoconfiguration支持自动配置测试。

大多数开发人员使用SpringBoot-starter-test“starter”,它导入了Spring Boot测试模块以及JUnitJupiter、AssertJ、Hamcrest和许多其他有用的库。

如果您有使用JUnit4的测试,则可以使用JUnit5的老式引擎来运行它们。要使用Vintage引擎,请添加对junit-vintage-Engine的依赖关系,如下例所示:

<dependency>
    <groupId>org.junit.vintage</groupId>
    <artifactId>junit-vintage-engine</artifactId>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>
                
                

hamcrest-core被排除,而支持org.hamcrest:hamcrest,后者是Spring-boot-starter-test的一部分。

8.1. Test Scope Dependencies

Spring-boot-starter-test“starter”(在test作用域中)包含以下提供的库:

  • JUnit5:Java应用程序单元测试的事实标准。

  • Spring测试&;Spring Boot测试:对Spring Boot应用程序的实用程序和集成测试支持。

  • AssertJ:一个流畅的断言库。

  • Hamcrest:匹配器对象库(也称为约束或谓词)。

  • Mockito:Java模拟框架。

  • JSONassert:JSON的断言库。

  • JsonPath:JSON的XPath。

我们通常发现这些通用库在编写测试时很有用。如果这些库不能满足您的需要,您可以添加自己的其他测试依赖项。

8.2. Testing Spring Applications

依赖项注入的主要优势之一是它应该使您的代码更容易进行单元测试。您可以使用new操作符实例化对象,甚至不需要使用Spring。您还可以使用模拟对象而不是实际依赖项。

通常,您需要超越单元测试,开始集成测试(使用SpringApplicationContext)。能够在不需要部署应用程序或连接到其他基础设施的情况下执行集成测试是很有用的。

Spring框架包括用于此类集成测试的专用测试模块。您可以直接向org.springframework:Spring-test声明依赖项,或者使用Spring-ot-starter-test“starter”将其传递地拉入。

如果您以前没有使用过Spring-test模块,那么您应该从阅读Spring框架参考文档的相关小节开始。

8.3. Testing Spring Boot Applications

一个Spring Boot应用程序是一个SpringApplicationContext,因此除了您通常使用普通的Spring上下文进行测试之外,不需要做任何非常特殊的事情来测试它。

External properties, logging, and other features of Spring Boot are installed in the context by default only if you use SpringApplication to create it.

Spring Boot提供了一个@SpringBootTest注释,当您需要Spring Boot功能时,可以使用它作为标准Spring-test@ConextConfiguration注释的替代。注释的工作方式是通过SpringApplication创建测试中使用的ApplicationContext。除了@SpringBootTest之外,还提供了许多其他注释,用于测试应用程序的更具体的片段。

If you are using JUnit 4, do not forget to also add @RunWith(SpringRunner.class) to your test, otherwise the annotations will be ignored. If you are using JUnit 5, there is no need to add the equivalent @ExtendWith(SpringExtension.class) as @SpringBootTest and the other @…​Test annotations are already annotated with it.

默认情况下,@SpringBootTest不会启动服务器。您可以使用@SpringBootTestwebEnvironment属性进一步改进测试的运行方式:

  • 模拟(默认):加载WebApplicationContext并提供模拟Web环境。使用此注释时,嵌入式服务器不会启动。如果您的类路径上没有可用的Web环境,则此模式将透明地退回到创建常规的非WebApplicationContext。它可以与@AutoConfigureMockMvc@AutoConfigureWebTestClient结合使用,用于基于模拟的Web应用程序测试。

  • RANDOM_PORT:加载WebServerApplicationContext,并提供真实的Web环境。启动嵌入式服务器并在随机端口上侦听。

  • Defined_Port:加载WebServerApplicationContext并提供真实的Web环境。嵌入式服务器在已定义的端口(从应用程序属性)或默认端口8080上启动和侦听。

  • :使用SpringApplication加载ApplicationContext,但不提供任何Web环境(模拟或其他)。

If your test is @Transactional, it rolls back the transaction at the end of each test method by default. However, as using this arrangement with either RANDOM_PORT or DEFINED_PORT implicitly provides a real servlet environment, the HTTP client and server run in separate threads and, thus, in separate transactions. Any transaction initiated on the server does not roll back in this case.
@SpringBootTest with webEnvironment = WebEnvironment.RANDOM_PORT will also start the management server on a separate random port if your application uses a different port for the management server.

8.3.1. Detecting Web Application Type

如果Spring MVC可用,则配置常规的基于MVC的应用程序上下文。如果您只有Spring WebFlux,我们将检测到这一点并配置一个基于WebFlux的应用程序上下文。

如果两者都存在,则优先使用Spring MVC。如果要在此方案中测试反应式Web应用程序,则必须设置spring.main.web-app-type属性:

Java
Kotlin
import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest(properties = "spring.main.web-application-type=reactive") class MyWebFluxTests { // ... } 
             
             

8.3.2. Detecting Test Configuration

如果您熟悉Spring测试框架,您可能会习惯于使用<代码>@ConextConfiguration(CLASSES=…​),以指定要加载哪个Spring<代码>@配置 。或者,您可能经常在测试中使用嵌套的@configuration类。

在测试Spring Boot应用程序时,这通常不是必需的。每当您没有显式定义主配置时,Spring Boot的@*测试注释就会自动搜索您的主配置。

搜索算法从包含测试的包开始运行,直到找到一个用@SpringBootApplication@SpringBootConfiguration注释的类。只要您以合理的方式组织代码,通常就可以找到您的主要配置。

如果您使用测试批注来测试应用程序的更具体部分,则应该避免在main方法的应用程序类上添加特定于特定区域的配置设置。

@SpringBootApplication的底层组件扫描配置定义了用于确保切片按预期工作的排除过滤器。如果在@SpringBootApplication注释的类上使用显式的@ComponentScan指令,请注意这些过滤器将被禁用。如果您正在使用切片,则应重新定义它们。

如果您想定制主配置,您可以使用嵌套的@TestConfiguration类。与嵌套的@Configuration类不同,嵌套的@TestConfiguration类除了应用程序的主要配置外,还将使用嵌套的@TestConfiguration类。

Spring’s test framework caches application contexts between tests. Therefore, as long as your tests share the same configuration (no matter how it is discovered), the potentially time-consuming process of loading the context happens only once.

8.3.3. Using the Test Configuration Main Method

通常,@SpringBootTest发现的测试配置将是您的主@SpringBootApplication。在大多数结构良好的应用程序中,此配置类还将包括用于启动应用程序的main方法。

例如,以下是典型的Spring Boot应用程序的一个非常常见的代码模式:

Java
Kotlin
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); } } 
             
             

在上面的示例中,main方法除了委托给SpringApplication.run外,不执行任何操作。但是,也可以使用更复杂的main方法,该方法在调用SpringApplication.run之前应用定制。

例如,下面是一个更改横幅模式并设置其他配置文件的应用程序:

Java
Kotlin
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.setAdditionalProfiles("myprofile"); application.run(args); } } 
             
             

由于main方法中的自定义设置可能会影响生成的ApplicationContext,因此您可能还希望使用main方法来创建测试中使用的ApplicationContext。默认情况下,@SpringBootTest不会调用您的main方法,而是直接使用类本身创建ApplicationContext

如果要更改此行为,可以将@SpringBootTestuseMainMethod属性更改为UseMainMethod.ALWAYSUseMainMethod.WHEN_Available。设置为Always时,如果找不到main方法,则测试将失败。当设置为When_Available时,如果main方法可用,将使用该方法,否则将使用标准加载机制。

例如,下面的测试将调用MyApplicationmain方法,以创建ApplicationContext。如果Main方法设置了其他配置文件,则在ApplicationContext启动时这些配置文件将处于活动状态。

Java
Kotlin
import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.UseMainMethod; @SpringBootTest(useMainMethod = UseMainMethod.ALWAYS) public class MyApplicationTests { @Test void exampleTest() { // ... } } 
             
             

8.3.4. Excluding Test Configuration

如果您的应用程序使用组件扫描(例如,如果您使用@SpringBootApplication@ComponentScan),您可能会发现您仅为特定测试创建的顶级配置类被意外地到处拾取。

正如我们前面所看到的,@TestConfiguration可以在测试的内部类上使用,以定制主要配置。当放在顶级类上时,@TestConfiguration表示src/test/Java中的类不应该通过扫描获得。然后,您可以在需要的地方显式导入该类,如下例所示:

Java
Kotlin
import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Import; @SpringBootTest @Import(MyTestsConfiguration.class) class MyTests { @Test void exampleTest() { // ... } } 
             
             
If you directly use @ComponentScan (that is, not through @SpringBootApplication) you need to register the TypeExcludeFilter with it. See the Javadoc for details.

8.3.5. Using Application Arguments

如果您的应用程序需要参数,您可以使用args属性让@SpringBootTest注入它们。

Java
Kotlin
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.test.context.SpringBootTest; import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest(args = "--app.test=one") class MyApplicationArgumentTests { @Test void applicationArgumentsPopulated(@Autowired ApplicationArguments args) { assertThat(args.getOptionNames()).containsOnly("app.test"); assertThat(args.getOptionValues("app.test")).containsOnly("one"); } } 
             
             

8.3.6. Testing With a Mock Environment

默认情况下,@SpringBootTest不会启动服务器,而是设置一个模拟环境来测试Web端点。

有了Spring MVC,我们可以使用MockMvcWebTestClient查询我们的Web端点,如下例所示:

Java
Kotlin
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @SpringBootTest @AutoConfigureMockMvc class MyMockMvcTests { @Test void testWithMockMvc(@Autowired MockMvc mvc) throws Exception { mvc.perform(get("/")).andExpect(status().isOk()).andExpect(content().string("Hello World")); } // If Spring WebFlux is on the classpath, you can drive MVC tests with a WebTestClient @Test void testWithWebTestClient(@Autowired WebTestClient webClient) { webClient .get().uri("/") .exchange() .expectStatus().isOk() .expectBody(String.class).isEqualTo("Hello World"); } } 
             
             
If you want to focus only on the web layer and not start a complete ApplicationContext, consider using @WebMvcTest instead.

对于Spring WebFlux端点,您可以使用WebTestClient,如下例所示:

Java
Kotlin
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.web.reactive.server.WebTestClient; @SpringBootTest @AutoConfigureWebTestClient class MyMockWebTestClientTests { @Test void exampleTest(@Autowired WebTestClient webClient) { webClient .get().uri("/") .exchange() .expectStatus().isOk() .expectBody(String.class).isEqualTo("Hello World"); } } 
             
             

在模拟环境中进行测试通常比在完整的Servlet容器中运行更快。然而,由于模仿发生在Spring MVC层,依赖于较低级别的Servlet容器行为的代码不能直接使用MockMvc进行测试。

例如,Spring Boot的错误处理基于Servlet容器提供的“错误页面”支持。这意味着,虽然您可以按预期测试MVC层抛出和处理异常,但您不能直接测试是否呈现了特定的自定义错误页面。如果您需要测试这些较低级别的关注点,您可以启动一个完全运行的服务器,如下一节所述。

8.3.7. Testing With a Running Server

如果您需要启动完全运行的服务器,我们建议您使用随机端口。如果您使用@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT),,则每次测试运行时都会随机选择一个可用的端口。

@LocalServerPort注释可用于将实际使用的端口注入测试。为方便起见,需要对启动的服务器进行REST调用的测试可以另外@AuToweraWebTestClient,它解析到正在运行的服务器的相对链接,并附带用于验证响应的专用API,如下例所示:

Java
Kotlin
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.test.web.reactive.server.WebTestClient; @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) class MyRandomPortWebTestClientTests { @Test void exampleTest(@Autowired WebTestClient webClient) { webClient .get().uri("/") .exchange() .expectStatus().isOk() .expectBody(String.class).isEqualTo("Hello World"); } } 
             
             
WebTestClient can be used against both live servers and mock environments.

这个设置需要类路径上的Spring-webFlux。如果您不能或将不会添加WebFlux,Spring Boot还提供了TestRestTemplate功能:

Java
Kotlin
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.boot.test.web.client.TestRestTemplate; import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) class MyRandomPortTestRestTemplateTests { @Test void exampleTest(@Autowired TestRestTemplate restTemplate) { String body = restTemplate.getForObject("/", String.class); assertThat(body).isEqualTo("Hello World"); } } 
             
             

8.3.8. Customizing WebTestClient

若要自定义WebTestClientBean,请配置WebTestClientBuilderCustomizerBean。使用用于创建WebTestClientWebTestClient.Builder调用任何此类Bean。

8.3.9. Using JMX

当测试上下文框架缓存上下文时,默认情况下禁用JMX,以防止相同的组件在同一个域中注册。如果此类测试需要访问MBeanServer,请考虑将其标记为脏:

Java
Kotlin
import javax.management.MBeanServer; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.annotation.DirtiesContext; import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest(properties = "spring.jmx.enabled=true") @DirtiesContext class MyJmxTests { @Autowired private MBeanServer mBeanServer; @Test void exampleTest() { assertThat(this.mBeanServer.getDomains()).contains("java.lang"); // ... } } 
             
             

8.3.10. Using Metrics

无论您的类路径是什么,在使用@SpringBootTest时,仪表注册中心(内存中支持的除外)不会自动配置。

如果您需要将指标导出到不同的后端,作为集成测试的一部分,请使用@AutoConfigureObservability对其进行注释。

8.3.11. Using Tracing

无论您的类路径是什么,当使用@SpringBootTest时,跟踪都不会自动配置。

如果您需要将跟踪作为集成测试的一部分,请使用@AutoConfigureObservability对其进行注释。

8.3.12. Mocking and Spying Beans

在运行测试时,有时有必要模拟应用程序上下文中的某些组件。例如,您可能有一个外观覆盖在开发期间不可用的某些远程服务。当您想要模拟在真实环境中可能很难触发的故障时,模拟也很有用。

Spring Boot包含一个@MockBean注释,可用于为ApplicationContext中的Bean定义Mockito模拟。您可以使用注释来添加新的Bean或替换单个现有的Bean定义。该注释可以直接用于测试类、测试中的字段或@Configuration类和字段。当在一个字段上使用时,创建的模拟的实例也被注入。模拟Bean在每个测试方法之后自动重置。

如果您的测试使用了Spring Boot的某个测试注释(如@SpringBootTest),则会自动启用此功能。要以不同的排列使用此功能,必须显式添加监听程序,如下例所示:

Java
Kotlin
import org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener; import org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestExecutionListeners; @ContextConfiguration(classes = MyConfig.class) @TestExecutionListeners({ MockitoTestExecutionListener.class, ResetMocksTestExecutionListener.class }) class MyTests { // ... } 
                  
                  

下面的示例用模拟实现替换现有的RemoteServiceBean:

Java
Kotlin
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; @SpringBootTest class MyTests { @Autowired private Reverser reverser; @MockBean private RemoteService remoteService; @Test void exampleTest() { given(this.remoteService.getValue()).willReturn("spring"); String reverse = this.reverser.getReverseValue(); // Calls injected RemoteService assertThat(reverse).isEqualTo("gnirps"); } } 
             
             
@MockBean cannot be used to mock the behavior of a bean that is exercised during application context refresh. By the time the test is executed, the application context refresh has completed and it is too late to configure the mocked behavior. We recommend using a @Bean method to create and configure the mock in this situation.

此外,您可以使用@SpyBean用Mockitospy包装任何现有的Bean。有关详细信息,请参阅Javadoc

CGLib proxies, such as those created for scoped beans, declare the proxied methods as final. This stops Mockito from functioning correctly as it cannot mock or spy on final methods in its default configuration. If you want to mock or spy on such a bean, configure Mockito to use its inline mock maker by adding org.mockito:mockito-inline to your application’s test dependencies. This allows Mockito to mock and spy on final methods.
While Spring’s test framework caches application contexts between tests and reuses a context for tests sharing the same configuration, the use of @MockBean or @SpyBean influences the cache key, which will most likely increase the number of contexts.
If you are using @SpyBean to spy on a bean with @Cacheable methods that refer to parameters by name, your application must be compiled with -parameters. This ensures that the parameter names are available to the caching infrastructure once the bean has been spied upon.
When you are using @SpyBean to spy on a bean that is proxied by Spring, you may need to remove Spring’s proxy in some situations, for example when setting expectations using given or when. Use AopTestUtils.getTargetObject(yourProxiedSpy) to do so.

8.3.13. Auto-configured Tests

Spring Boot的自动配置系统对于应用程序工作得很好,但有时测试起来可能有点困难。只加载测试应用程序的“切片”所需的配置部分通常很有帮助。例如,您可能希望测试Spring MVC控制器是否正确映射URL,并且您不希望在这些测试中涉及数据库调用,或者您可能希望测试JPA实体,并且在这些测试运行时您对Web层不感兴趣。

春秋-引导-测试-自动配置模块包括许多可用于自动配置此类“片”的注释。它们的工作方式都相似,都提供了一个<代码>@…加载<​>应用程序上下文和一个或多个<代码>@AutoConfigure…的测试批注​可用于自定义自动配置设置的批注。

Each slice restricts component scan to appropriate components and loads a very restricted set of auto-configuration classes. If you need to exclude one of them, most @…​Test annotations provide an excludeAutoConfiguration attribute. Alternatively, you can use @ImportAutoConfiguration#exclude.
Including multiple “slices” by using several @…​Test annotations in one test is not supported. If you need multiple “slices”, pick one of the @…​Test annotations and include the @AutoConfigure…​ annotations of the other “slices” by hand.
It is also possible to use the @AutoConfigure…​ annotations with the standard @SpringBootTest annotation. You can use this combination if you are not interested in “slicing” your application but you want some of the auto-configured test beans.

8.3.14. Auto-configured JSON Tests

要测试对象JSON序列化和反序列化是否按预期工作,可以使用@JsonTest注释。@JsonTest自动配置可用的受支持的JSON映射器,它可以是下列库之一:

  • Jackson对象映射器、任何@JsonComponentBean和任何Jackson模块

  • gson

  • Jsonb

A list of the auto-configurations that are enabled by @JsonTest can be found in the appendix.

如果需要配置自动配置的元素,可以使用@AutoConfigureJsonTesters注释。

Spring Boot包括基于AssertJ的帮助器,它们使用JSONAssert和JsonPath库来检查JSON是否按预期显示。JacksonTesterGsonTesterJsonbTesterBasicJsonTester类分别可用于Jackson、gson、Jsonb和Strings。当使用@JsonTest时,测试类上的任何helper字段都可以是@AuTower。以下示例显示了Jackson的测试类:

Java
Kotlin
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.json.JsonTest; import org.springframework.boot.test.json.JacksonTester; import static org.assertj.core.api.Assertions.assertThat; @JsonTest class MyJsonTests { @Autowired private JacksonTester<VehicleDetails> json; @Test void serialize() throws Exception { VehicleDetails details = new VehicleDetails("Honda", "Civic"); // Assert against a `.json` file in the same package as the test assertThat(this.json.write(details)).isEqualToJson("expected.json"); // Or use JSON path based assertions assertThat(this.json.write(details)).hasJsonPathStringValue("@.make"); assertThat(this.json.write(details)).extractingJsonPathStringValue("@.make").isEqualTo("Honda"); } @Test void deserialize() throws Exception { String content = "{\"make\":\"Ford\",\"model\":\"Focus\"}"; assertThat(this.json.parse(content)).isEqualTo(new VehicleDetails("Ford", "Focus")); assertThat(this.json.parseObject(content).getMake()).isEqualTo("Ford"); } } 
             
             
JSON helper classes can also be used directly in standard unit tests. To do so, call the initFields method of the helper in your @Before method if you do not use @JsonTest.

如果使用Spring Boot的基于AssertJ的帮助器来断言给定JSON路径上的数值,则可能无法根据类型使用isEqualTo。相反,您可以使用AssertJ的满足值来断言该值匹配给定的条件。例如,下面的示例断言实际数字是偏移量0.01内接近0.15的浮点值。

Java
Kotlin
@Test
void someTest() throws Exception {
    SomeObject value = new SomeObject(0.152f);
    assertThat(this.json.write(value)).extractingJsonPathNumberValue("@.test.numberValue")
            .satisfies((number) -> assertThat(number.floatValue()).isCloseTo(0.15f, within(0.01f)));
}

             
             

8.3.15. Auto-configured Spring MVC Tests

要测试Spring MVC控制器是否按预期工作,请使用@WebMvcTest注释。@WebMvcTest自动配置Spring MVC基础设施,并将扫描的Bean限制为@Controller@ControllerAdvice@JsonComponentConverterGenericConverterFilterHandlerInterceptorWebMvcConfigurerWebMvcRegistrationsHandlerMethodArgentResolver。使用@WebMvcTest注释时,不会扫描常规的@Component@ConfigurationPropertiesBean。@EnableConfigurationProperties可用于包含@ConfigurationPropertiesBean。

A list of the auto-configuration settings that are enabled by @WebMvcTest can be found in the appendix.
If you need to register extra components, such as the Jackson Module, you can import additional configuration classes by using @Import on your test.

通常,@WebMvcTest仅限于单个控制器,并与@MockBean结合使用,为所需的协作者提供模拟实现。

@WebMvcTest还会自动配置MockMvc。模拟MVC提供了一种强大的方法来快速测试MVC控制器,而无需启动完整的HTTP服务器。

You can also auto-configure MockMvc in a non-@WebMvcTest (such as @SpringBootTest) by annotating it with @AutoConfigureMockMvc. The following example uses MockMvc:
Java
Kotlin
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import static org.mockito.BDDMockito.given; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @WebMvcTest(UserVehicleController.class) class MyControllerTests { @Autowired private MockMvc mvc; @MockBean private UserVehicleService userVehicleService; @Test void testExample() throws Exception { given(this.userVehicleService.getVehicleDetails("sboot")) .willReturn(new VehicleDetails("Honda", "Civic")); this.mvc.perform(get("/sboot/vehicle").accept(MediaType.TEXT_PLAIN)) .andExpect(status().isOk()) .andExpect(content().string("Honda Civic")); } } 
             
             
If you need to configure elements of the auto-configuration (for example, when servlet filters should be applied) you can use attributes in the @AutoConfigureMockMvc annotation.

如果您使用HtmlUnit和Selify,自动配置还会提供一个HtmlUnitWebClientBean和/或一个SelifyWebDriverBean。下面的示例使用HtmlUnit:

Java
Kotlin
import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.html.HtmlPage; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; @WebMvcTest(UserVehicleController.class) class MyHtmlUnitTests { @Autowired private WebClient webClient; @MockBean private UserVehicleService userVehicleService; @Test void testExample() throws Exception { given(this.userVehicleService.getVehicleDetails("sboot")).willReturn(new VehicleDetails("Honda", "Civic")); HtmlPage page = this.webClient.getPage("/sboot/vehicle.html"); assertThat(page.getBody().getTextContent()).isEqualTo("Honda Civic"); } } 
             
             
By default, Spring Boot puts WebDriver beans in a special “scope” to ensure that the driver exits after each test and that a new instance is injected. If you do not want this behavior, you can add @Scope("singleton") to your WebDriver @Bean definition.
The webDriver scope created by Spring Boot will replace any user defined scope of the same name. If you define your own webDriver scope you may find it stops working when you use @WebMvcTest.

如果类路径上有Spring Security,@WebMvcTest还将扫描WebSecurityConfigurerBean。您可以使用Spring Security的测试支持,而不是完全禁用此类测试的安全性。有关如何使用Spring Security的MockMvc支持的更多详细信息,可以在howto.html方法部分找到。

Sometimes writing Spring MVC tests is not enough; Spring Boot can help you run full end-to-end tests with an actual server.

8.3.16. Auto-configured Spring WebFlux Tests

要测试Spring WebFlux控制器是否按预期工作,可以使用@WebFlosTest注释。@WebFlosTest自动配置Spring WebFlux基础设施,并将扫描的Bean限制为@Controller@ControllerAdvice@JsonComponentConverterGenericConverterWebFilterWebFLuxConfigurer。使用@WebFlosTest注释时,不会扫描常规的@Component@ConfigurationPropertiesBean。@EnableConfigurationProperties可用于包含@ConfigurationPropertiesBean。

A list of the auto-configurations that are enabled by @WebFluxTest can be found in the appendix.
If you need to register extra components, such as Jackson Module, you can import additional configuration classes using @Import on your test.

通常,@WebFlosTest被限制为单个控制器,并与@MockBean注释结合使用,为所需的协作者提供模拟实现。

@WebFlosTest还自动配置WebTestClient,这提供了一种强大的方法来快速测试WebFlux控制器,而无需启动完整的HTTP服务器。

You can also auto-configure WebTestClient in a non-@WebFluxTest (such as @SpringBootTest) by annotating it with @AutoConfigureWebTestClient. The following example shows a class that uses both @WebFluxTest and a WebTestClient:
Java
Kotlin
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.test.web.reactive.server.WebTestClient; import static org.mockito.BDDMockito.given; @WebFluxTest(UserVehicleController.class) class MyControllerTests { @Autowired private WebTestClient webClient; @MockBean private UserVehicleService userVehicleService; @Test void testExample() { given(this.userVehicleService.getVehicleDetails("sboot")) .willReturn(new VehicleDetails("Honda", "Civic")); this.webClient.get().uri("/sboot/vehicle").accept(MediaType.TEXT_PLAIN).exchange() .expectStatus().isOk() .expectBody(String.class).isEqualTo("Honda Civic"); } } 
             
             
This setup is only supported by WebFlux applications as using WebTestClient in a mocked web application only works with WebFlux at the moment.
@WebFluxTest cannot detect routes registered through the functional web framework. For testing RouterFunction beans in the context, consider importing your RouterFunction yourself by using @Import or by using @SpringBootTest.
@WebFluxTest cannot detect custom security configuration registered as a @Bean of type SecurityWebFilterChain. To include that in your test, you will need to import the configuration that registers the bean by using @Import or by using @SpringBootTest.
Sometimes writing Spring WebFlux tests is not enough; Spring Boot can help you run full end-to-end tests with an actual server.

8.3.17. Auto-configured Spring GraphQL Tests

Spring GraphQL提供了专用的测试支持模块;您需要将其添加到您的项目中:

Maven
<dependencies>
  <dependency>
    <groupId>org.springframework.graphql</groupId>
    <artifactId>spring-graphql-test</artifactId>
    <scope>test</scope>
  </dependency>
  <!-- Unless already present in the compile scope -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
    <scope>test</scope>
  </dependency>
</dependencies>
             
             
Gradle
dependencies {
  testImplementation("org.springframework.graphql:spring-graphql-test")
  // Unless already present in the implementation configuration
  testImplementation("org.springframework.boot:spring-boot-starter-webflux")
}
             
             

此测试模块附带GraphQlTester。Spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/testing.adoc

8.3.18. Auto-configured Data Cassandra Tests

您可以使用@DataCassandraTest测试Cassandra应用程序。默认情况下,它配置CassandraTemplate,扫描@Table类,并配置Spring数据Cassandra存储库。使用@DataCassandraTest注释时,不会扫描常规的@Component@ConfigurationPropertiesBean。@EnableConfigurationProperties可用于包含@ConfigurationPropertiesBean。(有关在Spring Boot中使用Cassandra的更多信息,请参阅“data.html”。)

A list of the auto-configuration settings that are enabled by @DataCassandraTest can be found in the appendix.

以下示例显示了在Spring Boot中使用Cassandra测试的典型设置:

Java
Kotlin
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.data.cassandra.DataCassandraTest; @DataCassandraTest class MyDataCassandraTests { @Autowired private SomeRepository repository; } 
             
             

8.3.19. Auto-configured Data Couchbase Tests

您可以使用@DataCouchbase测试来测试Couchbase应用程序。默认情况下,它配置Couchbase模板Reactive Couchbase模板,扫描@Document类,并配置Spring data Couchbase存储库。当使用@DataCouchbase测试注释时,不会扫描常规的@Component@ConfigurationPropertiesBean。@EnableConfigurationProperties可用于包含@ConfigurationPropertiesBean。(有关在Spring Boot中使用Couchbase的更多信息,请参阅本章前面的“data.html”)。

A list of the auto-configuration settings that are enabled by @DataCouchbaseTest can be found in the appendix.

以下示例显示了在Spring Boot中使用Couchbase测试的典型设置:

Java
Kotlin
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.data.couchbase.DataCouchbaseTest; @DataCouchbaseTest class MyDataCouchbaseTests { @Autowired private SomeRepository repository; // ... } 
             
             

8.3.20. Auto-configured Data Elasticsearch Tests

您可以使用@DataElasticearch测试来测试Elasticearch应用程序。默认情况下,它配置Elasticearch RestTemplate,扫描@Document类,并配置Spring data Elasticearch存储库。使用@DataElasticearch Test注释时,不会扫描常规的@Component@ConfigurationPropertiesBean。@EnableConfigurationProperties可用于包含@ConfigurationPropertiesBean。(有关在Spring Boot中使用Elasticearch的更多信息,请参阅本章前面的“data.html”)。

A list of the auto-configuration settings that are enabled by @DataElasticsearchTest can be found in the appendix.

下面的示例显示了在Spring Boot中使用Elasticearch测试的典型设置:

Java
Kotlin
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.data.elasticsearch.DataElasticsearchTest; @DataElasticsearchTest class MyDataElasticsearchTests { @Autowired private SomeRepository repository; // ... } 
             
             

8.3.21. Auto-configured Data JPA Tests

您可以使用@DataJpaTest注释来测试JPA应用程序。默认情况下,它扫描@Entity类并配置Spring data JPA存储库。如果类路径上有嵌入式数据库可用,它也会配置一个。默认情况下,通过将spring.jpa.show-SQL属性设置为true来记录SQL查询。这可以使用注释的showSql()属性禁用。

使用@DataJpaTest注释时,不会扫描常规的@Component@ConfigurationPropertiesBean。@EnableConfigurationProperties可用于包含@ConfigurationPropertiesBean。

A list of the auto-configuration settings that are enabled by @DataJpaTest can be found in the appendix.

默认情况下,数据JPA测试是事务性的,并在每次测试结束时回滚。有关更多详细信息,请参阅Spring框架参考文档中的相关小节。如果这不是您想要的,您可以禁用一个测试或整个类的事务管理,如下所示:

Java
Kotlin
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @DataJpaTest @Transactional(propagation = Propagation.NOT_SUPPORTED) class MyNonTransactionalTests { // ... } 
             
             
TestEntityManager can also be auto-configured to any of your Spring-based test class by adding @AutoConfigureTestEntityManager. When doing so, make sure that your test is running in a transaction, for instance by adding @Transactional on your test class or method.

如果您需要,也可以使用JdbcTemplate。下面的示例显示正在使用的@DataJpaTest批注:

Java
Kotlin
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; import static org.assertj.core.api.Assertions.assertThat; @DataJpaTest class MyRepositoryTests { @Autowired private TestEntityManager entityManager; @Autowired private UserRepository repository; @Test void testExample() { this.entityManager.persist(new User("sboot", "1234")); User user = this.repository.findByUsername("sboot"); assertThat(user.getUsername()).isEqualTo("sboot"); assertThat(user.getEmployeeNumber()).isEqualTo("1234"); } } 
             
             

内存中的嵌入式数据库通常可以很好地用于测试,因为它们速度很快,不需要任何安装。但是,如果您更喜欢对实际数据库运行测试,则可以使用@AutoConfigureTestDatabase注释,如下例所示:

Java
Kotlin
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; @DataJpaTest @AutoConfigureTestDatabase(replace = Replace.NONE) class MyRepositoryTests { // ... } 
             
             

8.3.22. Auto-configured JDBC Tests

@JdbcTest类似于@DataJpaTest,但用于只需要DataSource且不使用Spring数据JDBC的测试。默认情况下,它配置一个内存中的嵌入式数据库和一个JdbcTemplate。使用@JdbcTest注释时,不会扫描常规的@Component@ConfigurationPropertiesBean。@EnableConfigurationProperties可用于包含@ConfigurationPropertiesBean。

A list of the auto-configurations that are enabled by @JdbcTest can be found in the appendix.

默认情况下,JDBC测试是事务性的,并在每次测试结束时回滚。有关更多详细信息,请参阅Spring框架参考文档中的相关小节。如果这不是您想要的,您可以禁用测试或整个类的事务管理,如下所示:

Java
Kotlin
import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @JdbcTest @Transactional(propagation = Propagation.NOT_SUPPORTED) class MyTransactionalTests { } 
             
             

如果您希望测试在真实的数据库上运行,您可以使用@AutoConfigureTestDatabase注释,方法与DataJpaTest相同。(请参阅“自动配置数据JPA测试”。)

8.3.23. Auto-configured Data JDBC Tests

@DataJdbcTest类似于@JdbcTest,但用于使用Spring data JDBC存储库的测试。默认情况下,它配置内存中的嵌入式数据库、JdbcTemplate和Spring data JDBC存储库。当使用@DataJdbcTest批注时,只扫描AbstractJdbcConfiguration子类,不扫描常规的@Component@ConfigurationPropertiesBean。@EnableConfigurationProperties可用于包含@ConfigurationPropertiesBean。

A list of the auto-configurations that are enabled by @DataJdbcTest can be found in the appendix.

默认情况下,数据JDBC测试是事务性的,并在每次测试结束时回滚。有关更多详细信息,请参阅Spring框架参考文档中的相关小节。如果这不是您想要的,您可以禁用一个测试或整个测试类的事务管理,如所示。

如果您希望测试在真实的数据库上运行,您可以使用@AutoConfigureTestDatabase注释,方法与DataJpaTest相同。(请参阅“自动配置数据JPA测试”。)

8.3.24. Auto-configured jOOQ Tests

您可以使用@JooqTest@JdbcTest类似的方式,但用于与jOOQ相关的测试。由于jOOQ在很大程度上依赖于与数据库模式对应的基于Java的模式,因此使用了现有的DataSource。如果您想用内存中的数据库替换它,您可以使用@AutoConfigureTestDatabase覆盖这些设置。(有关在Spring Boot中使用jOOQ的更多信息,请参阅“data.html”。)使用@JooqTest注释时,不会扫描常规的@Component@ConfigurationPropertiesBean。@EnableConfigurationProperties可用于包含@ConfigurationPropertiesBean。

A list of the auto-configurations that are enabled by @JooqTest can be found in the appendix.

@JooqTest配置DSLContext。下面的示例显示正在使用的@JooqTest批注:

Java
Kotlin
import org.jooq.DSLContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.jooq.JooqTest; @JooqTest class MyJooqTests { @Autowired private DSLContext dslContext; // ... } 
             
             

JOOQ测试是事务性的,默认情况下会在每次测试结束时回滚。如果这不是您想要的,您可以禁用测试或整个测试类的事务管理,如所示,如JDBC示例所示。

8.3.25. Auto-configured Data MongoDB Tests

您可以使用@DataMongoTest测试MongoDB应用程序。默认情况下,它配置一个MongoTemplate,扫描@Document类,并配置Spring data MongoDB存储库。使用@DataMongoTest注释时,不会扫描常规的@Component@ConfigurationPropertiesBean。@EnableConfigurationProperties可用于包含@ConfigurationPropertiesBean。(有关在Spring Boot中使用MongoDB的更多信息,请参阅“data.html”。)

A list of the auto-configuration settings that are enabled by @DataMongoTest can be found in the appendix.

下面的类显示了正在使用的@DataMongoTest批注:

Java
Kotlin
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest; import org.springframework.data.mongodb.core.MongoTemplate; @DataMongoTest class MyDataMongoDbTests { @Autowired private MongoTemplate mongoTemplate; // ... } 
             
             

8.3.26. Auto-configured Data Neo4j Tests

您可以使用@DataNeo4jTest测试Neo4j应用程序。默认情况下,它扫描@Node类,并配置Spring data Neo4j存储库。使用@DataNeo4jTest注释时,不扫描常规的@Component@ConfigurationPropertiesBean。@EnableConfigurationProperties可用于包含@ConfigurationPropertiesBean。(有关在Spring Boot中使用Neo4J的更多信息,请参阅“data.html”。)

A list of the auto-configuration settings that are enabled by @DataNeo4jTest can be found in the appendix.

以下示例显示了在Spring Boot中使用Neo4J测试的典型设置:

Java
Kotlin
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest; @DataNeo4jTest class MyDataNeo4jTests { @Autowired private SomeRepository repository; // ... } 
             
             

默认情况下,Data Neo4j测试是事务性的,并在每次测试结束时回滚。有关更多详细信息,请参阅Spring框架参考文档中的相关小节。如果这不是您想要的,您可以禁用测试或整个类的事务管理,如下所示:

Java
Kotlin
import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @DataNeo4jTest @Transactional(propagation = Propagation.NOT_SUPPORTED) class MyDataNeo4jTests { } 
             
             
Transactional tests are not supported with reactive access. If you are using this style, you must configure @DataNeo4jTest tests as described above.

8.3.27. Auto-configured Data Redis Tests

您可以使用@DataRedisTest测试Redis应用程序。默认情况下,它扫描@RedisHash类并配置Spring data Redis存储库。使用@DataRedisTest注释时,不会扫描常规的@Component@ConfigurationPropertiesBean。@EnableConfigurationProperties可用于包含@ConfigurationPropertiesBean。(有关在Spring Boot中使用Redis的更多信息,请参阅“data.html”。)

A list of the auto-configuration settings that are enabled by @DataRedisTest can be found in the appendix.

下面的示例显示正在使用的@DataRedisTest批注:

Java
Kotlin
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest; @DataRedisTest class MyDataRedisTests { @Autowired private SomeRepository repository; // ... } 
             
             

8.3.28. Auto-configured Data LDAP Tests

您可以使用@DataLdapTest来测试LDAP应用程序。默认情况下,它配置内存中的嵌入式LDAP(如果可用)、配置LdapTemplate、扫描@Entry类以及配置Spring data LDAP存储库。使用@DataLdapTest注释时,不会扫描常规的@Component@ConfigurationPropertiesBean。@EnableConfigurationProperties可用于包含@ConfigurationPropertiesBean。(有关通过Spring Boot使用LDAP的更多信息,请参阅“data.html

A list of the auto-configuration settings that are enabled by @DataLdapTest can be found in the appendix.

下面的示例显示正在使用的@DataLdapTest批注:

Java
Kotlin
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest; import org.springframework.ldap.core.LdapTemplate; @DataLdapTest class MyDataLdapTests { @Autowired private LdapTemplate ldapTemplate; // ... } 
             
             

内存中的嵌入式LDAP通常可以很好地用于测试,因为它速度很快,不需要任何开发人员安装。但是,如果您更喜欢在实际的LDAP服务器上运行测试,则应该排除嵌入式LDAP自动配置,如下例所示:

Java
Kotlin
import org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration; import org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest; @DataLdapTest(excludeAutoConfiguration = EmbeddedLdapAutoConfiguration.class) class MyDataLdapTests { // ... } 
             
             

8.3.29. Auto-configured REST Clients

您可以使用@RestClientTest注释来测试REST客户端。默认情况下,它自动配置Jackson、gson和Jsonb支持,配置RestTemplateBuilder,并添加对MockRestServiceServer的支持。使用@RestClientTest注释时,不会扫描常规的@Component@ConfigurationPropertiesBean。@EnableConfigurationProperties可用于包含@ConfigurationPropertiesBean。

A list of the auto-configuration settings that are enabled by @RestClientTest can be found in the appendix.

应使用@RestClientTest组件属性指定要测试的特定Bean,如下例所示:

Java
Kotlin
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.client.RestClientTest; import org.springframework.http.MediaType; import org.springframework.test.web.client.MockRestServiceServer; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; @RestClientTest(RemoteVehicleDetailsService.class) class MyRestClientTests { @Autowired private RemoteVehicleDetailsService service; @Autowired private MockRestServiceServer server; @Test void getVehicleDetailsWhenResultIsSuccessShouldReturnDetails() { this.server.expect(requestTo("/greet/details")).andRespond(withSuccess("hello", MediaType.TEXT_PLAIN)); String greeting = this.service.callRestService(); assertThat(greeting).isEqualTo("hello"); } } 
             
             

8.3.30. Auto-configured Spring REST Docs Tests

您可以使用@AutoConfigureRestDocs注释在您的Mock MVC、REST Assured或WebTestClient测试中使用Spring rest Docs。它消除了在Spring rest文档中使用JUnit扩展的需要。

@AutoConfigureRestDocs可用于覆盖默认输出目录(如果您使用的是Maven,则目标/生成的代码片段;如果您使用的是Gradle,则构建/生成的代码片段)。它还可用于配置出现在任何记录的URI中的主机、方案和端口。

Auto-configured Spring REST Docs Tests With Mock MVC

@AutoConfigureRestDocs定制MockMvcBean,在测试基于Servlet的Web应用程序时使用Spring REST文档。您可以使用@Autwire注入它,并像使用Mock MVC和Spring REST文档时一样在测试中使用它,如下例所示:

Java
Kotlin
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @WebMvcTest(UserController.class) @AutoConfigureRestDocs class MyUserDocumentationTests { @Autowired private MockMvc mvc; @Test void listUsers() throws Exception { this.mvc.perform(get("/users").accept(MediaType.TEXT_PLAIN)) .andExpect(status().isOk()) .andDo(document("list-users")); } } 
              
              

如果您需要比<RestDocsMockMvcConfigurationCustomizer>@AutoConfigureRestDocs属性所提供的更多的对Spring rest Docs配置的控制,您可以使用Spring Bean,如下例所示:

Java
Kotlin
import org.springframework.boot.test.autoconfigure.restdocs.RestDocsMockMvcConfigurationCustomizer; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.restdocs.mockmvc.MockMvcRestDocumentationConfigurer; import org.springframework.restdocs.templates.TemplateFormats; @TestConfiguration(proxyBeanMethods = false) public class MyRestDocsConfiguration implements RestDocsMockMvcConfigurationCustomizer { @Override public void customize(MockMvcRestDocumentationConfigurer configurer) { configurer.snippets().withTemplateFormat(TemplateFormats.markdown()); } } 
              
              

如果您希望利用Spring rest Docs对参数化输出目录的支持,您可以创建一个RestDocumentationResultHandlerBean。自动配置总是使用此结果处理程序调用Do,从而导致每个MockMvc调用自动生成默认代码片段。下面的示例显示了正在定义的RestDocumentationResultHandler

Java
Kotlin
import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation; import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; @TestConfiguration(proxyBeanMethods = false) public class MyResultHandlerConfiguration { @Bean public RestDocumentationResultHandler restDocumentation() { return MockMvcRestDocumentation.document("{method-name}"); } } 
              
              
Auto-configured Spring REST Docs Tests With WebTestClient

@AutoConfigureRestDocs在测试反应性Web应用程序时还可以与WebTestClient一起使用。您可以使用@AuTower注入它,并在测试中使用它,就像您通常使用@WebFlosTest和Spring REST文档一样,如下例所示:

Java
Kotlin
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; import org.springframework.test.web.reactive.server.WebTestClient; import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document; @WebFluxTest @AutoConfigureRestDocs class MyUsersDocumentationTests { @Autowired private WebTestClient webTestClient; @Test void listUsers() { this.webTestClient .get().uri("/") .exchange() .expectStatus() .isOk() .expectBody() .consumeWith(document("list-users")); } } 
              
              

如果您需要比<RestDocsWebTestClientConfigurationCustomizer>@AutoConfigureRestDocs属性所提供的更多的对Spring rest Docs配置的控制,您可以使用Spring Bean,如下例所示:

Java
Kotlin
import org.springframework.boot.test.autoconfigure.restdocs.RestDocsWebTestClientConfigurationCustomizer; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentationConfigurer; @TestConfiguration(proxyBeanMethods = false) public class MyRestDocsConfiguration implements RestDocsWebTestClientConfigurationCustomizer { @Override public void customize(WebTestClientRestDocumentationConfigurer configurer) { configurer.snippets().withEncoding("UTF-8"); } } 
              
              

如果您想使用Spring REST Docs对参数化输出目录的支持,您可以使用WebTestClientBuilderCustomizer为每个实体交换结果配置一个使用者。下面的示例显示正在定义这样一个WebTestClientBuilderCustomizer

Java
Kotlin
import org.springframework.boot.test.context.TestConfiguration; import org.springframework.boot.test.web.reactive.server.WebTestClientBuilderCustomizer; import org.springframework.context.annotation.Bean; import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document; @TestConfiguration(proxyBeanMethods = false) public class MyWebTestClientBuilderCustomizerConfiguration { @Bean public WebTestClientBuilderCustomizer restDocumentation() { return (builder) -> builder.entityExchangeResultConsumer(document("{method-name}")); } } 
              
              
Auto-configured Spring REST Docs Tests With REST Assured

@AutoConfigureRestDocs使RequestSpecificationBean可用于您的测试,该Bean已预配置为使用Spring REST文档。您可以使用@Autwire注入它,并像使用REST Assured和Spring REST文档时一样在测试中使用它,如下例所示:

Java
Kotlin
import io.restassured.specification.RequestSpecification; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.boot.test.web.server.LocalServerPort; import static io.restassured.RestAssured.given; import static org.hamcrest.Matchers.is; import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document; @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @AutoConfigureRestDocs class MyUserDocumentationTests { @Test void listUsers(@Autowired RequestSpecification documentationSpec, @LocalServerPort int port) { given(documentationSpec) .filter(document("list-users")) .when() .port(port) .get("/") .then().assertThat() .statusCode(is(200)); } } 
              
              

如果您需要比<RestDocsRestAssuredConfigurationCustomizer>@AutoConfigureRestDocs属性更好地控制Spring rest Docs配置,则可以使用Spring Bean,如下例所示:

Java
Kotlin
import org.springframework.boot.test.autoconfigure.restdocs.RestDocsRestAssuredConfigurationCustomizer; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.restdocs.restassured.RestAssuredRestDocumentationConfigurer; import org.springframework.restdocs.templates.TemplateFormats; @TestConfiguration(proxyBeanMethods = false) public class MyRestDocsConfiguration implements RestDocsRestAssuredConfigurationCustomizer { @Override public void customize(RestAssuredRestDocumentationConfigurer configurer) { configurer.snippets().withTemplateFormat(TemplateFormats.markdown()); } } 
              
              

8.3.31. Auto-configured Spring Web Services Tests

Auto-configured Spring Web Services Client Tests

您可以使用@WebServiceClientTest来测试使用Spring Web Services项目调用Web服务的应用程序。默认情况下,它配置一个模拟WebServiceServerBean,并自动定制您的WebServiceTemplateBuilder。(有关在Spring Boot中使用Web服务的更多信息,请参阅“io.html”。)

A list of the auto-configuration settings that are enabled by @WebServiceClientTest can be found in the appendix.

下面的示例显示正在使用的@WebServiceClientTest批注:

Java
Kotlin
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.webservices.client.WebServiceClientTest; import org.springframework.ws.test.client.MockWebServiceServer; import org.springframework.xml.transform.StringSource; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.ws.test.client.RequestMatchers.payload; import static org.springframework.ws.test.client.ResponseCreators.withPayload; @WebServiceClientTest(SomeWebService.class) class MyWebServiceClientTests { @Autowired private MockWebServiceServer server; @Autowired private SomeWebService someWebService; @Test void mockServerCall() { this.server .expect(payload(new StringSource("<request/>"))) .andRespond(withPayload(new StringSource("<response><status>200</status></response>"))); assertThat(this.someWebService.test()) .extracting(Response::getStatus) .isEqualTo(200); } } 
              
              
Auto-configured Spring Web Services Server Tests

您可以使用@WebServiceServerTest来测试使用Spring Web Services项目实现Web服务的应用程序。默认情况下,它配置一个可用于调用您的Web服务端点的MockWebServiceClientBean。(有关在Spring Boot中使用Web服务的更多信息,请参阅“io.html”。)

A list of the auto-configuration settings that are enabled by @WebServiceServerTest can be found in the appendix.

下面的示例显示正在使用的@WebServiceServerTest批注:

Java
Kotlin
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.webservices.server.WebServiceServerTest; import org.springframework.ws.test.server.MockWebServiceClient; import org.springframework.ws.test.server.RequestCreators; import org.springframework.ws.test.server.ResponseMatchers; import org.springframework.xml.transform.StringSource; @WebServiceServerTest(ExampleEndpoint.class) class MyWebServiceServerTests { @Autowired private MockWebServiceClient client; @Test void mockServerCall() { this.client .sendRequest(RequestCreators.withPayload(new StringSource("<ExampleRequest/>"))) .andExpect(ResponseMatchers.payload(new StringSource("<ExampleResponse>42</ExampleResponse>"))); } } 
              
              

8.3.32. Additional Auto-configuration and Slicing

每个切片提供一个或多个@AutoConfigure…​注释,即定义应该作为片的一部分包括的自动配置。通过创建自定义@AutoConfigure…,可以在逐个测试的基础上添加其他自动配置​批注或将@ImportAutoConfiguration添加到测试中,如下例所示:

Java
Kotlin
import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration; import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest; @JdbcTest @ImportAutoConfiguration(IntegrationAutoConfiguration.class) class MyJdbcTests { } 
             
             
Make sure to not use the regular @Import annotation to import auto-configurations as they are handled in a specific way by Spring Boot.

或者,通过将切片批注注册到存储在META-INF/Spring中的文件中,可以为切片批注的任何使用添加其他自动配置,如下例所示:

META-INF/spring/org.springframework.boot.test.autoconfigure.jdbc.JdbcTest.imports
com.example.IntegrationAutoConfiguration

在本例中,在使用<com.example.IntegrationAutoConfiguration>@JDBCTest注释的每个测试上都启用了代码。

You can use comments via # in this file.
A slice or @AutoConfigure…​ annotation can be customized this way as long as it is meta-annotated with @ImportAutoConfiguration.

8.3.33. User Configuration and Slicing

如果您以合理的方式组织代码,则您的@SpringBootApplication类默认用作测试的配置。

然后,重要的是不要在应用程序的主类中使用特定于其功能的特定区域的配置设置。

假设您使用的是Spring Batch,并且依赖于它的自动配置。您可以按如下方式定义@SpringBootApplication

Java
Kotlin
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableBatchProcessing public class MyApplication { // ... } 
             
             

因为这个类是测试的源代码配置,所以任何切片测试实际上都会尝试启动Spring Batch,这绝对不是您想要做的事情。推荐的方法是将该区域特定的配置移动到与您的应用程序处于同一级别的单独@Configuration类,如下例所示:

Java
Kotlin
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.context.annotation.Configuration; @Configuration(proxyBeanMethods = false) @EnableBatchProcessing public class MyBatchConfiguration { // ... } 
             
             
Depending on the complexity of your application, you may either have a single @Configuration class for your customizations or one class per domain area. The latter approach lets you enable it in one of your tests, if necessary, with the @Import annotation. See this how-to section for more details on when you might want to enable specific @Configuration classes for slice tests.

测试切片从扫描中排除@Configuration类。例如,对于@WebMvcTest,以下配置不会在测试片加载的应用程序上下文中包括给定的WebMvcConfigurerBean:

Java
Kotlin
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration(proxyBeanMethods = false) public class MyWebConfiguration { @Bean public WebMvcConfigurer testConfigurer() { return new WebMvcConfigurer() { // ... }; } } 
             
             

然而,下面的配置将导致测试切片加载定制的WebMvcConfigurer

Java
Kotlin
import org.springframework.stereotype.Component; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Component public class MyWebMvcConfigurer implements WebMvcConfigurer { // ... } 
             
             

另一个令人困惑的原因是类路径扫描。假设虽然您以合理的方式构建了代码,但您需要扫描一个额外的包。您的应用程序可能类似于以下代码:

Java
Kotlin
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan; @SpringBootApplication @ComponentScan({ "com.example.app", "com.example.another" }) public class MyApplication { // ... } 
             
             

这样做有效地覆盖了默认的组件扫描指令,其副作用是扫描这两个包,而不管您选择的是哪个切片。例如,@DataJpaTest似乎突然扫描应用程序的组件和用户配置。同样,将定制指令移到单独的类中是解决此问题的好方法。

If this is not an option for you, you can create a @SpringBootConfiguration somewhere in the hierarchy of your test so that it is used instead. Alternatively, you can specify a source for your test, which disables the behavior of finding a default one.

8.3.34. Using Spock to Test Spring Boot Applications

Spock 2.2或更高版本可用于测试Spring Boot应用程序。为此,将Spock的-groovy-4.0版本的Spock-Spring模块的依赖项添加到应用程序的构建中。Spock-Spring将Spring的测试框架集成到Spock中。有关详细信息,请参阅Spock的Spring模块文档

8.4. Test Utilities

在测试应用程序时通常有用的几个测试实用程序类被打包为SpringBoot的一部分。

8.4.1. ConfigDataApplicationContextInitializer

ConfigDataApplicationContextInitializer是一个ApplicationContextInitializer,您可以将其应用于您的测试以加载Spring BootApplication.Properties文件。当您不需要@SpringBootTest提供的全套功能时,可以使用它,如下例所示:

Java
Kotlin
import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer; import org.springframework.test.context.ContextConfiguration; @ContextConfiguration(classes = Config.class, initializers = ConfigDataApplicationContextInitializer.class) class MyConfigFileTests { // ... } 
             
             
Using ConfigDataApplicationContextInitializer alone does not provide support for @Value("${…​}") injection. Its only job is to ensure that application.properties files are loaded into Spring’s Environment. For @Value support, you need to either additionally configure a PropertySourcesPlaceholderConfigurer or use @SpringBootTest, which auto-configures one for you.

8.4.2. TestPropertyValues

TestPropertyValues允许您向ConfigurableEnvironmentConfigurableApplicationContext快速添加属性。您可以使用key=Value字符串进行调用,如下所示:

Java
Kotlin
import org.junit.jupiter.api.Test; import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.mock.env.MockEnvironment; import static org.assertj.core.api.Assertions.assertThat; class MyEnvironmentTests { @Test void testPropertySources() { MockEnvironment environment = new MockEnvironment(); TestPropertyValues.of("org=Spring", "name=Boot").applyTo(environment); assertThat(environment.getProperty("name")).isEqualTo("Boot"); } } 
             
             

8.4.3. OutputCapture

OutputCapture是一个JUnit扩展,可用于捕获System.outSystem.err输出。要使用Add@ExtendWith(OutputCaptureExtension.class)并将CapturedOutput作为参数注入测试类构造函数或测试方法,如下所示:

Java
Kotlin
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.OutputCaptureExtension; import static org.assertj.core.api.Assertions.assertThat; @ExtendWith(OutputCaptureExtension.class) class MyOutputCaptureTests { @Test void testName(CapturedOutput output) { System.out.println("Hello World!"); assertThat(output).contains("World"); } } 
             
             

8.4.4. TestRestTemplate

TestRestTemplate是用于集成测试的Spring的RestTemplate的一个方便的替代方案。您可以获得普通模板或发送基本HTTP身份验证的模板(带有用户名和密码)。在任何一种情况下,模板都是容错的。这意味着它以一种测试友好的方式运行,不会在4xx和5xx错误中引发异常。相反,可以通过返回的ResponseEntity及其状态代码来检测此类错误。

Spring Framework 5.0 provides a new WebTestClient that works for WebFlux integration tests and both WebFlux and MVC end-to-end testing. It provides a fluent API for assertions, unlike TestRestTemplate.

建议(但不是强制)使用Apache HTTP客户端(版本4.3.2或更高版本)。如果您的类路径中有它,TestRestTemplate通过适当地配置客户端来响应。如果您使用的是ApacheHTTP客户端,则会启用一些额外的测试友好特性:

  • 不遵循重定向(因此您可以断言响应位置)。

  • Cookie被忽略(因此模板是无状态的)。

TestRestTemplate可以在集成测试中直接实例化,如下例所示:

Java
Kotlin
import org.junit.jupiter.api.Test; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.http.ResponseEntity; import static org.assertj.core.api.Assertions.assertThat; class MyTests { private final TestRestTemplate template = new TestRestTemplate(); @Test void testRequest() { ResponseEntity<String> headers = this.template.getForEntity("https://myhost.example.com/example", String.class); assertThat(headers.getHeaders().getLocation()).hasHost("other.example.com"); } } 
             
             

或者,如果您将@SpringBootTest批注与WebEnvironmental ment.RANDOM_PORTWebEnvironmental ment.DEFINED_PORT一起使用,则可以注入一个完全配置的TestRestTemplate并开始使用它。如果需要,可以通过RestTemplateBuilderBean应用其他定制。任何未指定主机和端口的URL都会自动连接到嵌入式服务器,如下例所示:

Java
Kotlin
import java.time.Duration; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.context.annotation.Bean; import org.springframework.http.HttpHeaders; import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) class MySpringBootTests { @Autowired private TestRestTemplate template; @Test void testRequest() { HttpHeaders headers = this.template.getForEntity("/example", String.class).getHeaders(); assertThat(headers.getLocation()).hasHost("other.example.com"); } @TestConfiguration(proxyBeanMethods = false) static class RestTemplateBuilderConfiguration { @Bean RestTemplateBuilder restTemplateBuilder() { return new RestTemplateBuilder().setConnectTimeout(Duration.ofSeconds(1)) .setReadTimeout(Duration.ofSeconds(1)); } } } 
             
             

9. Creating Your Own Auto-configuration

如果您在一家开发共享库的公司工作,或者如果您在开放源码或商业库上工作,您可能希望开发自己的自动配置。自动配置类可以捆绑在外部JAR中,并且仍然可以由Spring Boot获取。

自动配置可以与提供自动配置代码以及您将与其一起使用的典型库的“启动器”相关联。我们首先介绍构建您自己的自动配置所需了解的知识,然后介绍创建自定义入门程序所需的典型步骤。

9.1. Understanding Auto-configured Beans

实现自动配置的类使用@Autoconfiguration进行注释。该注释本身使用@configuration进行元注释,从而使自动配置成为标准的@configuration类。附加的@Conditional注释用于约束何时应用自动配置。通常,自动配置类使用@ConditionalOnClass@ConditionalOnMissingBean注释。这确保了只有当找到相关类并且您没有声明您自己的@configuration时,才会应用自动配置。

您可以浏览spring-boot-autoconfigure的源代码以查看Spring提供的<代码>@AutoConfiguration类 (参见META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件)。

9.2. Locating Auto-configuration Candidates

Spring Boot检查已发布的JAR中是否存在META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件。该文件应列出您的配置类,每行一个类名,如下例所示:

com.mycorp.libx.autoconfigure.LibXAutoConfiguration
com.mycorp.libx.autoconfigure.LibXWebAutoConfiguration
You can add comments to the imports file using the # character.
Auto-configurations must be loaded only by being named in the imports file. Make sure that they are defined in a specific package space and that they are never the target of component scanning. Furthermore, auto-configuration classes should not enable component scanning to find additional components. Specific @Imports should be used instead.

如果您的配置需要以特定的顺序应用,您可以在@AutoConfigurationTM@AutoConfigureBefore>批注或专用的 <代码>@AutoConfigureAfter批注上使用<代码>前、<代码>前<代码>、<代码>后 和<代码>后 属性。例如,如果您提供特定于Web的配置,则您的类可能需要在 WebMvcAutoConfiguration之后应用。

如果您想订购某些不应该相互直接了解的自动配置,您还可以使用@AutoConfigureOrder。该注释与常规的@Order注释具有相同的语义,但为自动配置类提供了专用的顺序。

与标准的@configuration类一样,应用自动配置类的顺序只影响定义它们的Bean的顺序。随后创建这些Bean的顺序不受影响,并由每个Bean的依赖关系和任何@DependsOn关系确定。

9.3. Condition Annotations

您几乎总是希望在自动配置类中包含一个或多个@Conditional注释。@ConditionalOnMissingBean注释是一个常见的示例,用于允许开发人员在对您的默认设置不满意时覆盖自动配置。

Spring Boot包括许多@Conditional批注,您可以通过批注@Configuration类或单个@Bean方法在您自己的代码中重用这些批注。这些注释包括:

9.3.1. Class Conditions

@ConditionalOnClass@ConditionalOnMissingClass批注允许根据是否存在特定类来包括@Configuration类。由于注释元数据是使用ASM进行解析的,因此您可以使用属性来引用实际的类,即使该类可能并不实际出现在运行的应用程序类路径中。如果您喜欢使用字符串值指定类名,也可以使用name属性。

这种机制不适用于@Bean方法,在@Bean方法中,返回类型通常是条件的目标:在方法上的条件应用之前,JVM将加载类和可能已处理的方法引用,如果类不存在,这些引用将失败。

要处理此场景,可以使用单独的@Configuration类来隔离该条件,如下例所示:

Java
Kotlin
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @AutoConfiguration // Some conditions ... public class MyAutoConfiguration { // Auto-configured beans ... @Configuration(proxyBeanMethods = false) @ConditionalOnClass(SomeService.class) public static class SomeServiceConfiguration { @Bean @ConditionalOnMissingBean public SomeService someService() { return new SomeService(); } } } 
             
             
If you use @ConditionalOnClass or @ConditionalOnMissingClass as a part of a meta-annotation to compose your own composed annotations, you must use name as referring to the class in such a case is not handled.

9.3.2. Bean Conditions

@ConditionalOnBean@ConditionalOnMissingBean注释允许根据是否存在特定的Bean来包含Bean。您可以使用属性按类型指定Bean,或使用名称按名称指定Bean。搜索属性允许您限制在搜索Bean时应考虑的ApplicationContext层次结构。

当放置在@Bean方法上时,目标类型默认为该方法的返回类型,如下例所示:

Java
Kotlin
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; @AutoConfiguration public class MyAutoConfiguration { @Bean @ConditionalOnMissingBean public SomeService someService() { return new SomeService(); } } 
             
             

在前面的示例中,如果ApplicationContext中尚未包含任何SomeService类型的Bean,则将创建SomeServiceBean。

You need to be very careful about the order in which bean definitions are added, as these conditions are evaluated based on what has been processed so far. For this reason, we recommend using only @ConditionalOnBean and @ConditionalOnMissingBean annotations on auto-configuration classes (since these are guaranteed to load after any user-defined bean definitions have been added).
@ConditionalOnBean and @ConditionalOnMissingBean do not prevent @Configuration classes from being created. The only difference between using these conditions at the class level and marking each contained @Bean method with the annotation is that the former prevents registration of the @Configuration class as a bean if the condition does not match.
When declaring a @Bean method, provide as much type information as possible in the method’s return type. For example, if your bean’s concrete class implements an interface the bean method’s return type should be the concrete class and not the interface. Providing as much type information as possible in @Bean methods is particularly important when using bean conditions as their evaluation can only rely upon to type information that is available in the method signature.

9.3.3. Property Conditions

@ConditionalOnProperty注释允许基于Spring Environment属性包括配置。使用前缀名称属性指定应该检查的属性。默认情况下,匹配存在且不等于False的任何属性。您还可以使用havingValuematchIfMissing属性创建更高级的检查。

9.3.4. Resource Conditions

@ConditionalOnResource注释允许仅在存在特定资源时才包括配置。可以使用常用的Spring约定指定资源,如下面的示例所示:file:/home/user/test.dat

9.3.5. Web Application Conditions

@ConditionalOnWebApplication@ConditionalOnNotWebApplication注释允许根据应用程序是否为“Web应用程序”来包含配置。基于Servlet的Web应用程序是使用SpringWebApplicationContext、定义会话作用域或具有ConfigurableWebEnvironment的任何应用程序。反应式Web应用程序是使用<ConfigurableReactiveWebEnvironment.>Reactive WebApplicationContext或具有

@ConditionalOnWarDeployment注释允许根据应用程序是否是部署到容器的传统WAR应用程序来包括配置。对于使用嵌入式服务器运行的应用程序,此条件不匹配。

9.3.6. SpEL Expression Conditions

@ConditionalOnExpression注释允许根据Spel表达式的结果包括配置。

Referencing a bean in the expression will cause that bean to be initialized very early in context refresh processing. As a result, the bean won’t be eligible for post-processing (such as configuration properties binding) and its state may be incomplete.

9.4. Testing your Auto-configuration

自动配置可能受许多因素的影响:用户配置(@Bean定义和环境定制)、条件评估(特定库的存在)以及其他。具体地说,每个测试都应该创建一个定义良好的ApplicationContext,表示这些定制的组合。ApplicationConextRunner提供了一种很好的方法来实现这一点。

ApplicationConextRunner通常被定义为测试类的一个字段,用于收集基本的公共配置。下面的示例确保始终调用MyServiceAutoConfiguration

Java
Kotlin
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
        .withConfiguration(AutoConfigurations.of(MyServiceAutoConfiguration.class));

            
            
If multiple auto-configurations have to be defined, there is no need to order their declarations as they are invoked in the exact same order as when running the application.

每个测试都可以使用Runner来表示特定的用例。例如,下面的示例调用一个用户配置(UserConfiguration),并检查自动配置是否正确后退。调用Run提供可与AssertJ一起使用的回调上下文。

Java
Kotlin
@Test
void defaultServiceBacksOff() {
    this.contextRunner.withUserConfiguration(UserConfiguration.class).run((context) -> {
        assertThat(context).hasSingleBean(MyService.class);
        assertThat(context).getBean("myCustomService").isSameAs(context.getBean(MyService.class));
    });
}

@Configuration(proxyBeanMethods = false)
static class UserConfiguration {

    @Bean
    MyService myCustomService() {
        return new MyService("mine");
    }

}

            
            

还可以轻松自定义环境,如下例所示:

Java
Kotlin
@Test
void serviceNameCanBeConfigured() {
    this.contextRunner.withPropertyValues("user.name=test123").run((context) -> {
        assertThat(context).hasSingleBean(MyService.class);
        assertThat(context.getBean(MyService.class).getName()).isEqualTo("test123");
    });
}

            
            

运行器还可用于显示ConditionEvaluationReport。报告可以在信息调试级别打印。以下示例显示如何在自动配置测试中使用ConditionEvaluationReportLoggingListener打印报告。

Java
Kotlin
import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener; import org.springframework.boot.logging.LogLevel; import org.springframework.boot.test.context.runner.ApplicationContextRunner; class MyConditionEvaluationReportingTests { @Test void autoConfigTest() { new ApplicationContextRunner() .withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO)) .run((context) -> { // Test something... }); } } 
            
            

9.4.1. Simulating a Web Context

如果您需要测试仅在Servlet或反应式Web应用程序上下文中操作的自动配置,请分别使用WebApplicationConextRunnerReactiveWebApplicationContextRunner

9.4.2. Overriding the Classpath

还可以测试当特定类和/或包在运行时不存在时会发生什么。Spring Boot附带了一个FilteredClassLoader,运行者可以轻松地使用它。在下面的示例中,我们断言如果MyService不存在,则自动配置被正确禁用:

Java
Kotlin
@Test
void serviceIsIgnoredIfLibraryIsNotPresent() {
    this.contextRunner.withClassLoader(new FilteredClassLoader(MyService.class))
            .run((context) -> assertThat(context).doesNotHaveBean("myService"));
}

             
             

9.5. Creating Your Own Starter

典型的Spring Boot starter包含自动配置和定制给定技术的基础设施的代码,我们称其为“acme”。为了使其易于扩展,可以向环境公开专用命名空间中的多个配置键。最后,提供了单一的“starter”依赖关系,以帮助用户尽可能轻松地开始。

具体地说,自定义启动器可以包含以下内容:

  • 自动配置模块,包含“acme”的自动配置代码。

  • starter模块,它为自动配置模块以及“acme”和任何通常有用的其他依赖项提供依赖项。简而言之,添加入门程序应该可以提供开始使用该库所需的一切。

这种在两个模块中分开的方式是没有必要的。如果“acme”有几种风格、选项或可选功能,那么最好将自动配置分开,因为您可以清楚地表示某些功能是可选的。此外,您还可以创建一个启动器,提供有关这些可选依赖项的意见。与此同时,其他人只能依靠自动配置模块,并以不同的观点定制自己的Starter。

如果自动配置相对简单,并且没有可选功能,那么将启动器中的两个模块合并绝对是一个选择。

9.5.1. Naming

您应该确保为您的初学者提供适当的命名空间。即使您使用不同的MavengroupID,模块名称也不要以SpringBoot开头。我们可能会在未来为您自动配置的东西提供官方支持。

根据经验,您应该以启动器的名字命名一个组合模块。例如,假设您正在为“acme”创建一个starter,并将自动配置模块命名为acme-Spring-boot,将starter命名为acme-Spring-ot-starter。如果您只有一个将这两个模块组合在一起的模块,那么将其命名为acme-Spring-ot-starter

9.5.2. Configuration keys

如果您的启动程序提供了配置密钥,请为它们使用唯一的命名空间。特别是,不要将键包含在Spring Boot使用的名称空间中(例如服务器管理Spring等等)。如果您使用相同的命名空间,我们将来可能会以破坏您的模块的方式修改这些命名空间。经验法则是,在所有键前面加上您拥有的名称空间(例如acme)。

确保通过为每个属性添加字段javadoc来记录配置密钥,如下例所示:

Java
Kotlin
import java.time.Duration; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties("acme") public class AcmeProperties { /** * Whether to check the location of acme resources. */ private boolean checkLocation = true; /** * Timeout for establishing a connection to the acme server. */ private Duration loginTimeout = Duration.ofSeconds(3);  // getters/setters ...  public boolean isCheckLocation() { return this.checkLocation; } public void setCheckLocation(boolean checkLocation) { this.checkLocation = checkLocation; } public Duration getLoginTimeout() { return this.loginTimeout; } public void setLoginTimeout(Duration loginTimeout) { this.loginTimeout = loginTimeout; } } 
             
             
You should only use plain text with @ConfigurationProperties field Javadoc, since they are not processed before being added to the JSON.

以下是我们在内部遵循的一些规则,以确保描述的一致性:

  • 不要以“The”或“A”作为描述的开头。

  • 对于布尔类型,描述以“是否”或“启用”开头。

  • 对于基于集合的类型,说明以“逗号分隔列表”开头

  • 使用java.time.Duration而不是long,如果默认单位与毫秒不同,请描述默认单位,例如“如果没有指定持续时间后缀,则将使用秒”。

  • 除非必须在运行时确定,否则请勿在描述中提供默认值。

确保触发元数据生成,以便IDE帮助您的键也可用。您可能希望查看生成的元数据(META-INF/spring-configuration-metadata.json),以确保正确记录了密钥。在兼容的IDE中使用您自己的Starter来验证元数据的质量也是一个好主意。

9.5.3. The “autoconfigure” Module

自动配置模块包含开始使用该库所需的所有内容。它还可以包含配置键定义(如@ConfigurationProperties)和任何可用于进一步定制组件初始化方式的回调接口。

You should mark the dependencies to the library as optional so that you can include the autoconfigure module in your projects more easily. If you do it that way, the library is not provided and, by default, Spring Boot backs off.

Spring Boot使用注释处理器在元数据文件(META-INF/spring-autoconfigure-metadata.properties).中收集关于自动配置的条件如果该文件存在,则它被用来急切地过滤不匹配的自动配置,这将缩短启动时间。

使用Maven构建时,建议在包含自动配置的模块中添加以下依赖项:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-autoconfigure-processor</artifactId>
    <optional>true</optional>
</dependency>
             
             

如果您已经在应用程序中直接定义了自动配置,请确保配置Spring-ot-maven-plugin,以防止重新打包目标将依赖项添加到FAT JAR中:

<project>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.springframework.boot</groupId>
                            <artifactId>spring-boot-autoconfigure-processor</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
             
             

使用Gradle时,应在注解处理器配置中声明依赖项,如下例所示:

dependencies {
    annotationProcessor "org.springframework.boot:spring-boot-autoconfigure-processor"
}
             
             

9.5.4. Starter Module

开胃菜实际上是一个空罐子。它的唯一目的是提供与库一起工作所需的依赖项。你可以把它看作是一种对开始需要什么的固执己见的观点。

不要对添加了您的初学者的项目做出假设。如果您正在自动配置的库通常需要其他启动器,那么也要提到它们。如果可选依赖项的数量很多,则提供一组适当的默认依赖项可能很困难,因为您应该避免包括库的典型使用所不必要的依赖项。换句话说,您不应该包括可选的依赖项。

Either way, your starter must reference the core Spring Boot starter (spring-boot-starter) directly or indirectly (there is no need to add it if your starter relies on another starter). If a project is created with only your custom starter, Spring Boot’s core features will be honoured by the presence of the core starter.

10. Kotlin Support

Kotlin是一种针对JVM(和其他平台)的静态类型语言,它允许编写简洁优雅的代码,同时提供与现有Java库的互操作性

Spring Boot通过利用其他Spring项目中的支持来提供Kotlin支持,比如Spring框架、Spring data和Reader。有关详细信息,请参阅Spring框架Kotlin支持文档

开始使用Spring Boot和Kotlin的最简单方法是按照本综合教程进行操作。您可以使用start.spring.io创建新的Kotlin项目。如果您需要支持,请随时加入Kotlin Slack的#Spring频道,或者使用Stack Overflow上的SpringKotlin标签提问。

10.1. Requirements

Spring Boot至少需要Kotlin 1.7.x,并通过依赖管理管理合适的Kotlin版本。要使用kotlin,类路径上必须存在org.jetbrains.kotlin:kotlin-stdliborg.jetbrains.kotlin:kotlin-reflect。也可以使用kotlin-stdlib变体kotlin-stdlib-jdk7kotlin-stdlib-jdk8

由于kotlin类在默认情况下是最终的,因此您可能希望配置kotlin-Spring插件,以便自动打开带Spring注释的类,以便可以代理它们。

在Kotlin中序列化/反序列化JSON数据需要Jackson的Kotlin模块。当在类路径上找到它时,它会自动注册。如果杰克逊和科特林存在,但杰克逊·科特林模块不存在,则会记录一条警告消息。

These dependencies and plugins are provided by default if one bootstraps a Kotlin project on start.spring.io.

10.2. Null-safety

Kotlin的主要功能之一是空安全。它在编译时处理NULL值,而不是将问题推迟到运行时并遇到NullPointerException。这有助于消除常见的错误来源,而无需支付像可选这样的包装器的成本。Kotlin还允许使用具有可空值的函数构造,如Kotlin中的空安全综合指南中所述。

尽管Java不允许在其类型系统中表示空安全,但Spring框架、Spring data和Reader现在通过工具友好的注释为它们的API提供了空安全。默认情况下,Kotlin中使用的Java API的类型被识别为放宽了空检查的平台类型Kotlin对JSR 305批注的支持与可为空性批注相结合,为Kotlin中的相关Spring API提供了空安全性。

可以通过添加带有以下选项的-Xjsr305编译器标志来配置JSR305检查:-Xjsr305={STRICT|WARN|IGNORE}。默认行为与-Xjsr305=warn相同。为了在从Spring API推断的Kotlin类型中考虑空安全性,Strong值是必需的,但在使用时应该知道,即使在次要版本之间也可能演变Spring API的为空性声明,并且将来可能会添加更多检查)。

Generic type arguments, varargs and array elements nullability are not yet supported. See SPR-15942 for up-to-date information. Also be aware that Spring Boot’s own API is not yet annotated.

10.3. Kotlin API

10.3.1. runApplication

Spring Boot提供了一种使用runApplication<;MyApplication>;(*args)运行应用程序的惯用方法,如以下示例所示:

import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication @SpringBootApplication class MyApplication fun main(args: Array<String>) { runApplication<MyApplication>(*args) } 
             
             

这是SpringApplication.run(MyApplication::class.java,*args的临时替代品)。它还允许定制应用程序,如下例所示:

runApplication<MyApplication>(*args) {
    setBannerMode(OFF)
}

             
             

10.3.2. Extensions

Kotlin扩展提供了使用附加功能扩展现有类的能力。Spring Boot Kotlin API利用这些扩展将特定于Kotlin的新功能添加到现有API中。

TestRestTemplate扩展,类似于Spring框架中的RestOperations提供的扩展。除了其他功能外,这些扩展还使利用Kotlin实例化类型参数成为可能。

10.4. Dependency management

为了避免在类路径上混合不同版本的Kotlin依赖项,Spring Boot导入了Kotlin BOM。

使用Maven,可以通过设置kotlin.Version属性定制kotlin版本,并为kotlin-maven-plugin提供插件管理。使用Gradle,Spring Boot插件会自动将kotlin.version与Kotlin插件的版本对齐。

Spring Boot还通过导入Kotlin Coroutines BOM来管理协程依存关系的版本。可以通过设置kotlin-coroutines.Version属性来自定义版本。

org.jetbrains.kotlinx:kotlinx-coroutines-reactor dependency is provided by default if one bootstraps a Kotlin project with at least one reactive dependency on start.spring.io.

10.5. @ConfigurationProperties

@ConfigurationProperties构造函数绑定配合使用时,支持具有不可变的val属性的类,如下例所示:

@ConfigurationProperties("example.kotlin")
data class KotlinExampleProperties(
        val name: String,
        val description: String,
        val myService: MyService) {

    data class MyService(
            val apiToken: String,
            val uri: URI
    )
}

            
            
To generate your own metadata using the annotation processor, kapt should be configured with the spring-boot-configuration-processor dependency. Note that some features (such as detecting the default value or deprecated items) are not working due to limitations in the model kapt provides.

10.6. Testing

虽然可以使用JUnit4测试Kotlin代码,但默认情况下会提供JUnit5,建议使用JUnit5。JUnit5允许一个测试类实例化一次,然后在类的所有测试中重复使用。这使得在非静态方法上使用@BeForeAll@After All注释成为可能,这非常适合Kotlin。

要模拟Kotlin类,建议使用MockK。如果您需要与特定于Mockito的@MockBean@SpyBean批注对应的Mockk,您可以使用提供类似@MockkBean@SpykBean批注的SpringMockK

10.7. Resources

10.7.2. Examples

11. What to Read Next

如果您想了解本节中讨论的任何类的更多信息,请参阅Spring Boot API文档,或者可以直接浏览源代码。如果您有特定的问题,请参阅操作方法部分。

如果您对Spring Boot的核心特性感到满意,可以继续阅读生产就绪特性