添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

本节深入探讨 Spring Boot 的细节。在这里您可以了解您可能想要使用和自定义的主要功能。如果您还没有这样做,您可能需要阅读“ 入门 ”和“ 使用 Spring Boot 进行开发 ”部分,以便您打下良好的基础知识。

1. Spring应用

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

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

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

  . ____ _ _ _ _
 /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \
 \\/ ___)| |_)| | | | | || (_| | ) ) ) )
  ' |____| .__|_| |_|_| |_\__, | // / /
 =========|_|==============|___/=/_/_/_/
 :: 春季启动 :: (v2.7.10)
2023-03-23 08:14:17.996 INFO 17618 --- [main] osbdfsMyApplication:在 PID 为 17618 的 myhost 上使用 Java 1.8.0_362 启动 MyApplication(/opt/apps/myapp.jar 由 myuser 在 /opt/apps/ 中启动)
2023-03-23 08:14:18.001 INFO 17618 --- [main] osbdfsMyApplication:未设置活动配置文件,回落到 1 个默认配置文件:“默认”
2023-03-23 08:14:19.597 INFO 17618 --- [main] osbwembedded.tomcat.TomcatWebServer:Tomcat 初始化端口:8080 (http)
2023-03-23 08:14:19.623 INFO 17618 --- [main] o.apache.catalina.core.StandardService:启动服务 [Tomcat]
2023-03-23 08:14:19.623 INFO 17618 --- [main] org.apache.catalina.core.StandardEngine:启动 Servlet 引擎:[Apache Tomcat/9.0.73]
2023-03-23 08:14:20.092 INFO 17618 --- [main] oaccC[Tomcat].[localhost].[/]:初始化 Spring 嵌入式 WebApplicationContext
2023-03-23 08:14:20.092 INFO 17618 --- [main] wscServletWebServerApplicationContext:Root WebApplicationContext:初始化在 2042 毫秒内完成
2023-03-23 08:14:21.281 INFO 17618 --- [main] osbwembedded.tomcat.TomcatWebServer:Tomcat 在端口上启动:8080 (http),上下文路径为“”
2023-03-23 08:14:21.295 INFO 17618 --- [main] osbdfsMyApplication:在 4.208 秒内启动 MyApplication(JVM 运行 4.643)
2023-03-23 08:14:21.309 INFO 17618 --- [ionShutdownHook] o.apache.catalina.core.StandardService:停止服务 [Tomcat]

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

要在启动期间添加额外的日志记录,您可以logStartupInfo(boolean)SpringApplication.

1.1. 启动失败

如果您的应用程序无法启动,注册者FailureAnalyzers有机会提供专门的错误消息和解决问题的具体操作。例如,如果您在端口上启动 Web 应用程序8080并且该端口已被使用,您应该会看到类似于以下消息的内容:

******************************
应用程序启动失败
******************************
嵌入式 servlet 容器无法启动。端口 8080 已被使用。
识别并停止侦听端口 8080 的进程,或将此应用程序配置为侦听另一个端口。

Spring Boot 提供了多种FailureAnalyzer实现,您可以添加自己的.

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

例如,如果您使用 运行您的应用程序java -jar,则可以按debug如下方式启用该属性:

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

1.2. 惰性初始化

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

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

可以使用lazyInitializationon 方法SpringApplicationBuildersetLazyInitializationon 方法以编程方式启用延迟初始化SpringApplicationspring.main.lazy-initialization或者,可以使用以下示例中所示的属性启用它:

spring.main.lazy-initialization=true

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

1.3. 自定义横幅

banner.txt可以通过将文件添加到类路径或将spring.banner.location属性设置为此类文件的位置来更改启动时打印的横幅。如果文件的编码不是 UTF-8,您可以设置spring.banner.charset. 除了文本文件之外,您还可以将banner.gifbanner.jpgbanner.png图像文件添加到类路径或设置spring.banner.image.location属性。图像被转换为 ASCII 艺术表现形式并打印在任何文本横幅上方。

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

${application.version} 您的应用程序的版本号,如在中声明的那样MANIFEST.MF。例如,Implementation-Version: 1.0打印为1.0. ${application.formatted-version} 您的应用程序的版本号,在中声明MANIFEST.MF并格式化显示(用括号括起来并以 为前缀v)。例如(v1.0)${spring-boot.version} 您正在使用的 Spring Boot 版本。例如2.7.10${spring-boot.formatted-version} 您正在使用的 Spring Boot 版本,经过格式化以供显示(用方括号括起来并以 为前缀v)。例如(v2.7.10)${Ansi.NAME}(或${AnsiColor.NAME},,${AnsiBackground.NAME}${AnsiStyle.NAME} NAMEANSI 转义代码的名称在哪里。AnsiPropertySource详情请见。 ${application.title} 您的应用程序的标题,如中声明的那样MANIFEST.MF。例如Implementation-Title: MyApp打印为MyApp.

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

您还可以使用该spring.main.banner-mode属性来确定是否必须在System.out( console) 上打印横幅、将其发送到配置的记录器 ( log) 或根本不生成 ( off)。

打印的横幅在以下名称下注册为单例 bean springBootBanner:。

${application.version}属性${application.formatted-version}仅在您使用 Spring Boot 启动器时可用。如果您正在运行解压的 jar 并以java -cp <classpath> <mainclass>.这就是为什么我们建议您始终使用java org.springframework.boot.loader.JarLauncher. application.*这将在构建类路径和启动您的应用程序之前初始化横幅变量。

1.4. 自定义 SpringApplication

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

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

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

也可以SpringApplication使用application.properties文件进行配置。有关详细信息,请参阅*外部化配置*。

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

1.5. 流利的生成器 API

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

允许您将多个方法调用和包含以及允许您创建层次结构的方法SpringApplicationBuilder链接在一起,如以下示例所示:parent``child

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

创建层次结构时有一些限制ApplicationContext。例如,Web 组件必须包含在子上下文中,并且同样Environment用于父上下文和子上下文。有关详细信息, 请参阅SpringApplicationBuilderJavadoc 。

1.6. 应用可用性

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

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

1.6.1. 活性状态

应用程序的“活动”状态表明它的内部状态是否允许它正常工作,或者如果它当前失败则自行恢复。损坏的“活动”状态意味着应用程序处于无法恢复的状态,基础架构应重新启动应用程序。

一般来说,“Liveness”状态不应该基于外部检查,比如Health checks。如果是这样,一个失败的外部系统(数据库、Web API、外部缓存)将触发大规模重启和整个平台的级联故障

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

1.6.2. 准备状态

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

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

预期在启动期间运行的任务应该由组件执行,CommandLineRunnerApplicationRunner不是使用 Spring 组件生命周期回调,例如@PostConstruct.

1.6.3. 管理应用程序可用性状态

应用程序组件可以随时通过注入ApplicationAvailability接口和调用方法来检索当前的可用性状态。更多时候,应用程序会想要监听状态更新或更新应用程序的状态。

例如,我们可以将应用程序的“Readiness”状态导出到一个文件中,以便 Kubernetes 的“exec Probe”可以查看这个文件:

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

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

@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通过 Actuator Health Endpoints 为“Liveness”和“Readiness”提供 Kubernetes HTTP 探测您可以在专用部分中获得有关在 Kubernetes 上部署 Spring Boot 应用程序的更多指导。

1.7. 应用程序事件和监听器

除了通常的 Spring Framework 事件(例如 )之外ContextRefreshedEvent,aSpringApplication还会发送一些额外的应用程序事件。

有些事件实际上是在ApplicationContext创建之前触发的,因此您不能将这些事件的侦听器注册为@Bean. SpringApplication.addListeners(…)您可以使用方法或方法注册它们SpringApplicationBuilder.listeners(…)。如果您希望自动注册这些侦听器,而不管应用程序的创建方式如何,您可以将文件添加META-INF/spring.factories到您的项目并使用密钥引用您的侦听器org.springframework.context.ApplicationListener,如以下示例所示:org.springframework.context.ApplicationListener=com.example.project.MyListener

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

  • AnApplicationStartingEvent在运行开始时发送,但在任何处理之前发送,除了侦听器和初始化程序的注册。
  • 当要在上下文中使用的 已知但在创建上下文之前ApplicationEnvironmentPreparedEvent发送An 。Environment
  • 准备好并调用 ApplicationContextInitializers 但在加载任何 bean 定义之前ApplicationContextInitializedEvent发送An 。ApplicationContext
  • ApplicationPreparedEvent在刷新开始之前但在加载 bean 定义之后发送。
  • ApplicationStartedEvent在刷新上下文之后但在调用任何应用程序和命令行运行程序之前发送An 。
  • AvailabilityChangeEvent在 with 之后立即发送AnLivenessState.CORRECT以指示该应用程序被认为是实时的。
  • 在调用ApplicationReadyEvent任何应用程序和命令行运行程序后发送。
  • AvailabilityChangeEvent在 with 之后立即发送AnReadinessState.ACCEPTING_TRAFFIC以指示应用程序已准备好服务请求。
  • ApplicationFailedEvent如果启动时出现异常,则发送An 。
  • 上面的列表只包括SpringApplicationEvent绑定到 a 的 s SpringApplication。除了这些之外,以下事件也在之后ApplicationPreparedEvent和之前发布ApplicationStartedEvent

  • A在准备就绪WebServerInitializedEvent后发送WebServerServletWebServerInitializedEventReactiveWebServerInitializedEvent分别是 servlet 和反应式变体。
  • 刷新ContextRefreshedEvent时发送A。ApplicationContext
  • 您通常不需要使用应用程序事件,但知道它们存在会很方便。在内部,Spring Boot 使用事件来处理各种任务。

    事件侦听器不应运行可能冗长的任务,因为它们默认在同一线程中执行。考虑改用应用程序和命令行运行器

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

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

    1.8. 网络环境

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

  • 如果存在 Spring MVC,则AnnotationConfigServletWebServerApplicationContext使用
  • 如果 Spring MVC 不存在而 Spring WebFlux 存在,则AnnotationConfigReactiveWebServerApplicationContext使用
  • 否则,AnnotationConfigApplicationContext使用
  • 这意味着如果您WebClient在同一应用程序中使用 Spring MVC 和 Spring WebFlux 的新功能,则默认情况下将使用 Spring MVC。您可以通过调用轻松覆盖它setWebApplicationType(WebApplicationType)

    也可以完全控制ApplicationContext调用所使用的类型setApplicationContextFactory(…)

    1.9. 访问应用程序参数

    如果您需要访问传递给 的应用程序参数SpringApplication.run(…),您可以注入一个org.springframework.boot.ApplicationArgumentsbean。该ApplicationArguments接口提供对原始String[]参数以及已解析参数optionnon-option参数的访问,如以下示例所示:

    @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"]
    

    这些CommandLineRunner接口提供对应用程序参数作为字符串数组的访问,而ApplicationRunner使用ApplicationArguments前面讨论的接口。以下示例显示了一个CommandLineRunner方法run

    @Component
    public class MyCommandLineRunner implements CommandLineRunner {
        @Override
        public void run(String... args) {
            // Do something...
    

    如果定义了几个CommandLineRunner必须ApplicationRunner按特定顺序调用的 bean,您可以另外实现org.springframework.core.Ordered接口或使用org.springframework.core.annotation.Order注释。

    1.11. 申请出口

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

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

    @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.Ordered或使用org.springframework.core.annotation.Order注释。

    1.12. 管理员功能

    可以通过指定属性为应用程序启用与管理相关的功能spring.application.admin.enabled。这暴露了SpringApplicationAdminMXBean平台上的MBeanServer。您可以使用此功能远程管理您的 Spring Boot 应用程序。此功能也可用于任何服务包装器实现。

    1.13. 应用程序启动跟踪

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

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

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

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

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

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

    Spring Boot 还可以配置为公开一个以 JSON 文档形式提供此信息的startup端点

    2. 外化配置

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

    属性值可以通过注解直接注入 bean @Value,通过 Spring 的抽象访问Environment或者通过.@ConfigurationProperties

    Spring Boot 使用一种非常特殊的PropertySource顺序,旨在允许合理地覆盖值。后面的属性源可以覆盖前面定义的值。来源按以下顺序考虑:

  • 默认属性(由设置指定SpringApplication.setDefaultProperties)。
  • @PropertySource类上的注释@ConfigurationEnvironment请注意,在刷新应用程序上下文之前,不会将此类属性源添加到。现在配置某些属性(例如logging.*spring.main.*在刷新开始前读取)为时已晚。
  • 配置数据(例如application.properties文件)。
  • RandomValuePropertySource仅在 中具有属性的random.*
  • 操作系统环境变量。
  • Java 系统属性 ( System.getProperties())。
  • JNDI 属性来自java:comp/env.
  • ServletContext初始化参数。
  • ServletConfig初始化参数。
  • 属性来自SPRING_APPLICATION_JSON(嵌入在环境变量或系统属性中的内联 JSON)。
  • 命令行参数。
  • properties测试的属性。@SpringBootTest在和测试注释上可用,用于测试应用程序的特定部分
  • @TestPropertySource测试注释。
  • $HOME/.config/spring-boot当 devtools 处于活动状态时,目录中的Devtools全局设置属性。
  • 配置数据文件按以下顺序考虑:

  • 打包在 jar 中的应用程序属性application.properties(和 YAML 变体)。
  • 打包在您的 jar(和 YAML 变体)中的特定于配置文件的应用程序属性application-{profile}.properties
  • 打包的 jar(和 YAML 变体)之外的应用程序属性application.properties
  • 打包的 jar(和 YAML 变体)之外的特定于配置文件的应用程序属性application-{profile}.properties
  • 2.1. 访问命令行属性

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

    如果您不想将命令行属性添加到 中Environment,您可以使用 禁用它们SpringApplication.setAddCommandLineProperties(false)

    2.2. JSON 应用程序属性

    环境变量和系统属性通常有限制,这意味着某些属性名称不能使用。为了解决这个问题,Spring Boot 允许您将属性块编码为单个 JSON 结构。

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

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

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

    在前面的示例中,您最终my.name=test在 Spring 中Environment

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

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

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

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

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

    2.3. 外部应用程序属性

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

  • 类路径/config
  • 从当前目录
  • config/当前目录下的子目录
  • config/子目录的直接子目录
  • 该列表按优先级排序(较低项的值覆盖较早的项)。加载文件中的文档被添加PropertySources到 Spring 中Environment

    如果您不喜欢application作为配置文件名,您可以通过指定一个spring.config.name环境属性来切换到另一个文件名。例如,要查找myproject.propertiesmyproject.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
    

    在大多数情况下,spring.config.location您添加的每个项目都将引用一个文件或目录。位置按照它们被定义的顺序处理,后面的可以覆盖前面的值。

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

    使用配置的位置spring.config.location替换默认位置。例如,如果spring.config.location配置了值optional:classpath:/custom-config/,optional:file:./custom-config/,则考虑的完整位置集是:

  • optional:classpath:custom-config/
  • optional:file:./custom-config/
  • 如果您更喜欢添加其他位置,而不是替换它们,您可以使用spring.config.additional-location. 从其他位置加载的属性可以覆盖默认位置中的属性。例如,如果spring.config.additional-location配置了值optional:classpath:/custom-config/,optional:file:./custom-config/,则考虑的完整位置集是:

  • optional:classpath:/;optional:classpath:/config/
  • optional:file:./;optional:file:./config/;optional:file:./config/*/
  • optional:classpath:custom-config/
  • optional:file:./custom-config/
  • 此搜索顺序使您可以在一个配置文件中指定默认值,然后在另一个配置文件中有选择地覆盖这些值。您可以在默认位置之一的application.properties(或您选择的任何其他基本名称)中为您的应用程序提供默认值。spring.config.name然后可以在运行时使用位于自定义位置之一的不同文件覆盖这些默认值。

    2.3.1. 可选地点

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

    如果你想指定一个位置,但你不介意它并不总是存在,你可以使用前缀optional:。您可以将此前缀与spring.config.locationspring.config.additional-location属性以及spring.config.import声明一起使用。

    例如,spring.config.importoptional:file:./myconfig.properties允许您的应用程序启动,即使myconfig.properties文件丢失。

    如果您想忽略所有ConfigDataLocationNotFoundExceptions并始终继续启动您的应用程序,您可以使用该spring.config.on-not-found属性。将值设置为ignore使用SpringApplication.setDefaultProperties(…)或与系统/环境变量一起使用。

    2.3.2. 通配符位置

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

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

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

    您可以自己将通配符位置与spring.config.locationspring.config.additional-location属性一起使用。

    2.3.3. 配置文件特定文件

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

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

    最后获胜的策略适用于营业地点组级别。A spring.config.locationofclasspath:/cfg/,classpath:/ext/将不会具有与 相同的覆盖规则classpath:/cfg/;classpath:/ext/。例如,继续prod,live上面的示例,我们可能有以下文件:/配置文件 application-live.properties /分机 application-live.properties 应用产品.properties当我们有一个spring.config.locationclasspath:/cfg/,classpath:/ext/,我们在处理所有/cfg文件之前处理所有/ext文件:/cfg/application-live.properties``/ext/application-prod.properties``/ext/application-live.properties相反,当我们有classpath:/cfg/;classpath:/ext/(带有;分隔符)时,我们在同一级别处理/cfg和:/ext``/ext/application-prod.properties``/cfg/application-live.properties``/ext/application-live.properties

    2.3.4. 导入附加数据

    应用程序属性可以使用该属性从其他位置导入更多配置数据spring.config.import。进口在发现时进行处理,并被视为紧接在声明进口的文件下方插入的附加文件。

    例如,您的类路径application.properties文件中可能包含以下内容:

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

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

    一个导入无论声明多少次都只会被导入一次。在 properties/yaml 文件中的单个文档中定义导入的顺序无关紧要。例如,下面的两个示例产生相同的结果:

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

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

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

    2.3.5. 导入无扩展名文件

    某些云平台无法为卷挂载文件添加文件扩展名。要导入这些没有扩展名的文件,你需要给 Spring Boot 一个提示,让它知道如何加载它们。您可以通过在方括号中放置一个扩展提示来做到这一点。

    例如,假设您有一个/etc/config/myconfig要导入为 yaml 的文件。您可以application.properties使用以下方法将其导入:

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

    2.3.6. 使用配置树

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

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

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

  • 单个文件包含一组完整的属性(通常写为 YAML)。
  • 多个文件被写入目录树,文件名成为“键”,内容成为“值”。
  • 对于第一种情况,您可以直接使用上述spring.config.import方法导入 YAML 或 Properties 文件。对于第二种情况,您需要使用前缀,以便 Spring Boot 知道它需要将所有文件公开为属性。configtree:

    例如,假设 Kubernetes 已经安装了以下卷:

    我的应用程序/

    username文件的内容将是一个配置值,而其内容password将是一个秘密。

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

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

    然后,您可以以通常的方式访问或注入myapp.username属性。myapp.password``Environment

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

    例如,给定以下体积:

    数据库配置/ mq配置/

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

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

    这将添加db.usernamedb.passwordmq.username属性mq.password

    配置树也可用于 Docker 机密。当 Docker swarm 服务被授予访问秘密的权限时,秘密就会被装载到容器中。例如,如果一个名为 secretdb.password挂载在 location /run/secrets/,您可以db.password使用以下命令使 Spring 环境可用:

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

    2.3.7. 财产占位符

    application.properties和中的值在使用时application.yml会通过现有值进行过滤Environment,因此您可以参考以前定义的值(例如,来自系统属性或环境变量)。标准${name}属性占位符语法可用于值内的任何位置。属性占位符还可以指定一个默认值,使用 a:将默认值与属性名称分隔开,例如${name:default}

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

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

    假设该username属性未在别处设置,app.description则值为MyApp is a Spring Boot application written by Unknown

    2.3.8. 使用多文档文件

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

    对于application.yml文件,使用标准的 YAML 多文档语法。三个连续的连字符代表一个文档的结尾和下一个文档的开始。

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

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

    对于application.properties文件,特殊#---!---注释用于标记文档拆分:

    spring.application.name=MyApp
    spring.application.name=MyCloudApp
    spring.config.activate.on-cloud-platform=kubernetes
    

    2.3.9. 激活属性

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

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

    以下激活属性可用:

    spring.config.activate.on-cloud-platform=kubernetes spring.config.activate.on-profile=prod | staging myotherprop=sometimes-set

    2.4. 加密属性

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

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

    2.5. 使用 YAML

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

    2.5.1. 将 YAML 映射到属性

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

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

    为了从 访问这些属性Environment,它们将被展平如下:

    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:

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

    前面的示例将转换为这些属性:

    my.servers[0]=dev.example.com
    my.servers[1]=another.example.com
    

    2.5.2. 直接加载 YAML

    Spring 框架提供了两个方便的类,可用于加载 YAML 文档。将YamlPropertiesFactoryBeanYAML 加载为Properties并将YamlMapFactoryBeanYAML 加载为Map.

    YamlPropertySourceLoader如果要将 YAML 作为 Spring 加载,也可以使用该类PropertySource

    2.6. 配置随机值

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

    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]}
    

    语法random.int*是任何OPEN value (,max) CLOSE字符OPEN,CLOSEvalue,max整数。如果max提供,则为value最小值,max为最大值(不包括)。

    2.7. 配置系统环境属性

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

    例如,如果将前缀设置为,则也将像在系统环境中一样解析input诸如 之类的属性。remote.timeout``input.remote.timeout

    2.8. 类型安全配置属性

    使用@Value("${property}")注解注入配置属性有时会很麻烦,尤其是当您使用多个属性或您的数据本质上是分层的时。Spring Boot 提供了一种使用属性的替代方法,可以让强类型 bean 管理和验证应用程序的配置。

    2.8.1. JavaBean 属性绑定

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

    @ConfigurationProperties("my.service")
    public class MyProperties {
        private boolean enabled;
        private InetAddress remoteAddress;
        private final Security security = new Security();
        // getters / setters...
        public static class Security {
            private String username;
            private String password;
            private List<String> roles = new ArrayList<>(Collections.singleton("USER"));
            // getters / setters...
    

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

  • my.service.enabled,默认值为false
  • my.service.remote-address, 具有可以从String.
  • my.service.security.username,具有嵌套的“安全”对象,其名称由属性的名称确定。特别是,该类型根本没有在那里使用,可能是SecurityProperties.
  • my.service.security.password.
  • my.service.security.roles,其中的集合String默认为USER.
  • 这种安排依赖于默认的空构造函数,getter 和 setter 通常是强制性的,因为绑定是通过标准 Java Beans 属性描述符进行的,就像在 Spring MVC 中一样。在以下情况下可以省略 setter:地图,只要它们被初始化,就需要一个 getter 但不一定是 setter,因为它们可以被活页夹改变。可以通过索引(通常使用 YAML)或使用单个逗号分隔值(属性)来访问集合和数组。在后一种情况下,setter 是强制性的。我们建议始终为此类类型添加一个 setter。如果您初始化一个集合,请确保它不是不可变的(如前例所示)。如果嵌套的 POJO 属性被初始化(如Security前面示例中的字段),则不需要 setter。如果您希望活页夹使用其默认构造函数动态创建实例,则需要一个设置器。有些人使用 Project Lombok 来自动添加 getter 和 setter。确保 Lombok 不会为此类类型生成任何特定的构造函数,因为容器会自动使用它来实例化对象。最后,只考虑标准 Java Bean 属性,不支持绑定静态属性。 // fields... public MyProperties(boolean enabled, InetAddress remoteAddress, Security security) { this.enabled = enabled; this.remoteAddress = remoteAddress; this.security = security; // getters... public static class Security { // fields... public Security(String username, String password, @DefaultValue("USER") List<String> roles) { this.username = username; this.password = password; this.roles = roles; // getters...

    在此设置中,@ConstructorBinding注释用于指示应使用构造函数绑定。这意味着绑定器将期望找到一个带有您希望绑定的参数的构造函数。如果您使用的是 Java 16 或更高版本,构造函数绑定可以与记录一起使用。在这种情况下,除非您的记录有多个构造函数,否则没有必要使用@ConstructorBinding.

    类的嵌套成员@ConstructorBinding(如上Security例)也将通过其构造函数进行绑定。

    可以使用@DefaultValue构造函数参数指定默认值,或者在使用 Java 16 或更高版本时使用记录组件指定默认值。转换服务将用于将String值强制转换为缺失属性的目标类型。

    参考前面的示例,如果没有属性绑定到Security,则该MyProperties实例将包含null的值security。要使它包含一个非空的实例,Security即使没有属性绑定到它(使用 Kotlin 时,这将需要将 的usernamepassword参数声明Security为可空的,因为它们没有默认值),使用空@DefaultValue注释:

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

    2.8.3. 启用@ConfigurationProperties 注释类型

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

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

    @Configuration(proxyBeanMethods = false)
    @EnableConfigurationProperties(SomeProperties.class)
    public class MyConfiguration {
    
    @ConfigurationProperties("some.properties")
    public class SomeProperties {
    

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

    @SpringBootApplication
    @ConfigurationPropertiesScan({ "com.example.app", "com.example.another" })
    public class MyApplication {
    当@ConfigurationProperties使用配置属性扫描或通过 注册 bean时@EnableConfigurationProperties,bean 有一个约定名称:<prefix>-<fqn>,其中是注释<prefix>中指定的环境键前缀,是 bean 的完全限定名称。如果注释不提供任何前缀,则仅使用 bean 的完全限定名称。@ConfigurationProperties``<fqn>假设在包中,上面例子com.example.app的bean名字是.SomeProperties``some.properties-com.example.app.SomeProperties
    

    我们建议@ConfigurationProperties只处理环境,特别是不要从上下文中注入其他 beans。*Aware对于极端情况,可以使用 setter 注入或框架提供的任何接口(例如EnvironmentAware,如果您需要访问Environment)。如果您仍想使用构造函数注入其他 bean,则配置属性 bean 必须注释@Component并使用基于 JavaBean 的属性绑定。

    2.8.4. 使用@ConfigurationProperties 注释的类型

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

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

    要使用@ConfigurationPropertiesbean,您可以使用与任何其他 bean 相同的方式注入它们,如以下示例所示:

    @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();
            // ...
        // ...
    

    2.8.5. 第三方配置

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

    要从Environment属性配置 bean,请添加@ConfigurationProperties到它的 bean 注册中,如以下示例所示:

    @Configuration(proxyBeanMethods = false)
    public class ThirdPartyConfiguration {
        @Bean
        @ConfigurationProperties(prefix = "another")
        public AnotherComponent anotherComponent() {
            return new AnotherComponent();
    

    使用前缀定义的任何 JavaBean 属性都以类似于前面示例的方式another映射到该bean 。AnotherComponent``SomeProperties

    2.8.6. 宽松的装订

    Spring Boot 使用一些宽松的规则将Environment属性绑定到bean,因此属性名称和 bean 属性名称@ConfigurationProperties之间不需要完全匹配。Environment这有用的常见示例包括破折号分隔的环境属性(例如,context-path绑定到contextPath)和大写的环境属性(例如,PORT绑定到port)。

    例如,考虑以下@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;
    

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

    绑定到Map属性时,您可能需要使用特殊的括号表示法,以便key保留原始值。如果键未被 包围[],则任何非字母数字字符-.将被删除。

    例如,考虑将以下属性绑定到 a Map<String,String>

    my.map.[/key1]=value1
    my.map.[/key2]=value2
    my.map./key3=value3
    

    上面的属性将绑定到一个Mapwith /key1, /key2andkey3作为地图中的键。斜线已被删除,key3因为它没有被方括号包围。

    绑定到标量值时,.其中带有的键不需要用[]. 标量值包括枚举和java.lang包中除Object. 绑定a.b=cMap<String, String>将保留.键中的并返回一个包含条目的映射{"a.b"="c"}。对于任何其他类型,如果您包含key一个.. 例如,绑定a.b=cMap<String, Object>将返回一个带有条目的映射{"a"={"b"="c"}},而[a.b]=c将返回一个带有条目的映射{"a.b"="c"}

    从环境变量绑定

    大多数操作系统对可用于环境变量的名称施加了严格的规则。例如,Linux shell 变量只能包含字母(atozAto Z)、数字(0to 9)或下划线字符(_)。按照惯例,Unix shell 变量的名称也将以大写形式显示。

    Spring Boot 宽松的绑定规则,就是为了尽可能兼容这些命名限制而设计的。

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

  • 将点 ( .) 替换为下划线 ( _)。
  • 删除任何破折号 ( -)。
  • 转换为大写。
  • 例如,配置属性spring.main.log-startup-info将是一个名为 的环境变量SPRING_MAIN_LOGSTARTUPINFO

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

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

    2.8.7. 合并复杂类型

    当列表在多个地方配置时,覆盖通过替换整个列表来工作。

    例如,假设一个MyPojo对象具有name默认的description属性nullMyPojo以下示例公开了来自 的对象列表MyProperties

    @ConfigurationProperties("my")
    public class MyProperties {
        private final List<MyPojo> list = new ArrayList<>();
        public List<MyPojo> getList() {
            return this.list;
    

    考虑以下配置:

    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配置文件已启用,则list 仍然只包含一个条目(名称为my another name,描述为null)。此配置不会将第二个MyPojo实例添加到列表中,也不会合并项目。

    当在多个配置文件中指定 a 时List,将使用优先级最高的(并且只有那个)。考虑以下示例:

    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属性,您可以绑定从多个来源提取的属性值。但是,对于多个来源中的同一属性,将使用优先级最高的那个。以下示例公开了一个Map<String, MyPojo>from MyProperties

    @ConfigurationProperties("my")
    public class MyProperties {
        private final Map<String, MyPojo> map = new LinkedHashMap<>();
        public Map<String, MyPojo> getMap() {
            return this.map;
    

    考虑以下配置:

    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)。

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

  • 常规long表示(使用毫秒作为默认单位,除非@DurationUnit已指定 a)
  • 使用的标准 ISO-8601 格式java.time.Duration
  • 一种更易读的格式,其中值和单位耦合(10s表示 10 秒)
  • 考虑以下示例:

    @ConfigurationProperties("my")
    public class MyProperties {
        @DurationUnit(ChronoUnit.SECONDS)
        private Duration sessionTimeout = Duration.ofSeconds(30);
        private Duration readTimeout = Duration.ofMillis(1000);
        // getters / setters...
    

    要指定 30 秒的会话超时,30PT30S都是30s等效的。可以使用以下任何形式指定 500 毫秒的读取超时:500,PT0.5S500ms

    您还可以使用任何受支持的单位。这些都是:

  • ns纳秒
  • us微秒
  • ms几毫秒
  • s几秒钟
  • m几分钟
  • h用了几个小时
  • d好几天
  • 默认单位是毫秒,可以使用@DurationUnit上面示例中所示的方法覆盖。

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

    @ConfigurationProperties("my")
    @ConstructorBinding
    public class MyProperties {
        // fields...
        public MyProperties(@DurationUnit(ChronoUnit.SECONDS) @DefaultValue("30s") Duration sessionTimeout,
                @DefaultValue("1000ms") Duration readTimeout) {
            this.sessionTimeout = sessionTimeout;
            this.readTimeout = readTimeout;
        // getters...
    

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

  • 常规int表示(使用天作为默认单位,除非@PeriodUnit已指定 a)
  • 使用的标准 ISO-8601 格式java.time.Period
  • 一种更简单的格式,其中值和单位对耦合(1y3d表示 1 年零 3 天)
  • 简单格式支持以下单位:

  • m几个月
  • d好几天
  • Spring Framework 有一个以DataSize字节为单位表示大小的值类型。如果公开DataSize属性,则应用程序属性中的以下格式可用:

  • 常规long表示(使用字节作为默认单位,除非@DataSizeUnit已指定 a)
  • 一种更易读的格式,其中值和单位耦合(10MB表示 10 兆字节)
  • 考虑以下示例:

    @ConfigurationProperties("my")
    public class MyProperties {
        @DataSizeUnit(DataUnit.MEGABYTES)
        private DataSize bufferSize = DataSize.ofMegabytes(2);
        private DataSize sizeThreshold = DataSize.ofBytes(512);
        // getters/setters...
    

    指定缓冲区大小为 10 兆字节,10并且10MB是等效的。256 字节的大小阈值可以指定为256256B

    您还可以使用任何受支持的单位。这些都是:

  • B对于字节
  • KB千字节
  • MB兆字节
  • GB千兆字节
  • TB太字节
  • 默认单位是字节,可以使用@DataSizeUnit上面示例中所示的方法覆盖。

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

    @ConfigurationProperties("my")
    @ConstructorBinding
    public class MyProperties {
        // fields...
        public MyProperties(@DataSizeUnit(DataUnit.MEGABYTES) @DefaultValue("2MB") DataSize bufferSize,
                @DefaultValue("512B") DataSize sizeThreshold) {
            this.bufferSize = bufferSize;
            this.sizeThreshold = sizeThreshold;
        // getters...
    

    2.8.9. @ConfigurationProperties 验证

    @ConfigurationProperties每当使用 Spring 的注释对类进行注释时,Spring Boot 都会尝试验证类@Validatedjavax.validation您可以直接在配置类上使用 JSR-303约束注释。为此,请确保您的类路径上有一个兼容的 JSR-303 实现,然后将约束注释添加到您的字段,如以下示例所示:

    @ConfigurationProperties("my.service")
    @Validated
    public class MyProperties {
        @NotNull
        private InetAddress remoteAddress;
        // getters/setters...
    

    为确保始终为嵌套属性触发验证,即使未找到任何属性,关联的字段也必须用 注释@Valid。以下示例建立在前面的MyProperties示例之上:

    @ConfigurationProperties("my.service")
    @Validated
    public class MyProperties {
        @NotNull
        private InetAddress remoteAddress;
        @Valid
        private final Security security = new Security();
        // getters/setters...
        public static class Security {
            @NotEmpty
            private String username;
            // getters/setters...
    

    您还可以Validator通过创建一个名为configurationPropertiesValidator. @Bean应声明该方法static。配置属性验证器是在应用程序生命周期的早期创建的,将方法声明@Bean为静态可以创建 bean,而无需实例化@Configuration类。这样做可以避免早期实例化可能导致的任何问题。

    如果您确实想使用@Value,我们建议您使用规范形式(仅使用小写字母的 kebab-case)来引用属性名称。这将允许 Spring Boot 使用与放松绑定 @ConfigurationProperties时相同的逻辑。例如,将从文件以及系统环境中@Value("${demo.item-price}")获取demo.item-price和形成demo.itemPrice表格。如果你改用了,就不会考虑了。application.properties``DEMO_ITEMPRICE``@Value("${demo.itemPrice}")``demo.item-price``DEMO_ITEMPRICE

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

    SpEL在解析这些文件和填充环境时,不会处理来自应用程序属性文件的表达式 。但是,可以SpEL@Value. 如果应用程序属性文件中的属性值是一个SpEL表达式,则在通过@Value.

    Spring Profiles 提供了一种方法来隔离应用程序配置的各个部分,并使其仅在特定环境中可用。任何@Component, @Configurationor 都@ConfigurationProperties可以@Profile在加载时标上限制,如下例所示:

    @Configuration(proxyBeanMethods = false)
    @Profile("production")
    public class ProductionConfiguration {
        // ...
    

    您可以使用spring.profiles.active Environment属性来指定哪些配置文件处于活动状态。您可以使用本章前面描述的任何方式指定属性。例如,您可以将其包含在您的 中application.properties,如以下示例所示:

    spring.profiles.active=dev,hsqldb
    

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

    如果没有配置文件处于活动状态,则会启用默认配置文件。默认配置文件的名称是default,可以使用spring.profiles.default Environment属性对其进行调整,如以下示例所示:

    spring.profiles.default=none
    spring.profiles.active`并且`spring.profiles.default`只能用于非配置文件特定的文档。这意味着它们不能包含在[配置](https://docs.spring.io/spring-boot/docs/2.7.10/reference/html/features.html#features.external-config.files.activation-properties)[文件特定文件](https://docs.spring.io/spring-boot/docs/2.7.10/reference/html/features.html#features.external-config.files.profile-specific)或由.`spring.config.activate.on-profile
    

    例如第二个文件配置无效:

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

    3.1. 添加活动配置文件

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

    有时,将属性添加到活动配置文件而不是替换它们很有用。该spring.profiles.include属性可用于在属性激活的配置文件之上添加活动配置文件spring.profiles.active。入口SpringApplication点还有一个 Java API 用于设置额外的配置文件。请参阅SpringApplicationsetAdditionalProfiles()中的方法。

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

    spring.profiles.include[0]=common
    spring.profiles.include[1]=local
    

    如果给定的配置文件处于活动状态,则下一部分中描述的配置文件组也可用于添加活动配置文件。

    3.2. 配置文件组

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

    为此,Spring Boot 允许您定义配置文件组。配置文件组允许您为相关的配置文件组定义逻辑名称。

    例如,我们可以创建一个由我们的和配置文件production组成的组。proddb``prodmq

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

    现在可以开始使用我们的应用程序--spring.profiles.active=production来激活production,proddbprodmq配置文件。

    3.3. 以编程方式设置配置文件

    SpringApplication.setAdditionalProfiles(…)您可以通过在应用程序运行之前调用以编程方式设置活动配置文件。也可以通过使用 Spring 的ConfigurableEnvironment接口来激活配置文件。

    3.4. 配置文件特定的配置文件

    通过引用的application.properties(或) 和文件的特定配置文件变体被视为文件并加载。有关详细信息,请参阅“配置文件特定文件”。application.yml``@ConfigurationProperties

    4.日志记录

    Spring Boot 将Commons Logging用于所有内部日志记录,但将底层日志实现保持打开状态。为Java Util LoggingLog4J2Logback提供了默认配置。在每种情况下,记录器都预先配置为使用控制台输出,同时还提供可选的文件输出。

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

    4.1. 日志格式

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

    2023-03-23 08:14:12.786 INFO 17119 --- [main] osbdfsMyApplication:在 PID 为 17119 的 myhost 上使用 Java 1.8.0_362 启动 MyApplication(/opt/apps/myapp.jar 由 myuser 在 /opt/apps/ 中启动)
    2023-03-23 08:14:12.791 INFO 17119 --- [main] osbdfsMyApplication:未设置活动配置文件,回落到 1 个默认配置文件:“默认”
    2023-03-23 08:14:14.729 INFO 17119 --- [main] osbwembedded.tomcat.TomcatWebServer:Tomcat 初始化端口:8080 (http)
    2023-03-23 08:14:14.740 INFO 17119 --- [main] o.apache.catalina.core.StandardService:启动服务 [Tomcat]
    2023-03-23 08:14:14.741 INFO 17119 --- [main] org.apache.catalina.core.StandardEngine:启动 Servlet 引擎:[Apache Tomcat/9.0.73]
    2023-03-23 08:14:14.824 INFO 17119 --- [main] oaccC[Tomcat].[localhost].[/]:初始化 Spring 嵌入式 WebApplicationContext
    2023-03-23 08:14:14.824 INFO 17119 --- [main] wscServletWebServerApplicationContext:Root WebApplicationContext:初始化在 1939 毫秒内完成
    2023-03-23 08:14:15.444 INFO 17119 --- [main] osbwembedded.tomcat.TomcatWebServer:Tomcat 在端口上启动:8080 (http),上下文路径为“”
    2023-03-23 08:14:15.456 INFO 17119 --- [main] osbdfsMyApplication:在 4.097 秒内启动 MyApplication(JVM 运行时间为 4.769)
    2023-03-23 08:14:15.469 INFO 17119 --- [ionShutdownHook] o.apache.catalina.core.StandardService:停止服务 [Tomcat]
    

    输出以下项目:

  • 日期和时间:毫秒精度且易于排序。
  • 日志级别:ERRORWARNINFODEBUGTRACE
  • 进程标识。
  • ---用于区分实际日志消息开始的分隔符。
  • 线程名称:括在方括号中(对于控制台输出可能会被截断)。
  • 记录器名称:这通常是源类名称(通常缩写)。
  • 日志消息。
  • 4.2. 控制台输出

    默认日志配置在写入消息时将消息回显到控制台。默认情况下,记录ERROR-level、WARN-level 和-level 消息。INFO您还可以通过使用标志启动应用程序来启用“调试”模式--debug

    $ java -jar myapp.jar --debug
    

    当启用调试模式时,选择的核心记录器(嵌入式容器、Hibernate 和 Spring Boot)被配置为输出更多信息。启用调试模式不会您的应用程序配置为记录所有DEBUG级别的消息。

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

    4.2.1. 颜色编码输出

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

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

    %clr(%5p)
    

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

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

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

    支持以下颜色和样式:

  • faint
  • green
  • magenta
  • yellow
  • 4.3. 文件输出

    默认情况下,Spring Boot 只记录到控制台,不写入日志文件。如果除了控制台输出之外还想写入日志文件,则需要设置一个logging.file.namelogging.file.path属性(例如,在您的application.properties.

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

    logging.file.name logging.file.path

    4.4. 文件轮换

    如果您使用的是 Logback,则可以使用您的application.propertiesapplication.yaml文件微调日志轮换设置。对于所有其他日志系统,您将需要自己直接配置轮换设置(例如,如果您使用 Log4J2,那么您可以添加一个log4j2.xmllog4j2-spring.xml文件)。

    支持以下旋转策略属性:

    4.5. 日志级别

    所有支持的日志记录系统都可以在 Spring 中设置记录器级别Environment(例如,在 中),方法是application.properties使用TRACE、DEBUG、INFO、WARN、ERROR、FATAL 或 OFF 之一。记录器可以通过使用来配置。logging.level.<logger-name>=<level>``level``root``logging.level.root

    以下示例显示了潜在的日志记录设置application.properties

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

    也可以使用环境变量设置日志级别。例如,LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_WEB=DEBUG将设置org.springframework.webDEBUG

    4.6. 日志组

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

    为了解决这个问题,Spring Boot 允许您在 Spring 中定义日志记录组Environment。例如,您可以通过将“tomcat”组添加到您的 来定义它application.properties

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

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

    logging.level.tomcat=trace
    

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

    org.springframework.core.codec, org.springframework.http, org.springframework.web, org.springframework.boot.actuate.endpoint.web,org.springframework.boot.web.servlet.ServletContextInitializerBeans org.springframework.jdbc.core, org.hibernate.SQL,org.jooq.tools.LoggerListener

    4.7. 使用日志关闭挂钩

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

    logging.register-shutdown-hook=false
    

    4.8. 自定义日志配置

    Environment可以通过在类路径中包含适当的库来激活各种日志记录系统,并且可以通过在类路径的根目录或以下 Spring属性指定的位置提供合适的配置文件来进一步自定义:logging.config

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

    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有关示例,请参见中的默认配置:

  • Log4j 2
  • Java Util 日志记录
  • ch.qos.logback.core.joran.spi.Interpreter@4中的错误:71 - [springProperty] 没有适用的操作,当前 ElementPath 是 [[configuration][springProperty]]ch.qos.logback.core.joran.spi.Interpreter@4
    中的错误:71 - [springProfile] 没有适用的操作,当前 ElementPath 是 [[configuration][springProfile]]
    

    4.9.1. 配置文件特定的配置

    <springProfile>标记允许您根据活动的 Spring 配置文件选择性地包含或排除配置部分。元素内的任何位置都支持配置文件部分<configuration>。使用该name属性指定哪个配置文件接受配置。标记<springProfile>可以包含配置文件名称(例如staging)或配置文件表达式。配置文件表达式允许表达更复杂的配置文件逻辑,例如production & (eu-central | eu-west)。查看参考指南了解更多详情。以下清单显示了三个示例配置文件:

    <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. 环境属性

    <springProperty>标记允许您公开 Spring 的属性Environment以在 Logback 中使用。application.properties如果您想在 Logback 配置中访问文件中的值,这样做会很有用。该标签的工作方式与 Logback 的标准标签类似<property>。但是,您不是直接指定value,而是指定source属性的 (来自Environment)。如果您需要将属性存储在local作用域之外的其他地方,您可以使用scope属性。如果您需要一个回退值(以防该属性未在 中设置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>
    

    Jackson 是首选的默认库。

    6.1. 杰克逊

    提供了 Jackson 的自动配置,Jackson 是spring-boot-starter-json. 当 Jackson 在类路径上时,ObjectMapper会自动配置一个 bean。提供了几个配置属性来自定义ObjectMapper.

    6.1.1. 自定义序列化器和反序列化器

    如果您使用 Jackson 序列化和反序列化 JSON 数据,您可能想要编写自己的JsonSerializerJsonDeserializer类。自定义序列化器通常通过模块向 Jackson 注册,但 Spring Boot 提供了另一种@JsonComponent注解,可以更轻松地直接注册 Spring Beans。

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

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

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

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

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

    @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. 混入

    Jackson 支持 mixin,可用于将附加注释混合到已在目标类上声明的注释中。Spring Boot 的 Jackson 自动配置将扫描您的应用程序包以查找带有注释的类,@JsonMixin并将它们注册到自动配置的ObjectMapper. 注册由 Spring Boot 执行JsonMixinModule

    6.2. 格森

    提供了 Gson 的自动配置。当 Gson 在类路径上时,Gson会自动配置一个 bean。提供了几个spring.gson.*配置属性用于自定义配置。要获得更多控制,GsonBuilderCustomizer可以使用一个或多个 bean。

    6.3. JSON-B

    提供了 JSON-B 的自动配置。当 JSON-B API 和实现在类路径上时,Jsonb将自动配置一个 bean。首选的 JSON-B 实现是 Apache Johnzon,它提供了依赖管理。

    七、任务执行与调度

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

    Executor如果您在上下文中定义了自定义项,常规任务执行(即@EnableAsync)将透明地使用它,但不会配置 Spring MVC 支持,因为它需要一个AsyncTaskExecutor实现(名为applicationTaskExecutor)。根据您的目标安排,您可以将您的更改Executor为 aThreadPoolTaskExecutor或同时定义 aThreadPoolTaskExecutor和 anAsyncConfigurer来包装您的自定义Executor.自动配置TaskExecutorBuilder允许您轻松创建实例来重现默认情况下自动配置的功能。
    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 秒)时,线程会被回收,因此池的收缩更为激进。

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

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

    TaskExecutorBuilder如果需要创建自定义执行程序或调度程序,bean 和bean都TaskSchedulerBuilder可以在上下文中使用。

    8. 测试

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

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

    如果您有使用 JUnit 4 的测试,则可以使用 JUnit 5 的老式引擎来运行它们。要使用 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. 测试范围依赖

    “ Starter spring-boot-starter-test”(在 中test scope)包含以下提供的库:

  • JUnit 5:单元测试 Java 应用程序的实际标准。
  • Spring Test & Spring Boot Test:对 Spring Boot 应用程序的实用程序和集成测试支持。
  • AssertJ:一个流畅的断言库。
  • Hamcrest:匹配器对象库(也称为约束或谓词)。
  • Mockito:一个 Java 模拟框架。
  • JSONassert:JSON 的断言库。
  • JsonPath:JSON 的 XPath。
  • 我们通常会发现这些公共库在编写测试时很有用。如果这些库不适合您的需要,您可以添加自己的额外测试依赖项。

    8.2. 测试 Spring 应用程序

    依赖注入的主要优点之一是它应该使您的代码更容易进行单元测试。您甚至可以在不涉及 Spring 的情况下使用运算符实例化对象new。您还可以使用模拟对象而不是真正的依赖项。

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

    Spring Framework 包含一个专门用于此类集成测试的测试模块。您可以直接声明依赖项org.springframework:spring-test或使用spring-boot-starter-test“Starter”以传递方式将其拉入。

    如果您以前没有使用过该spring-test模块,您应该先阅读Spring Framework 参考文档的相关部分。

    8.3. 测试 Spring Boot 应用程序

    Spring Boot 应用程序是一个 Spring ApplicationContext,因此除了通常使用 vanilla Spring 上下文所做的之外,无需做任何特别的事情来测试它。

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

  • MOCK(默认):加载网络ApplicationContext并提供模拟网络环境。使用此注释时不会启动嵌入式服务器。如果您的类路径上没有可用的 Web 环境,此模式会透明地回退到创建常规的非 Web ApplicationContext. 它可以与您的 Web 应用程序结合使用@AutoConfigureMockMvc@AutoConfigureWebTestClient用于基于模拟的测试。
  • RANDOM_PORT: 加载WebServerApplicationContext并提供真实的网络环境。嵌入式服务器启动并侦听随机端口。
  • DEFINED_PORT: 加载WebServerApplicationContext并提供真实的网络环境。嵌入式服务器启动并侦听定义的端口(来自您的application.properties)或默认端口8080
  • NONE``ApplicationContext:通过使用加载SpringApplication但不提供任何网络环境(模拟或其他)。
  • 8.3.1. 检测 Web 应用程序类型

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

    如果两者都存在,则 Spring MVC 优先。如果要在这种情况下测试响应式 Web 应用程序,则必须设置属性spring.main.web-application-type

    @SpringBootTest(properties = "spring.main.web-application-type=reactive")
    class MyWebFluxTests {
        // ...
    

    8.3.2. 检测测试配置

    如果您熟悉 Spring 测试框架,您可能习惯于使用@ContextConfiguration(classes=…)order 来指定@Configuration加载哪个 Spring。或者,您可能经常@Configuration在测试中使用嵌套类。

    在测试 Spring Boot 应用程序时,通常不需要这样做。@*Test只要您没有明确定义,Spring Boot 的注解就会自动搜索您的主要配置。

    @SpringBootApplication搜索算法从包含测试的包开始工作,直到找到用或注释的类@SpringBootConfiguration。只要您以合理的方式构建代码,通常就能找到您的主要配置。

    8.3.3. 排除测试配置

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

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

    @SpringBootTest
    @Import(MyTestsConfiguration.class)
    class MyTests {
        @Test
        void exampleTest() {
            // ...
    

    8.3.4. 使用应用程序参数

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

    @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.5. 使用模拟环境进行测试

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

    MockMvc使用 Spring MVC,我们可以使用or查询我们的 Web 端点WebTestClient,如以下示例所示:

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

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

    @SpringBootTest
    @AutoConfigureWebTestClient
    class MyMockWebTestClientTests {
        @Test
        void exampleTest(@Autowired WebTestClient webClient) {
            webClient
                .get().uri("/")
                .exchange()
                .expectStatus().isOk()
                .expectBody(String.class).isEqualTo("Hello World");
    

    8.3.6. 使用正在运行的服务器进行测试

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

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

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

    此设置需要spring-webflux类路径。如果你不能或不会添加 webflux,Spring Boot 也提供了一个TestRestTemplate工具:

    @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.7. 自定义 WebTestClient

    要自定义WebTestClientbean,请配置一个WebTestClientBuilderCustomizerbean。任何此类 bean 都使用用于WebTestClient.Builder创建WebTestClient.

    8.3.8. 使用 JMX

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

    @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.9. 使用指标

    无论您的类路径如何,仪表注册表(内存中支持的除外)在使用@SpringBootTest.

    如果您需要将指标导出到不同的后端作为集成测试的一部分,请使用@AutoConfigureMetrics.

    8.3.10。模拟和间谍豆

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

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

    void exampleTest() { given(this.remoteService.getValue()).willReturn("spring"); String reverse = this.reverser.getReverseValue(); // Calls injected RemoteService assertThat(reverse).isEqualTo("gnirps");

    8.3.11。自动配置测试

    Spring Boot 的自动配置系统适用于应用程序,但有时对测试来说有点过分。它通常有助于仅加载测试应用程序“切片”所需的配置部分。例如,您可能想测试 Spring MVC 控制器是否正确映射 URL,并且您不想在这些测试中涉及数据库调用,或者您可能想测试 JPA 实体,而当那些时您对 Web 层不感兴趣测试运行。

    spring-boot-test-autoconfigure模块包含许多可用于自动配置此类“切片”的注释。它们中的每一个都以类似的方式工作,提供一个@…Test加载的注解ApplicationContext和一个或多个@AutoConfigure…可用于自定义自动配置设置的注解。

    8.3.12。自动配置的 JSON 测试

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

  • 杰克逊ObjectMapper,任何@JsonComponent豆子和任何Module杰克逊
  • Jsonb
  • 如果需要配置自动配置的元素,可以使用注解@AutoConfigureJsonTesters

    Spring Boot 包含基于 AssertJ 的帮助程序,这些帮助程序与 JSONAssert 和 JsonPath 库一起工作,以检查 JSON 是否按预期显示。、、和类可分别用于 Jackson、Gson、Jsonb 和字符串JacksonTester。测试类上的任何辅助字段都可以在使用. 以下示例显示了 Jackson 的测试类:GsonTester``JsonbTester``BasicJsonTester``@Autowired``@JsonTest

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

    如果您使用 Spring Boot 的基于 AssertJ 的帮助程序对给定 JSON 路径中的数字值进行断言,则可能无法使用,isEqualTo具体取决于类型。相反,您可以使用 AssertJsatisfies断言该值与给定条件匹配。例如,以下示例断言实际数字是一个接近于0.15偏移量内的浮点值0.01

    @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.13。自动配置的 Spring MVC 测试

    要测试 Spring MVC 控制器是否按预期工作,请使用@WebMvcTest注释。 @WebMvcTest自动配置 Spring MVC 基础设施并将扫描的 bean 限制为@Controller, @ControllerAdvice, @JsonComponent, Converter, GenericConverter, Filter, HandlerInterceptor, WebMvcConfigurer,WebMvcRegistrationsHandlerMethodArgumentResolver. 使用注解 时不扫描正则@Component和bean。可用于包含bean。@ConfigurationProperties``@WebMvcTest``@EnableConfigurationProperties``@ConfigurationProperties

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

    如果您使用 HtmlUnit 和 Selenium,自动配置还会提供一个 HtmlUnit WebClientbean 和/或一个 Selenium WebDriverbean。以下示例使用 HtmlUnit:

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

    8.3.14。自动配置的 Spring WebFlux 测试

    要测试Spring WebFlux控制器是否按预期工作,您可以使用@WebFluxTest注释。 @WebFluxTest自动配置 Spring WebFlux 基础设施并将扫描的 bean 限制为@Controller, @ControllerAdvice, @JsonComponent, Converter, GenericConverter,WebFilterWebFluxConfigurer. 使用注解 时不扫描正则@Component和bean。可用于包含bean。@ConfigurationProperties``@WebFluxTest``@EnableConfigurationProperties``@ConfigurationProperties

    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"); <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>
    dependencies {
        testImplementation("org.springframework.graphql:spring-graphql-test")
        // Unless already present in the implementation configuration
        testImplementation("org.springframework.boot:spring-boot-starter-webflux")
    

    这个测试模块附带了GraphQlTester。测试仪在测试中使用较多,一定要熟悉使用。有GraphQlTester多种变体,Spring Boot 将根据测试类型自动配置它们:

  • 在服务器端执行测试ExecutionGraphQlServiceTester,没有客户端也没有传输
  • HttpGraphQlTester使用连接到服务器的客户端执行测试,有或没有实时服务器
  • Spring Boot 可帮助您使用注解测试Spring GraphQL 控制器@GraphQlTest@GraphQlTest自动配置 Spring GraphQL 基础设施,不涉及任何传输或服务器。这将扫描的bean 限制为@ControllerRuntimeWiringConfigurerJsonComponentConverterGenericConverterDataFetcherExceptionResolverInstrumentation。使用注解 时不扫描GraphQlSourceBuilderCustomizer正则@Component和bean。可用于包含bean。@ConfigurationProperties``@GraphQlTest``@EnableConfigurationProperties``@ConfigurationProperties

    通常,@GraphQlTest仅限于一组控制器,并与注释结合使用,@MockBean为所需的协作者提供模拟实现。

    @GraphQlTest(GreetingController.class)
    class GreetingControllerTests {
        @Autowired
        private GraphQlTester graphQlTester;
        @Test
        void shouldGreetWithSpecificName() {
            this.graphQlTester.document("{ greeting(name: \"Alice\") } ")
                .execute()
                .path("greeting")
                .entity(String.class)
                .isEqualTo("Hello, Alice!");
        @Test
        void shouldGreetWithDefaultName() {
            this.graphQlTester.document("{ greeting } ")
                .execute()
                .path("greeting")
                .entity(String.class)
                .isEqualTo("Hello, Spring!");
    

    @SpringBootTest测试是完整的集成测试,涉及整个应用程序。使用随机或定义的端口时,会配置一个实时服务器并HttpGraphQlTester自动提供一个 bean,以便您可以使用它来测试您的服务器。配置 MOCK 环境后,您还可以HttpGraphQlTester通过使用以下注释测试类来请求 bean @AutoConfigureHttpGraphQlTester

    @AutoConfigureHttpGraphQlTester
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
    class GraphQlIntegrationTests {
        @Test
        void shouldGreetWithSpecificName(@Autowired HttpGraphQlTester graphQlTester) {
            HttpGraphQlTester authenticatedTester = graphQlTester.mutate()
                .webTestClient((client) -> client.defaultHeaders((headers) -> headers.setBasicAuth("admin", "ilovespring")))
                .build();
            authenticatedTester.document("{ greeting(name: \"Alice\") } ")
                .execute()
                .path("greeting")
                .entity(String.class)
                .isEqualTo("Hello, Alice!");
    

    8.3.16。自动配置的数据 Cassandra 测试

    您可以使用它@DataCassandraTest来测试 Cassandra 应用程序。默认情况下,它会配置一个CassandraTemplate、扫描类@Table并配置 Spring Data Cassandra 存储库。使用注解 时不扫描正则@Component和bean。可用于包含bean。(有关将 Cassandra 与 Spring Boot 结合使用的更多信息,请参阅“ data.html ”。)@ConfigurationProperties``@DataCassandraTest``@EnableConfigurationProperties``@ConfigurationProperties

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

    @DataCassandraTest
    class MyDataCassandraTests {
        @Autowired
        private SomeRepository repository;
    

    8.3.17。自动配置的数据 Couchbase 测试

    您可以使用它@DataCouchbaseTest来测试 Couchbase 应用程序。默认情况下,它配置一个CouchbaseTemplateor ReactiveCouchbaseTemplate,扫描@Document类,并配置 Spring Data Couchbase 存储库。使用注解 时不扫描正则@Component和bean。可用于包含bean。(有关将 Couchbase 与 Spring Boot 结合使用的更多信息,请参阅本章前面的“ data.html ”。)@ConfigurationProperties``@DataCouchbaseTest``@EnableConfigurationProperties``@ConfigurationProperties

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

    @DataCouchbaseTest
    class MyDataCouchbaseTests {
        @Autowired
        private SomeRepository repository;
        // ...
    

    8.3.18。自动配置的数据 Elasticsearch 测试

    您可以使用它@DataElasticsearchTest来测试 Elasticsearch 应用程序。默认情况下,它会配置一个ElasticsearchRestTemplate、扫描@Document类并配置 Spring Data Elasticsearch 存储库。使用注解 时不扫描正则@Component和bean。可用于包含bean。(有关将 Elasticsearch 与 Spring Boot 结合使用的更多信息,请参阅本章前面的“ data.html ”。)@ConfigurationProperties``@DataElasticsearchTest``@EnableConfigurationProperties``@ConfigurationProperties

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

    @DataElasticsearchTest
    class MyDataElasticsearchTests {
        @Autowired
        private SomeRepository repository;
        // ...
    

    8.3.19。自动配置的数据 JPA 测试

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

    使用注解 时不扫描正则@Component和bean。可用于包含bean。@ConfigurationProperties``@DataJpaTest``@EnableConfigurationProperties``@ConfigurationProperties

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

    @DataJpaTest
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    class MyNonTransactionalTests {
        // ...
    

    数据 JPA 测试还可以注入一个TestEntityManagerbean,它提供了一种替代专门为测试设计的标准 JPA 的方法EntityManager

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

    @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,如以下示例所示:

    @DataJpaTest
    @AutoConfigureTestDatabase(replace = Replace.NONE)
    class MyRepositoryTests {
        // ...
    

    8.3.20。自动配置的 JDBC 测试

    @JdbcTest`类似于`@DataJpaTest`但适用于只需要`DataSource`而不使用 Spring Data JDBC 的测试。默认情况下,它配置一个内存中的嵌入式数据库和一个`JdbcTemplate`. 使用注解 时不扫描正则`@Component`和bean。可用于包含bean。`@ConfigurationProperties``@JdbcTest``@EnableConfigurationProperties``@ConfigurationProperties
    

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

    @JdbcTest
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    class MyTransactionalTests {
    

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

    8.3.21。自动配置的数据 JDBC 测试

    @DataJdbcTest`类似于`@JdbcTest`但适用于使用 Spring Data JDBC 存储库的测试。默认情况下,它配置一个内存中嵌入式数据库、一个`JdbcTemplate`和 Spring Data JDBC 存储库。使用注解时只`AbstractJdbcConfiguration`扫描子类,不扫描 regular和bean。可用于包含bean。`@DataJdbcTest``@Component``@ConfigurationProperties``@EnableConfigurationProperties``@ConfigurationProperties
    

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

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

    8.3.22。自动配置的 jOOQ 测试

    您可以使用@JooqTest与 but 类似的方式@JdbcTest进行 jOOQ 相关测试。由于 jOOQ 严重依赖与数据库模式相对应的基于 Java 的模式,因此DataSource使用现有模式。如果你想用内存数据库替换它,你可以使用@AutoConfigureTestDatabase覆盖这些设置。(有关将 jOOQ 与 Spring Boot 结合使用的更多信息,请参阅“ data.html ”。)使用注释 时不会扫描Regular@Component和beans。可用于包含bean。@ConfigurationProperties``@JooqTest``@EnableConfigurationProperties``@ConfigurationProperties

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

    8.3.23。自动配置数据 MongoDB 测试

    您可以使用它@DataMongoTest来测试 MongoDB 应用程序。默认情况下,它会配置内存中的嵌入式 MongoDB(如果可用)、配置MongoTemplate、扫描@Document类并配置 Spring Data MongoDB 存储库。使用注解 时不扫描正则@Component和bean。可用于包含bean。(有关将 MongoDB 与 Spring Boot 结合使用的更多信息,请参阅“ data.html ”。)@ConfigurationProperties``@DataMongoTest``@EnableConfigurationProperties``@ConfigurationProperties

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

    @DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class)
    class MyDataMongoDbTests {
        // ...
    

    8.3.24。自动配置的数据 Neo4j 测试

    您可以使用它@DataNeo4jTest来测试 Neo4j 应用程序。默认情况下,它会扫描@Node类并配置 Spring Data Neo4j 存储库。使用注解 时不扫描正则@Component和bean。可用于包含bean。(有关将 Neo4J 与 Spring Boot 结合使用的更多信息,请参阅“ data.html ”。)@ConfigurationProperties``@DataNeo4jTest``@EnableConfigurationProperties``@ConfigurationProperties

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

    @DataNeo4jTest
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    class MyDataNeo4jTests {
    

    8.3.26。自动配置的数据 LDAP 测试

    您可以使用它@DataLdapTest来测试 LDAP 应用程序。默认情况下,它会配置内存中的嵌入式 LDAP(如果可用)、配置LdapTemplate、扫描@Entry类并配置 Spring Data LDAP 存储库。使用注解 时不扫描正则@Component和bean。可用于包含bean。(有关将 LDAP 与 Spring Boot 结合使用的更多信息,请参阅“ data.html ”。)@ConfigurationProperties``@DataLdapTest``@EnableConfigurationProperties``@ConfigurationProperties

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

    @DataLdapTest(excludeAutoConfiguration = EmbeddedLdapAutoConfiguration.class)
    class MyDataLdapTests {
        // ...
    

    8.3.27。自动配置的 REST 客户端

    您可以使用@RestClientTest注释来测试 REST 客户端。默认情况下,它会自动配置 Jackson、GSON 和 Jsonb 支持,配置一个RestTemplateBuilder,并添加对MockRestServiceServer. 使用注解 时不扫描正则@Component和bean。可用于包含bean。@ConfigurationProperties``@RestClientTest``@EnableConfigurationProperties``@ConfigurationProperties

    value应使用 的或components属性指定要测试的特定 bean @RestClientTest,如以下示例所示:

    @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.28。自动配置的 Spring REST 文档测试

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

    @AutoConfigureRestDocs可用于覆盖默认输出目录(target/generated-snippets如果您使用 Maven 或build/generated-snippetsGradle)。它还可用于配置出现在任何记录的 URI 中的主机、方案和端口。

    使用 Mock MVC 自动配置的 Spring REST Docs 测试

    @AutoConfigureRestDocs``MockMvc在测试基于 servlet 的 Web 应用程序时自定义bean 以使用 Spring REST Docs。@Autowired您可以像使用 Mock MVC 和 Spring REST Docs 时一样,通过在测试中使用和使用它来注入它,如以下示例所示:

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

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

    @TestConfiguration(proxyBeanMethods = false)
    public class MyRestDocsConfiguration implements RestDocsMockMvcConfigurationCustomizer {
        @Override
        public void customize(MockMvcRestDocumentationConfigurer configurer) {
            configurer.snippets().withTemplateFormat(TemplateFormats.markdown());
    

    如果您想使用 Spring REST Docs 对参数化输出目录的支持,您可以创建一个RestDocumentationResultHandlerbean。自动配置调用alwaysDo此结果处理程序,从而导致每次MockMvc调用自动生成默认片段。以下示例显示了一个RestDocumentationResultHandler被定义的对象:

    @TestConfiguration(proxyBeanMethods = false)
    public class MyResultHandlerConfiguration {
        @Bean
        public RestDocumentationResultHandler restDocumentation() {
            return MockMvcRestDocumentation.document("{method-name}");
    
    使用 WebTestClient 自动配置的 Spring REST Docs 测试

    @AutoConfigureRestDocs也可以在测试响应式 Web 应用程序时使用WebTestClient@Autowired您可以像使用 Spring REST Docs时一样,通过在测试中使用和使用它来注入它@WebFluxTest,如以下示例所示:

    @WebFluxTest
    @AutoConfigureRestDocs
    class MyUsersDocumentationTests {
        @Autowired
        private WebTestClient webTestClient;
        @Test
        void listUsers() {
            this.webTestClient
                .get().uri("/")
            .exchange()
            .expectStatus()
                .isOk()
            .expectBody()
                .consumeWith(document("list-users"));
    

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

    @TestConfiguration(proxyBeanMethods = false)
    public class MyRestDocsConfiguration implements RestDocsWebTestClientConfigurationCustomizer {
        @Override
        public void customize(WebTestClientRestDocumentationConfigurer configurer) {
            configurer.snippets().withEncoding("UTF-8");
    

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

    @TestConfiguration(proxyBeanMethods = false)
    public class MyWebTestClientBuilderCustomizerConfiguration {
        @Bean
        public WebTestClientBuilderCustomizer restDocumentation() {
            return (builder) -> builder.entityExchangeResultConsumer(document("{method-name}"));
    
    使用 REST Assured 自动配置的 Spring REST Docs 测试

    @AutoConfigureRestDocs制作一个RequestSpecification预配置为使用 Spring REST Docs 的 bean,可用于您的测试。@Autowired您可以像使用 REST Assured 和 Spring REST Docs 时一样,通过在测试中使用和使用它来注入它,如以下示例所示:

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

    如果您需要对 Spring REST Docs 配置的控制比 的属性提供的控制更多@AutoConfigureRestDocs,则RestDocsRestAssuredConfigurationCustomizer可以使用 bean,如以下示例所示:

    @TestConfiguration(proxyBeanMethods = false)
    public class MyRestDocsConfiguration implements RestDocsRestAssuredConfigurationCustomizer {
        @Override
        public void customize(RestAssuredRestDocumentationConfigurer configurer) {
            configurer.snippets().withTemplateFormat(TemplateFormats.markdown());
    

    8.3.29。自动配置的 Spring Web 服务测试

    自动配置的 Spring Web 服务客户端测试

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

    以下示例显示了@WebServiceClientTest正在使用的注解:

    @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);
    
    自动配置的 Spring Web 服务服务器测试

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

    以下示例显示了@WebServiceServerTest正在使用的注解:

    @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.30。额外的自动配置和切片

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

    @JdbcTest
    @ImportAutoConfiguration(IntegrationAutoConfiguration.class)
    class MyJdbcTests {
    

    或者,可以为切片注释的任何使用添加额外的自动配置,方法是将它们注册到存储在META-INF/spring以下示例中的文件中:

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

    com.example.IntegrationAutoConfiguration
    

    在此示例中,com.example.IntegrationAutoConfiguration在每个用 注释的测试上启用@JdbcTest

    8.3.31。用户配置和切片

    如果您以合理的方式构建代码,默认情况下@SpringBootApplication您的类将用作测试的配置。

    因此,重要的是不要在应用程序的主类中乱放特定于其功能的特定区域的配置设置。

    假设您正在使用 Spring Batch 并且您依赖于它的自动配置。你可以定义你@SpringBootApplication的如下:

    @SpringBootApplication
    @EnableBatchProcessing
    public class MyApplication {
        // ...
    

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

    @Configuration(proxyBeanMethods = false)
    @EnableBatchProcessing
    public class MyBatchConfiguration {
        // ...
    

    测试切片将@Configuration类排除在扫描之外。例如,对于 a @WebMvcTest,以下配置不会WebMvcConfigurer在测试切片加载的应用程序上下文中包含给定的 bean:

    @Configuration(proxyBeanMethods = false)
    public class MyWebConfiguration {
        @Bean
        public WebMvcConfigurer testConfigurer() {
            return new WebMvcConfigurer() {
                // ...
    

    但是,下面的配置将导致WebMvcConfigurer测试切片加载自定义。

    @Component
    public class MyWebMvcConfigurer implements WebMvcConfigurer {
        // ...
    

    另一个混淆来源是类路径扫描。假设,当您以合理的方式构建代码时,您需要扫描一个额外的包。您的应用程序可能类似于以下代码:

    @SpringBootApplication
    @ComponentScan({ "com.example.app", "com.example.another" })
    public class MyApplication {
        // ...
    

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

    8.3.32。使用 Spock 测试 Spring Boot 应用程序

    Spock 2.x 可用于测试 Spring Boot 应用程序。为此,请将对 Spockspock-spring模块的依赖项添加到应用程序的构建中。 spock-spring将 Spring 的测试框架集成到 Spock 中。有关详细信息,请参阅Spock 的 Spring 模块的文档。

    8.4. 测试实用程序

    一些在测试您的应用程序时通常有用的测试实用程序类被打包为spring-boot.

    8.4.1. ConfigDataApplicationContextInitializer

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

    @ContextConfiguration(classes = Config.class, initializers = ConfigDataApplicationContextInitializer.class)
    class MyConfigFileTests {
        // ...
    

    8.4.2. 测试属性值

    TestPropertyValues让您快速将属性添加到ConfigurableEnvironmentConfigurableApplicationContext。您可以使用key=value字符串调用它,如下所示:

    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是一个 JUnit Extension,您可以使用它来捕获System.outSystem.err输出。使用 add@ExtendWith(OutputCaptureExtension.class)和 injectCapturedOutput作为测试类构造函数或测试方法的参数,如下所示:

    @ExtendWith(OutputCaptureExtension.class)
    class MyOutputCaptureTests {
        @Test
        void testName(CapturedOutput output) {
            System.out.println("Hello World!");
            assertThat(output).contains("World");
    

    8.4.4. 测试模板

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

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

  • 不遵循重定向(因此您可以断言响应位置)。
  • Cookies 被忽略(因此模板是无状态的)。
  • TestRestTemplate可以直接在您的集成测试中实例化,如以下示例所示:

    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注解与WebEnvironment.RANDOM_PORT或 一起使用WebEnvironment.DEFINED_PORT,则可以注入一个完全配置的TestRestTemplate并开始使用它。如有必要,可以通过 bean 应用其他定制RestTemplateBuilder。任何未指定主机和端口的 URL 都会自动连接到嵌入式服务器,如以下示例所示:

    @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. 创建你自己的自动配置

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

    自动配置可以与提供自动配置代码以及您将使用它的典型库的“启动器”相关联。我们首先介绍构建您自己的自动配置所需了解的内容,然后我们继续介绍创建自定义启动器所需的典型步骤

    9.1. 了解自动配置的 Bean

    实现自动配置的类用@AutoConfiguration. 这个注解本身是用元注解的@Configuration,使自动配置成为标准@Configuration类。附加@Conditional注释用于限制何时应应用自动配置。通常,自动配置类使用@ConditionalOnClass@ConditionalOnMissingBean注解。这确保自动配置仅在找到相关类且您尚未声明自己的@Configuration.

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

    9.2. 定位自动配置候选者

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

    com.mycorp.libx.autoconfigure.LibXAutoConfiguration
    com.mycorp.libx.autoconfigure.LibXWebAutoConfiguration
    

    如果您的配置需要按特定顺序应用,您可以在注释或专用和注释上使用beforebeforeName和属性。例如,如果您提供特定于 Web 的配置,则您的类可能需要在.after``afterName@AutoConfiguration@AutoConfigureBefore@AutoConfigureAfterWebMvcAutoConfiguration

    如果你想订购某些相互之间不应该有任何直接知识的自动配置,你也可以使用@AutoConfigureOrder. 该注释与常规@Order注释具有相同的语义,但为自动配置类提供了专用顺序。

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

    9.3. 条件注解

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

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

  • Bean 条件
  • 网络申请条件
  • SpEL 表达条件
  • 9.3.1. 上课条件

    和注释允许根据特定类的存在或不存在来包含类@ConditionalOnClass。由于注释元数据是使用ASM解析的,因此您可以使用该属性来引用真实的类,即使该类实际上可能不会出现在正在运行的应用程序类路径中。如果您更喜欢使用值来指定类名,也可以使用该属性。@ConditionalOnMissingClass``@Configuration``value``name``String

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

    为了处理这种情况,@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();
    

    9.3.2. Bean 条件

    和注释允许根据特定 bean 的存在或不存在来包含 bean @ConditionalOnBean@ConditionalOnMissingBean您可以使用该value属性按类型指定 beans 或name按名称指定 beans。该search属性允许您限制ApplicationContext在搜索 bean 时应考虑的层次结构。

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

    @AutoConfiguration
    public class MyAutoConfiguration {
        @Bean
        @ConditionalOnMissingBean
        public SomeService someService() {
            return new SomeService();
    

    在前面的示例中,如果.bean 中尚未包含someService任何类型的 bean,则将创建该 bean 。SomeService``ApplicationContext

    9.3.3. 物业条件

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

    9.3.4. 资源条件

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

    9.3.5. 网络申请条件

    和注释允许根据应用程序是否为 Web 应用程序来包含配置@ConditionalOnWebApplication@ConditionalOnNotWebApplication基于 servlet 的 Web 应用程序是任何使用 Spring WebApplicationContext、定义session范围或具有ConfigurableWebEnvironment. 反应式 Web 应用程序是任何ReactiveWebApplicationContext使用ConfigurableReactiveWebEnvironment.

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

    9.3.6. SpEL 表达条件

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

    9.4. 测试您的自动配置

    自动配置会受到许多因素的影响:用户配置(@Bean定义和Environment定制)、条件评估(特定库的存在)等。具体来说,每个测试都应该创建一个定义良好的ApplicationContext代表这些定制的组合。 ApplicationContextRunner提供了实现这一目标的好方法。

    ApplicationContextRunner通常定义为测试类的一个字段,用于收集基础的、通用的配置。以下示例确保MyServiceAutoConfiguration始终调用它:

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

    每个测试都可以使用运行器来表示特定的用例。例如,下面的示例调用用户配置 (