核心功能

1. SpringApplication 应用程序

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

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

}
Kotlin
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication


@SpringBootApplication
class MyApplication

fun main(args: Array<String>) {
    runApplication<MyApplication>(*args)
}

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

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

2024-05-23T07:28:02.825Z  INFO 110418 --- [           main] o.s.b.d.f.logexample.MyApplication       : Starting MyApplication using Java 17.0.11 with PID 110418 (/opt/apps/myapp.jar started by myuser in /opt/apps/)
2024-05-23T07:28:02.838Z  INFO 110418 --- [           main] o.s.b.d.f.logexample.MyApplication       : No active profile set, falling back to 1 default profile: "default"
2024-05-23T07:28:04.651Z  INFO 110418 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2024-05-23T07:28:04.677Z  INFO 110418 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2024-05-23T07:28:04.678Z  INFO 110418 --- [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.24]
2024-05-23T07:28:04.829Z  INFO 110418 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2024-05-23T07:28:04.832Z  INFO 110418 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1814 ms
2024-05-23T07:28:05.612Z  INFO 110418 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2024-05-23T07:28:05.629Z  INFO 110418 --- [           main] o.s.b.d.f.logexample.MyApplication       : Started MyApplication in 4.205 seconds (process running for 5.381)

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

要在启动期间添加其他日志记录,可以在 的子类中覆盖。logStartupInfo(boolean)SpringApplication

1.1. 启动失败

如果您的应用程序无法启动,注册后将有机会提供专用错误消息和解决问题的具体操作。 例如,如果您在 port 上启动一个 Web 应用程序,并且该端口已在使用中,您应该会看到类似于以下消息的内容:FailureAnalyzers8080spring-doc.cn

***************************
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 提供了许多实现,您可以添加自己的实现。FailureAnalyzer

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

例如,如果您使用 运行应用程序,则可以按如下方式启用该属性:java -jardebugspring-doc.cn

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

1.2. 延迟初始化

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

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

可以使用 on 或 on 方法以编程方式启用延迟初始化。 或者,可以使用以下示例中所示的属性启用它:lazyInitializationSpringApplicationBuildersetLazyInitializationSpringApplicationspring.main.lazy-initializationspring-doc.cn

性能
spring.main.lazy-initialization=true
Yaml
spring:
  main:
    lazy-initialization: true
如果要对某些 bean 禁用延迟初始化,同时对应用程序的其余部分使用延迟初始化,则可以使用 Comments 将其 lazy 属性显式设置为 false。@Lazy(false)

1.3. 自定义横幅

可以通过将文件添加到 Classpath 或将属性设置为此类文件的位置来更改启动时打印的标题。 如果文件的编码不是 UTF-8,则可以设置 .banner.txtspring.banner.locationspring.banner.charsetspring-doc.cn

在文件中,您可以使用 中的任何可用键以及以下任何占位符:banner.txtEnvironmentspring-doc.cn

表 1.横幅变量
变量 描述

${application.version}spring-doc.cn

应用程序中声明的应用程序版本号 。 例如,打印为 。MANIFEST.MFImplementation-Version: 1.01.0spring-doc.cn

${application.formatted-version}spring-doc.cn

应用程序的版本号,在 中声明并格式化为显示(用括号括起来,前缀为 )。 例如。MANIFEST.MFv(v1.0)spring-doc.cn

${spring-boot.version}spring-doc.cn

您正在使用的 Spring Boot 版本。 例如。3.1.12spring-doc.cn

${spring-boot.formatted-version}spring-doc.cn

您正在使用的 Spring Boot 版本,格式化为显示(用括号括起来,前缀为 )。 例如。v(v3.1.12)spring-doc.cn

${Ansi.NAME}(或 、 、${AnsiColor.NAME}${AnsiBackground.NAME}${AnsiStyle.NAME})spring-doc.cn

其中 是 ANSI 转义码的名称。 有关详细信息,请参阅 AnsiPropertySourceNAMEspring-doc.cn

${application.title}spring-doc.cn

应用程序中声明的应用程序标题。 例如,打印为 .MANIFEST.MFImplementation-Title: MyAppMyAppspring-doc.cn

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

您还可以使用该属性来确定横幅是否必须打印在 () 上、发送到配置的记录器 () 或根本不生成 ()。spring.main.banner-modeSystem.outconsolelogoffspring-doc.cn

打印的横幅将注册为以下名称下的单例 Bean: 。springBootBannerspring-doc.cn

这些 , 和 属性仅在您使用 Spring Boot Starters或与之一起使用时可用。 如果您运行的是解压缩的 jar 并使用本机映像启动它或将应用程序作为本机映像运行,则不会解析这些值。application.titleapplication.versionapplication.formatted-versionjava -jarjava -cpjava -cp <classpath> <mainclass>spring-doc.cn

要使用这些属性,请使用 java -jar 将应用程序启动为打包的 jar,或使用 java org.springframework.boot.loader.JarLauncher 将应用程序启动为解压缩的 jar。 这将初始化应用程序。banner 属性。application.spring-doc.cn

1.4. 自定义 SpringApplication

如果默认值不符合您的口味,您可以改为创建本地实例并对其进行自定义。 例如,要关闭横幅,您可以编写:SpringApplicationspring-doc.cn

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

}
Kotlin
import org.springframework.boot.Banner
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

@SpringBootApplication
class MyApplication

fun main(args: Array<String>) {
    runApplication<MyApplication>(*args) {
        setBannerMode(Banner.Mode.OFF)
    }
}
传递给的构造函数参数是 Spring bean 的配置源。 在大多数情况下,这些是对类的引用,但它们也可以是直接引用类。SpringApplication@Configuration@Component

也可以使用文件进行配置。 有关详细信息,请参阅 外部化配置SpringApplicationapplication.propertiesspring-doc.cn

有关配置选项的完整列表,请参阅 SpringApplication Javadocspring-doc.cn

1.5. Fluent Builder API

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

这允许您将多个方法调用和包含以及允许您创建层次结构的方法链接在一起,如以下示例所示:SpringApplicationBuilderparentchildspring-doc.cn

Java
new SpringApplicationBuilder().sources(Parent.class)
    .child(Application.class)
    .bannerMode(Banner.Mode.OFF)
    .run(args);
Kotlin
SpringApplicationBuilder()
    .sources(Parent::class.java)
    .child(Application::class.java)
    .bannerMode(Banner.Mode.OFF)
    .run(*args)
创建层次结构时存在一些限制。 例如,Web 组件必须包含在子上下文中,并且父上下文和子上下文都使用相同的 Web 组件。 有关完整详细信息,请参见 SpringApplicationBuilder JavadocApplicationContextEnvironment

1.6. 应用程序可用性

在平台上部署时,应用程序可以使用 Kubernetes 探针等基础设施向平台提供有关其可用性的信息。 Spring Boot 包括对常用的“liveness”和“readiness”可用性状态的开箱即用支持。 如果您使用的是 Spring Boot 的“actuator”支持,则这些状态将作为运行状况端点组公开。spring-doc.cn

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

1.6.1. 活跃状态

应用程序的 “Liveness” 状态表明其内部状态是否允许它正常工作,或者如果当前出现故障,则自行恢复。 损坏的 “Liveness” 状态意味着应用程序处于无法恢复的状态,基础设施应重新启动应用程序。spring-doc.cn

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

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

1.6.2. 就绪状态

应用程序的 “Readiness” 状态表明应用程序是否已准备好处理流量。 失败的 “Readiness” 状态告诉平台它暂时不应将流量路由到应用程序。 这通常发生在启动期间、处理组件时,或者如果应用程序决定太忙而无法进行其他流量,则随时发生。CommandLineRunnerApplicationRunnerspring-doc.cn

一旦调用了应用程序和命令行运行器,应用程序就被视为准备就绪,请参阅 Spring Boot 应用程序生命周期和相关应用程序事件spring-doc.cn

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

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

应用程序组件可以随时通过注入接口并对其调用方法来检索当前可用性状态。 更常见的是,应用程序需要侦听状态更新或更新应用程序的状态。ApplicationAvailabilityspring-doc.cn

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

Java
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
            }
            case REFUSING_TRAFFIC -> {
                // remove file /tmp/healthy
            }
        }
    }

}
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
class MyReadinessStateExporter {

    @EventListener
    fun onStateChange(event: AvailabilityChangeEvent<ReadinessState?>) {
        when (event.state) {
            ReadinessState.ACCEPTING_TRAFFIC -> {
                // create file /tmp/healthy
            }
            ReadinessState.REFUSING_TRAFFIC -> {
                // remove file /tmp/healthy
            }
            else -> {
                // ...
            }
        }
    }

}

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

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

}
Kotlin
import org.springframework.boot.availability.AvailabilityChangeEvent
import org.springframework.boot.availability.LivenessState
import org.springframework.context.ApplicationEventPublisher
import org.springframework.stereotype.Component

@Component
class MyLocalCacheVerifier(private val eventPublisher: ApplicationEventPublisher) {

    fun checkLocalCache() {
        try {
            // ...
        } catch (ex: CacheCompletelyBrokenException) {
            AvailabilityChangeEvent.publish(eventPublisher, ex, LivenessState.BROKEN)
        }
    }

}

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

除了通常的 Spring Framework 事件(例如ContextRefreshedEvent)之外,a 还会发送一些其他应用程序事件。SpringApplicationspring-doc.cn

某些事件实际上是在创建 之前触发的,因此您无法在这些事件上将侦听器注册为 。 您可以使用 method 或 method 注册它们。ApplicationContext@BeanSpringApplication.addListeners(…​)SpringApplicationBuilder.listeners(…​)spring-doc.cn

如果您希望自动注册这些侦听器,而不管应用程序是如何创建的,您都可以将文件添加到项目中并使用 key 引用您的侦听器,如以下示例所示:META-INF/spring.factoriesorg.springframework.context.ApplicationListenerspring-doc.cn

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

应用程序事件在应用程序运行时按以下顺序发送:spring-doc.cn

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

  2. 当 要在上下文中使用的 已知但在创建上下文之前,将发送 An。ApplicationEnvironmentPreparedEventEnvironmentspring-doc.cn

  3. 当准备好并调用ApplicationContextInitializers时,但在加载任何 bean 定义之前,将发送一个。ApplicationContextInitializedEventApplicationContextspring-doc.cn

  4. 在刷新开始之前,但在加载 Bean 定义之后发送 AN。ApplicationPreparedEventspring-doc.cn

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

  6. An 紧随其后发送 with,以指示应用程序被视为实时应用程序。AvailabilityChangeEventLivenessState.CORRECTspring-doc.cn

  7. 在调用任何应用程序和命令行运行程序后发送 AN。ApplicationReadyEventspring-doc.cn

  8. An 紧随其后发送 with,以指示应用程序已准备好为请求提供服务。AvailabilityChangeEventReadinessState.ACCEPTING_TRAFFICspring-doc.cn

  9. 如果启动时出现异常,则发送 An。ApplicationFailedEventspring-doc.cn

上面的列表仅包含绑定到 . 除此之外,以下事件还会在 之后 和 之前发布 :SpringApplicationEventSpringApplicationApplicationPreparedEventApplicationStartedEventspring-doc.cn

  • A 在 准备就绪后发送。 和 分别是 servlet 和 reactive 变体。WebServerInitializedEventWebServerServletWebServerInitializedEventReactiveWebServerInitializedEventspring-doc.cn

  • 刷新 时发送 A。ContextRefreshedEventApplicationContextspring-doc.cn

您通常不需要使用应用程序事件,但知道它们存在会很方便。 在内部, Spring Boot 使用事件来处理各种任务。
事件侦听器不应运行可能很长的任务,因为它们默认在同一线程中执行。 请考虑改用应用程序和命令行运行程序

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

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

1.8. Web 环境

A 尝试代表您创建正确的 类型。 用于确定 a 的算法如下:SpringApplicationApplicationContextWebApplicationTypespring-doc.cn

  • 如果存在 Spring MVC,则使用AnnotationConfigServletWebServerApplicationContextspring-doc.cn

  • 如果 Spring MVC 不存在而 Spring WebFlux 存在,则使用AnnotationConfigReactiveWebServerApplicationContextspring-doc.cn

  • 否则,使用AnnotationConfigApplicationContextspring-doc.cn

这意味着,如果你在同一个应用程序中使用 Spring MVC 和 Spring WebFlux 中的新版本,则默认情况下将使用 Spring MVC。 您可以通过调用 .WebClientsetWebApplicationType(WebApplicationType)spring-doc.cn

还可以通过调用 .ApplicationContextsetApplicationContextFactory(…​)spring-doc.cn

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

1.9. 访问应用程序参数

如果需要访问传递给 的应用程序参数,则可以注入一个 bean。 该接口提供对原始参数以及 parsed 和 arguments 的访问,如以下示例所示:SpringApplication.run(…​)org.springframework.boot.ApplicationArgumentsApplicationArgumentsString[]optionnon-optionspring-doc.cn

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

}
Kotlin
import org.springframework.boot.ApplicationArguments
import org.springframework.stereotype.Component

@Component
class MyBean(args: ApplicationArguments) {

    init {
        val debug = args.containsOption("debug")
        val files = args.nonOptionArgs
        if (debug) {
            println(files)
        }
        // if run with "--debug logfile.txt" prints ["logfile.txt"]
    }

}
Spring Boot 还向 Spring 注册 a 。 这还允许您使用 annotation 注入单个应用程序参数。CommandLinePropertySourceEnvironment@Value

1.10. 使用 ApplicationRunner 或 CommandLineRunner

如果你需要在启动后运行一些特定的代码,你可以实现 or 接口。 这两个接口的工作方式相同,并提供单个方法,该方法在完成之前调用。SpringApplicationApplicationRunnerCommandLineRunnerrunSpringApplication.run(…​)spring-doc.cn

此协定非常适合应在应用程序启动之后但在开始接受流量之前运行的任务。

接口以字符串数组的形式提供对应用程序参数的访问,而 则使用前面讨论的接口。 以下示例显示了 with a 方法:CommandLineRunnerApplicationRunnerApplicationArgumentsCommandLineRunnerrunspring-doc.cn

Java
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class MyCommandLineRunner implements CommandLineRunner {

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

}
Kotlin
import org.springframework.boot.CommandLineRunner
import org.springframework.stereotype.Component

@Component
class MyCommandLineRunner : CommandLineRunner {

    override fun run(vararg args: String) {
        // Do something...
    }

}

如果定义了多个 或 bean,并且必须按特定 Sequences 调用,则还可以实现接口或使用 Comments。CommandLineRunnerApplicationRunnerorg.springframework.core.Orderedorg.springframework.core.annotation.Orderspring-doc.cn

1.11. 应用程序退出

每个 API 都会向 JVM 注册一个 shutdown 钩子,以确保 在退出时正常关闭。 可以使用所有标准的 Spring 生命周期回调(例如接口或 Comments)。SpringApplicationApplicationContextDisposableBean@PreDestroyspring-doc.cn

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

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

}
Kotlin
import org.springframework.boot.ExitCodeGenerator
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Bean

import kotlin.system.exitProcess

@SpringBootApplication
class MyApplication {

    @Bean
    fun exitCodeGenerator() = ExitCodeGenerator { 42 }

}

fun main(args: Array<String>) {
    exitProcess(SpringApplication.exit(
        runApplication<MyApplication>(*args)))
}

此外,该接口可能由异常实现。 当遇到此类异常时, Spring Boot 返回已实现的方法提供的退出代码。ExitCodeGeneratorgetExitCode()spring-doc.cn

如果有多个 ,则使用生成的第一个非零退出代码。 要控制生成器的调用顺序,请另外实现接口或使用 Comments。ExitCodeGeneratororg.springframework.core.Orderedorg.springframework.core.annotation.Orderspring-doc.cn

1.12. 管理员功能

可以通过指定属性为应用程序启用与管理员相关的功能。 这会在 platform 上公开 SpringApplicationAdminMXBean。 您可以使用此功能远程管理 Spring Boot 应用程序。 此功能对于任何服务包装器实现也很有用。spring.application.admin.enabledMBeanServerspring-doc.cn

如果您想知道应用程序正在哪个 HTTP 端口上运行,请获取键为 .local.server.port

1.13. 应用程序启动跟踪

在应用程序启动期间,和 执行许多与应用程序生命周期相关的任务, bean 生命周期,甚至处理应用程序事件。 通过ApplicationStartup, Spring Framework 允许你使用StartupStep对象跟踪应用程序启动序列。 收集此数据可以用于分析目的,或者只是为了更好地了解应用程序启动过程。SpringApplicationApplicationContextspring-doc.cn

您可以在设置实例时选择实施。 例如,要使用 ,您可以编写:ApplicationStartupSpringApplicationBufferingApplicationStartupspring-doc.cn

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

}
Kotlin
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup
import org.springframework.boot.runApplication

@SpringBootApplication
class MyApplication

fun main(args: Array<String>) {
    runApplication<MyApplication>(*args) {
        applicationStartup = BufferingApplicationStartup(2048)
    }
}

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

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

Spring Boot 附带了该变体;此实现用于缓冲启动步骤并将其排空到外部 Metrics 系统中。 应用程序可以在任何组件中请求 type 为 的 bean。BufferingApplicationStartupBufferingApplicationStartupspring-doc.cn

Spring Boot 还可以配置为公开一个启动端点,该端点将此信息作为 JSON 文档提供。spring-doc.cn

2. 外部化配置

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

属性值可以通过使用 Comments 直接注入到 bean 中,通过 Spring 的抽象访问,或者通过 .@ValueEnvironment@ConfigurationPropertiesspring-doc.cn

Spring Boot 使用一个非常特殊的 Sequences,旨在允许合理地覆盖值。 后面的属性源可以覆盖前面的属性源中定义的值。 按以下顺序考虑源:PropertySourcespring-doc.cn

  1. 默认属性(通过设置 指定)。SpringApplication.setDefaultPropertiesspring-doc.cn

  2. @PropertySource类上的注释。 请注意,在刷新应用程序上下文之前,此类属性源不会添加到 。 现在配置某些属性(例如,在刷新开始之前读取的 and)为时已晚。@ConfigurationEnvironmentlogging.*spring.main.*spring-doc.cn

  3. 配置数据(例如文件)。application.propertiesspring-doc.cn

  4. A 仅在 中具有属性。RandomValuePropertySourcerandom.*spring-doc.cn

  5. OS 环境变量。spring-doc.cn

  6. Java 系统属性 ()。System.getProperties()spring-doc.cn

  7. JNDI 属性来自 .java:comp/envspring-doc.cn

  8. ServletContextinit 参数。spring-doc.cn

  9. ServletConfiginit 参数。spring-doc.cn

  10. 属性(嵌入在环境变量或系统属性中的内联 JSON)。SPRING_APPLICATION_JSONspring-doc.cn

  11. 命令行参数。spring-doc.cn

  12. properties属性。 可用于 @SpringBootTest 和测试注释,用于测试应用程序的特定切片spring-doc.cn

  13. @DynamicPropertySource Comments。spring-doc.cn

  14. @TestPropertySource 测试中的注释。spring-doc.cn

  15. devtools 处于活动状态时目录中的 devtools 全局设置属性$HOME/.config/spring-bootspring-doc.cn

配置数据文件按以下顺序考虑:spring-doc.cn

  1. 打包在 jar 中的应用程序属性(和 YAML 变体)。application.propertiesspring-doc.cn

  2. 打包在 jar 中(和 YAML 变体)的特定于配置文件的应用程序属性application-{profile}.propertiesspring-doc.cn

  3. 打包的 jar(和 YAML 变体)之外的应用程序属性application.propertiesspring-doc.cn

  4. 打包的 jar(和 YAML 变体)之外特定于配置文件的应用程序属性application-{profile}.propertiesspring-doc.cn

建议整个应用程序坚持使用一种格式。 如果在同一位置有 和 YAML 格式的配置文件,则优先。.properties.properties
如果使用环境变量而不是系统属性,则大多数操作系统不允许使用句点分隔的键名称,但您可以改用下划线(例如,而不是 )。 有关详细信息,请参阅从环境变量绑定SPRING_CONFIG_NAMEspring.config.name
如果应用程序在 servlet 容器或应用程序服务器中运行,则可以使用 JNDI 属性 (in) 或 servlet 上下文初始化参数来代替环境变量或系统属性。java:comp/env

为了提供具体示例,假设您开发了一个使用属性的 a,如以下示例所示:@Componentnamespring-doc.cn

Java
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    @Value("${name}")
    private String name;

    // ...

}
Kotlin
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component

@Component
class MyBean {

    @Value("\${name}")
    private val name: String? = null

    // ...

}

在应用程序类路径上(例如,在 jar 中),您可以有一个文件,该文件为 . 在新环境中运行时,可以在 jar 外部提供一个文件,该文件会覆盖 . 对于一次性测试,您可以使用特定的命令行开关(例如)。application.propertiesnameapplication.propertiesnamejava -jar app.jar --name="Spring"spring-doc.cn

和 endpoints 可用于确定属性具有特定值的原因。 您可以使用这两个终端节点来诊断意外的属性值。 有关详细信息,请参阅“生产就绪功能”部分。envconfigprops

2.1. 访问命令行属性

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

如果不希望将命令行属性添加到 中,则可以使用 来禁用它们。EnvironmentSpringApplication.setAddCommandLineProperties(false)spring-doc.cn

2.2. JSON 应用程序属性

环境变量和系统属性通常具有限制,这意味着无法使用某些属性名称。 为了帮助解决这个问题, Spring Boot 允许您将一个属性块编码为单个 JSON 结构。spring-doc.cn

当您的应用程序启动时,将解析 any 或 属性并将其添加到 .spring.application.jsonSPRING_APPLICATION_JSONEnvironmentspring-doc.cn

例如,可以在 UN*X shell 的命令行中将该属性作为环境变量提供:SPRING_APPLICATION_JSONspring-doc.cn

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

在前面的示例中,您最终会在 Spring .my.name=testEnvironmentspring-doc.cn

相同的 JSON 也可以作为系统属性提供:spring-doc.cn

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

或者,您可以使用命令行参数提供 JSON:spring-doc.cn

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

如果要部署到经典 Application Server,则还可以使用名为 的 JNDI 变量。java:comp/env/spring.application.jsonspring-doc.cn

尽管 JSON 中的值将添加到生成的属性源中,但 会将属性视为缺失值。 这意味着 JSON 无法使用值覆盖低阶属性源中的属性。nullPropertySourcesPropertyResolvernullnull

2.3. 外部应用程序属性

Spring Boot 将在应用程序启动时自动从以下位置查找并加载文件:application.propertiesapplication.yamlspring-doc.cn

  1. 从 classpathspring-doc.cn

    1. 类路径根spring-doc.cn

    2. classpath 包/configspring-doc.cn

  2. 从当前目录spring-doc.cn

    1. 当前目录spring-doc.cn

    2. 当前目录中的子目录config/spring-doc.cn

    3. 子目录的直接子目录config/spring-doc.cn

该列表按优先级排序(较低项中的值将覆盖较早项的值)。 加载文件中的文档将添加到 Spring 中。PropertySourcesEnvironmentspring-doc.cn

如果您不喜欢作为配置文件名,则可以通过指定 environment 属性来切换到其他文件名。 例如,要查找 and 文件,您可以按如下方式运行应用程序:applicationspring.config.namemyproject.propertiesmyproject.yamlspring-doc.cn

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

您还可以使用 environment 属性引用显式位置。 此属性接受要检查的一个或多个位置的逗号分隔列表。spring.config.locationspring-doc.cn

以下示例显示如何指定两个不同的文件:spring-doc.cn

$ java -jar myproject.jar --spring.config.location=\
    optional:classpath:/default.properties,\
    optional:classpath:/override.properties
如果位置是可选的,并且您不介意它们不存在,请使用前缀。optional:
spring.config.name、 和 用于确定必须加载哪些文件。 它们必须定义为环境属性(通常是 OS 环境变量、系统属性或命令行参数)。spring.config.locationspring.config.additional-location

如果包含目录(而不是文件),则它们应以 . 在运行时,它们将附加加载之前生成的名称。 中指定的文件将直接导入。spring.config.location/spring.config.namespring.config.locationspring-doc.cn

目录和文件位置值也都进行了扩展,以检查特定于配置文件的文件。 例如,如果您有 of ,您还会发现加载了相应的文件。spring.config.locationclasspath:myconfig.propertiesclasspath:myconfig-<profile>.properties

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

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

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

  1. optional:classpath:custom-config/spring-doc.cn

  2. optional:file:./custom-config/spring-doc.cn

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

  1. optional:classpath:/;optional:classpath:/config/spring-doc.cn

  2. optional:file:./;optional:file:./config/;optional:file:./config/*/spring-doc.cn

  3. optional:classpath:custom-config/spring-doc.cn

  4. optional:file:./custom-config/spring-doc.cn

此搜索顺序允许您在一个配置文件中指定默认值,然后在另一个配置文件中选择性地覆盖这些值。 您可以在其中一个默认位置 (或您选择的任何其他 basename ) 中为应用程序提供默认值。 然后,可以在运行时使用位于其中一个自定义位置的不同文件覆盖这些默认值。application.propertiesspring.config.namespring-doc.cn

2.3.1. 可选位置

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

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

例如,值 of 允许您的应用程序启动,即使文件缺失也是如此。spring.config.importoptional:file:./myconfig.propertiesmyconfig.propertiesspring-doc.cn

如果要忽略所有并始终继续启动应用程序,则可以使用该属性。 将值设置为 using 或 with a system/environment variable。ConfigDataLocationNotFoundExceptionsspring.config.on-not-foundignoreSpringApplication.setDefaultProperties(…​)spring-doc.cn

2.3.2. 通配符位置

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

例如,如果您有一些 Redis 配置和一些 MySQL 配置,您可能希望将这两个配置分开,同时要求这两个配置都存在于一个文件中。 这可能会导致两个单独的文件挂载在不同的位置,例如 和 。 在这种情况下,如果通配符位置为 ,将导致两个文件都被处理。application.propertiesapplication.properties/config/redis/application.properties/config/mysql/application.propertiesconfig/*/spring-doc.cn

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

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

通配符位置必须仅包含一个通配符位置,对于作为目录的搜索位置或作为文件的搜索位置,通配符位置必须以 结尾。 带有通配符的位置根据文件名的绝对路径按字母顺序排序。**/*/<filename>
通配符位置仅适用于外部目录。 不能在某个位置使用通配符。classpath:

2.3.3. 分析特定文件

除了属性文件,Spring Boot 还将尝试使用 naming convention 加载特定于配置文件的文件。 例如,如果您的应用程序激活名为 YAML 文件的配置文件并使用 YAML 文件,则 和 都将被考虑。applicationapplication-{profile}prodapplication.yamlapplication-prod.yamlspring-doc.cn

特定于配置文件的属性从与 standard 相同的位置加载,特定于配置文件的文件始终覆盖非特定文件。 如果指定了多个配置文件,则适用 last-wins 策略。 例如,如果配置文件由属性指定,则 中的值可以被 中的值覆盖。application.propertiesprod,livespring.profiles.activeapplication-prod.propertiesapplication-live.propertiesspring-doc.cn

“最后获胜”策略适用于营业地点组级别。 A of 将具有与 .spring.config.locationclasspath:/cfg/,classpath:/ext/classpath:/cfg/;classpath:/ext/spring-doc.cn

例如,继续上面的示例,我们可能有以下文件:prod,livespring-doc.cn

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

当我们有 a of 时,我们会先处理所有文件,然后再处理所有文件:spring.config.locationclasspath:/cfg/,classpath:/ext//cfg/extspring-doc.cn

  1. /cfg/application-live.propertiesspring-doc.cn

  2. /ext/application-prod.propertiesspring-doc.cn

  3. /ext/application-live.propertiesspring-doc.cn

当我们有 (带有分隔符) 时,我们会在同一级别处理 and:classpath:/cfg/;classpath:/ext/;/cfg/extspring-doc.cn

  1. /ext/application-prod.propertiesspring-doc.cn

  2. /cfg/application-live.propertiesspring-doc.cn

  3. /ext/application-live.propertiesspring-doc.cn

具有一组默认配置文件(默认情况下 ),如果未设置活动配置文件,则使用这些配置文件。 换句话说,如果未明确激活任何用户档案,则考虑 中的属性。Environment[default]application-defaultspring-doc.cn

属性文件只加载一次。 如果您已经直接导入了特定于配置文件的属性文件,则不会再次导入它。

2.3.4. 导入其他数据

应用程序属性可以使用该属性从其他位置导入进一步的配置数据。 导入在被发现时进行处理,并被视为插入到声明导入的导入文档的正下方的附加文档。spring.config.importspring-doc.cn

例如,您的 Classpath 文件中可能包含以下内容:application.propertiesspring-doc.cn

性能
spring.application.name=myapp
spring.config.import=optional:file:./dev.properties
Yaml
spring:
  application:
    name: "myapp"
  config:
    import: "optional:file:./dev.properties"

这将触发当前目录中文件的导入(如果存在此类文件)。 导入的值将优先于触发导入的文件。 在上面的示例中,可以重新定义为不同的值。dev.propertiesdev.propertiesdev.propertiesspring.application.namespring-doc.cn

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

性能
spring.config.import=my.properties
my.property=value
Yaml
spring:
  config:
    import: "my.properties"
my:
  property: "value"
性能
my.property=value
spring.config.import=my.properties
Yaml
my:
  property: "value"
spring:
  config:
    import: "my.properties"

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

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

在适当时,还会考虑导入特定于 Profile 的变体。 上面的示例将导入 both 以及 any variants。my.propertiesmy-<profile>.properties

Spring Boot 包含可插拔 API,允许支持各种不同的位置地址。 默认情况下,您可以导入 Java 属性、YAML 和“配置树”。spring-doc.cn

第三方 jar 可以提供对其他技术的支持(不要求文件是本地的)。 例如,您可以想象配置数据来自 Consul、Apache ZooKeeper 或 Netflix Archaius 等外部存储。spring-doc.cn

如果要支持自己的位置,请参阅包中的 和 类。ConfigDataLocationResolverConfigDataLoaderorg.springframework.boot.context.configspring-doc.cn

2.3.5. 导入无扩展文件

某些云平台无法向卷挂载的文件添加文件扩展名。 要导入这些无扩展名文件,你需要给 Spring Boot 一个提示,以便它知道如何加载它们。 您可以通过在方括号中放置扩展提示来执行此操作。spring-doc.cn

例如,假设您有一个希望作为 yaml 导入的文件。 您可以使用以下方法将其导入:/etc/config/myconfigapplication.propertiesspring-doc.cn

性能
spring.config.import=file:/etc/config/myconfig[.yaml]
Yaml
spring:
  config:
    import: "file:/etc/config/myconfig[.yaml]"

2.3.6. 使用配置树

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

作为环境变量的替代方案,许多云平台现在允许您将配置映射到挂载的数据卷。 例如,Kubernetes 可以同时对 ConfigMapSecret 进行卷挂载。spring-doc.cn

可以使用两种常见的卷挂载模式:spring-doc.cn

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

  2. 多个文件被写入目录树,文件名成为 'key',内容成为 'value'。spring-doc.cn

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

例如,假设 Kubernetes 挂载了以下卷:spring-doc.cn

etc/
  config/
    myapp/
      username
      password

文件的内容将是 config 值,而 的内容将是 secret。usernamepasswordspring-doc.cn

要导入这些属性,您可以将以下内容添加到您的 or 文件中:application.propertiesapplication.yamlspring-doc.cn

性能
spring.config.import=optional:configtree:/etc/config/
Yaml
spring:
  config:
    import: "optional:configtree:/etc/config/"

然后,你可以以通常的方式从 中访问或注入 和 属性。myapp.usernamemyapp.passwordEnvironmentspring-doc.cn

配置树下的文件夹和文件的名称构成属性名称。 在上面的示例中,要访问属性 as 和 ,您可以设置为 。usernamepasswordspring.config.importoptional:configtree:/etc/config/myapp
带有点表示法的文件名也会正确映射。 例如,在上面的示例中,名为 in 的文件将导致 .myapp.username/etc/configmyapp.usernameEnvironment
配置树值可以绑定到 string 和 types,具体取决于预期的内容。Stringbyte[]

如果要从同一个父文件夹导入多个配置树,则可以使用通配符快捷方式。 任何以 结尾的位置都会将所有直接子项作为配置树导入。 与非通配符导入一样,每个配置树下的文件夹和文件的名称构成属性名称。configtree:/*/spring-doc.cn

例如,给定以下卷:spring-doc.cn

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

您可以用作导入位置:configtree:/etc/config/*/spring-doc.cn

性能
spring.config.import=optional:configtree:/etc/config/*/
Yaml
spring:
  config:
    import: "optional:configtree:/etc/config/*/"

这将添加 、 和 属性。db.usernamedb.passwordmq.usernamemq.passwordspring-doc.cn

使用通配符加载的目录按字母顺序排序。 如果您需要不同的顺序,则应将每个位置列为单独的导入

配置树还可用于 Docker 密钥。 当 Docker Swarm 服务被授予对 secret 的访问权限时,secret 将被挂载到容器中。 例如,如果名为 的密钥挂载在 location ,则可以使用以下内容对 Spring 环境可用:db.password/run/secrets/db.passwordspring-doc.cn

性能
spring.config.import=optional:configtree:/run/secrets/
Yaml
spring:
  config:
    import: "optional:configtree:/run/secrets/"

2.3.7. 属性占位符

和 中的值在使用时通过现有值进行筛选,因此您可以引用以前定义的值 (例如,从系统属性或环境变量)。 标准 property-placeholder 语法可以在值中的任何位置使用。 属性占位符还可以使用 a 将默认值与属性名称分开,例如 。application.propertiesapplication.yamlEnvironment${name}:${name:default}spring-doc.cn

以下示例显示了带和不带默认值的占位符的用法:spring-doc.cn

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

假设该属性尚未在其他位置设置,则其值为 .usernameapp.descriptionMyApp is a Spring Boot application written by Unknownspring-doc.cn

您应该始终使用其规范形式(kebab-case 仅使用小写字母)在占位符中引用属性名称。 这将允许 Spring Boot 使用与 relaxed binding 时相同的 logic 。@ConfigurationPropertiesspring-doc.cn

例如,将从文件以及系统环境中选取 和 form。 如果你改用,则不会被考虑。${demo.item-price}demo.item-pricedemo.itemPriceapplication.propertiesDEMO_ITEMPRICE${demo.itemPrice}demo.item-priceDEMO_ITEMPRICEspring-doc.cn

您还可以使用此技术创建现有 Spring Boot 属性的“短”变体。 有关详细信息,请参阅 howto.html 操作方法。

2.3.8. 使用多文档文件

Spring Boot 允许您将单个物理文件拆分为多个 logical 文档,每个 logical 文档都是独立添加的。 文档按从上到下的顺序处理。 后面的文档可以覆盖前面文档中定义的属性。spring-doc.cn

对于文件,使用标准的 YAML 多文档语法。 三个连续的连字符表示一个文档的结尾和下一个文档的开头。application.yamlspring-doc.cn

例如,以下文件有两个逻辑文档:spring-doc.cn

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

对于文件,使用 special 或 comment 来标记文档拆分:application.properties#---!---spring-doc.cn

spring.application.name=MyApp
#---
spring.application.name=MyCloudApp
spring.config.activate.on-cloud-platform=kubernetes
属性文件分隔符不得有任何前导空格,并且必须恰好包含三个连字符。 紧接在分隔符之前和之后的行不能是相同的注释前缀。
多文档属性文件通常与激活属性(如 . 有关详细信息,请参阅下一节spring.config.activate.on-profile
无法使用 or 注释加载多文档属性文件。@PropertySource@TestPropertySource

2.3.9. 激活属性

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

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

可以使用以下激活属性:spring-doc.cn

表 2.激活属性
财产 注意

on-profilespring-doc.cn

必须匹配的配置文件表达式,文档才能处于活动状态。spring-doc.cn

on-cloud-platformspring-doc.cn

必须检测到 才能使文档处于活动状态。CloudPlatformspring-doc.cn

例如,以下指定第二个文档仅在 Kubernetes 上运行时处于活动状态,并且仅当 “prod” 或 “staging” 配置文件处于活动状态时:spring-doc.cn

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

2.4. 加密属性

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

如果你需要一种安全的方式来存储凭证和密码,Spring Cloud Vault 项目提供了在 HashiCorp Vault 中存储外部化配置的支持。spring-doc.cn

2.5. 使用 YAML

YAML 是 JSON 的超集,因此是指定分层配置数据的便捷格式。 只要你的 Classpath 上有 SnakeYAML 库,该类就会自动支持 YAML 作为属性的替代。SpringApplicationspring-doc.cn

如果您使用 “Starters”,则 SnakeYAML 由 .spring-boot-starter

2.5.1. 将 YAML 映射到属性

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

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

为了从 访问这些属性,它们将被拼合,如下所示:Environmentspring-doc.cn

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 列表也需要扁平化。 它们表示为带有取消引用器的属性键。 例如,请考虑以下 YAML:[index]spring-doc.cn

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

前面的示例将转换为以下属性:spring-doc.cn

my.servers[0]=dev.example.com
my.servers[1]=another.example.com
使用该表示法的属性可以使用 Spring Boot 的类绑定到 Java 或对象。 有关更多详细信息,请参阅下面的“类型安全配置属性”部分。[index]ListSetBinder
无法使用 or 注解加载 YAML 文件。 因此,如果需要以这种方式加载值,则需要使用属性文件。@PropertySource@TestPropertySource

2.5.2. 直接加载 YAML

Spring Framework 提供了两个方便的类,可用于加载 YAML 文档。 加载 YAML 作为 YAML,将 YAML 加载为 .YamlPropertiesFactoryBeanPropertiesYamlMapFactoryBeanMapspring-doc.cn

如果要将 YAML 加载为 Spring ,也可以使用该类。YamlPropertySourceLoaderPropertySourcespring-doc.cn

2.6. 配置随机值

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

性能
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]}
Yaml
my:
  secret: "${random.value}"
  number: "${random.int}"
  bignumber: "${random.long}"
  uuid: "${random.uuid}"
  number-less-than-ten: "${random.int(10)}"
  number-in-range: "${random.int[1024,65536]}"

语法是其中 s 是任何字符 和 整数。 如果提供,则为最小值和最大值(不包括)。random.int*OPEN value (,max) CLOSEOPEN,CLOSEvalue,maxmaxvaluemaxspring-doc.cn

2.7. 配置系统环境属性

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

例如,如果将前缀设置为 ,则诸如 这样的属性也将像在系统环境中一样进行解析。inputremote.timeoutinput.remote.timeoutspring-doc.cn

2.8. 类型安全的配置属性

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

2.8.1. JavaBean 属性绑定

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

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

    }

}
Kotlin
import org.springframework.boot.context.properties.ConfigurationProperties
import java.net.InetAddress

@ConfigurationProperties("my.service")
class MyProperties {

    var isEnabled = false

    var remoteAddress: InetAddress? = null

    val security = Security()

    class Security {

        var username: String? = null

        var password: String? = null

        var roles: List<String> = ArrayList(setOf("USER"))

    }

}

前面的 POJO 定义了以下属性:spring-doc.cn

  • my.service.enabled,默认值为falsespring-doc.cn

  • my.service.remote-address,其类型可以从 强制转换。Stringspring-doc.cn

  • my.service.security.username,其中包含一个嵌套的 “security” 对象,其名称由属性名称确定。 特别是,该类型根本没有在那里使用,并且可能是 。SecurityPropertiesspring-doc.cn

  • my.service.security.password.spring-doc.cn

  • my.service.security.roles,其中的集合默认为 .StringUSERspring-doc.cn

映射到 Spring Boot 中可用的类的属性(通过属性文件、YAML 文件、环境变量和其他机制进行配置)是公共 API,但类本身的访问器(getter/setter)不能直接使用。@ConfigurationProperties

这种安排依赖于默认的空构造函数,并且 getter 和 setter 通常是强制性的,因为绑定是通过标准 Java Beans 属性描述符进行的,就像在 Spring MVC 中一样。 在以下情况下,可以省略 setter:spring-doc.cn

  • 只要 Map 被初始化,就需要一个 getter,但不一定是一个 setter,因为它们可以被 binders 改变。spring-doc.cn

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

  • 如果初始化了嵌套的 POJO 属性(如前面示例中的字段),则不需要 setter。 如果希望 Binders 使用其默认构造函数动态创建实例,则需要 setter。Securityspring-doc.cn

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

最后,仅考虑标准 Java Bean 属性,并且不支持对静态属性进行绑定。spring-doc.cn

2.8.2. 构造函数绑定

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

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

    }

}
Kotlin
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.bind.DefaultValue
import java.net.InetAddress

@ConfigurationProperties("my.service")
class MyProperties(val enabled: Boolean, val remoteAddress: InetAddress,
        val security: Security) {

    class Security(val username: String, val password: String,
            @param:DefaultValue("USER") val roles: List<String>)

}

在此设置中,存在单个参数化构造函数意味着应使用构造函数绑定。 这意味着 Binder 将找到一个构造函数,其中包含您希望绑定的参数。 如果您的类具有多个构造函数,则注释可用于指定要用于构造函数绑定的构造函数。 要选择退出具有单个参数化构造函数的类的构造函数绑定,必须为构造函数添加注释或 made . 构造函数绑定可以与记录一起使用。 除非您的记录具有多个构造函数,否则无需使用 .@ConstructorBinding@Autowiredprivate@ConstructorBindingspring-doc.cn

构造函数绑定类的嵌套成员(如上例所示)也将通过其构造函数进行绑定。Securityspring-doc.cn

可以使用 on constructor parameters 和 record 组件指定默认值。 将应用转换服务以将 Comments 的值强制转换为缺失属性的目标类型。@DefaultValueStringspring-doc.cn

参考前面的示例,如果没有属性绑定到 ,则实例将包含 的值 。 要使其包含非 null 实例,即使没有绑定到任何属性(使用 Kotlin 时,这将需要将 和 参数声明为可为 null,因为它们没有默认值),请使用空注解:SecurityMyPropertiesnullsecuritySecurityusernamepasswordSecurity@DefaultValuespring-doc.cn

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

    class Security(val username: String?, val password: String?,
            @param:DefaultValue("USER") val roles: List<String>)

}
要使用构造函数绑定,必须使用 or configuration 属性扫描启用该类。 您不能将构造函数绑定与由常规 Spring 机制创建的 bean(例如 bean、使用方法创建的 bean 或使用 bean 加载的 bean )一起使用@EnableConfigurationProperties@Component@Bean@Import)
要在本机映像中使用构造函数绑定,必须使用 . 如果您使用 Spring Boot 的 Gradle 插件,或者如果您使用 Maven 和 .-parametersspring-boot-starter-parent
不建议使用 with,因为它主要用作返回类型。 因此,它不太适合 configuration property injection。 为了与其他类型的属性保持一致,如果声明了一个属性并且它没有值,则将绑定一个空值,而不是空值。java.util.Optional@ConfigurationPropertiesOptionalnullOptional

2.8.3. 启用 @ConfigurationProperties 注解类型

Spring Boot 提供了绑定类型并将其注册为 bean 的基础设施。 您可以逐个类启用配置属性,也可以启用配置属性扫描,其工作方式与组件扫描类似。@ConfigurationPropertiesspring-doc.cn

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

Java
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(SomeProperties.class)
public class MyConfiguration {

}
Kotlin
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(SomeProperties::class)
class MyConfiguration
Java
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("some.properties")
public class SomeProperties {

}
Kotlin
import org.springframework.boot.context.properties.ConfigurationProperties

@ConfigurationProperties("some.properties")
class SomeProperties

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

Java
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;

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

}
Kotlin
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.context.properties.ConfigurationPropertiesScan

@SpringBootApplication
@ConfigurationPropertiesScan("com.example.app", "com.example.another")
class MyApplication

当使用配置属性 scanning 或通过 注册 bean 时,该 bean 具有约定的名称: ,其中 是注释中指定的环境键前缀,是 bean 的完全限定名称。 如果 Comments 未提供任何前缀,则仅使用 Bean 的完全限定名称。@ConfigurationProperties@EnableConfigurationProperties<prefix>-<fqn><prefix>@ConfigurationProperties<fqn>spring-doc.cn

假设它在包中,则上面示例的 bean 名称为 。com.example.appSomePropertiessome.properties-com.example.app.SomePropertiesspring-doc.cn

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

2.8.4. 使用 @ConfigurationProperties 注解类型

这种配置样式特别适用于外部 YAML 配置,如以下示例所示:SpringApplicationspring-doc.cn

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

要使用 bean,可以像注入任何其他 bean 一样注入它们,如以下示例所示:@ConfigurationPropertiesspring-doc.cn

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

    // ...

}
Kotlin
import org.springframework.stereotype.Service

@Service
class MyService(val properties: MyProperties) {

    fun openConnection() {
        val server = Server(properties.remoteAddress)
        server.start()
        // ...
    }

    // ...

}
使用还可以生成元数据文件,IDE 可以使用这些文件为您自己的键提供自动完成功能。 有关详细信息,请参阅附录@ConfigurationProperties

2.8.5. 第三方配置

除了用于注释类外,您还可以在公共方法上使用它。 当您希望将属性绑定到不受控制的第三方组件时,这样做可能特别有用。@ConfigurationProperties@Beanspring-doc.cn

要从属性中配置 Bean,请添加到其 Bean 注册中,如以下示例所示:Environment@ConfigurationPropertiesspring-doc.cn

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

}
Kotlin
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class ThirdPartyConfiguration {

    @Bean
    @ConfigurationProperties(prefix = "another")
    fun anotherComponent(): AnotherComponent = AnotherComponent()

}

使用前缀定义的任何 JavaBean 属性都以类似于前面示例的方式映射到该 Bean 上。anotherAnotherComponentSomePropertiesspring-doc.cn

2.8.6. 松散绑定

Spring Boot 使用一些宽松的规则将属性绑定到 bean,因此属性名称和 bean 属性名称之间不需要完全匹配。 这有用的常见示例包括以短划线分隔的环境属性(例如,binds to )和大写的环境属性(例如,binds to )。Environment@ConfigurationPropertiesEnvironmentcontext-pathcontextPathPORTportspring-doc.cn

例如,请考虑以下类:@ConfigurationPropertiesspring-doc.cn

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

}
Kotlin
import org.springframework.boot.context.properties.ConfigurationProperties

@ConfigurationProperties(prefix = "my.main-project.person")
class MyPersonProperties {

    var firstName: String? = null

}

使用上述代码,可以使用以下属性名称:spring-doc.cn

表 3.松绑
财产 注意

my.main-project.person.first-namespring-doc.cn

Kebab 大小写,建议在 和 YAML 文件中使用。.propertiesspring-doc.cn

my.main-project.person.firstNamespring-doc.cn

标准 Camel 大小写语法。spring-doc.cn

my.main-project.person.first_namespring-doc.cn

下划线表示法,这是在 和 YAML 文件中使用的替代格式。.propertiesspring-doc.cn

MY_MAINPROJECT_PERSON_FIRSTNAMEspring-doc.cn

大写格式,使用系统环境变量时推荐使用。spring-doc.cn

注释的值必须采用 kebab 大小写(小写并用 分隔,例如 )。prefix-my.main-project.person
表 4.每个属性源的松散绑定规则
Property Source 简单 列表

属性文件spring-doc.cn

驼峰式大小写、kebab 大小写或下划线表示法spring-doc.cn

使用 或 逗号分隔值的标准列表语法[ ]spring-doc.cn

YAML 文件spring-doc.cn

驼峰式大小写、kebab 大小写或下划线表示法spring-doc.cn

标准 YAML 列表语法或逗号分隔值spring-doc.cn

环境变量spring-doc.cn

大写格式,下划线作为分隔符(请参阅从环境变量绑定)。spring-doc.cn

用下划线括起来的数值(请参见从环境变量绑定)spring-doc.cn

系统属性spring-doc.cn

驼峰式大小写、kebab 大小写或下划线表示法spring-doc.cn

使用 或 逗号分隔值的标准列表语法[ ]spring-doc.cn

我们建议尽可能以小写 kebab 格式存储属性,例如 .my.person.first-name=Rod
绑定映射

绑定到属性时,可能需要使用特殊的方括号表示法,以便保留原始值。 如果键未被 括起来,则任何非字母数字字符或已删除的字符。Mapkey[]-.spring-doc.cn

例如,考虑将以下属性绑定到 :Map<String,String>spring-doc.cn

性能
my.map.[/key1]=value1
my.map.[/key2]=value2
my.map./key3=value3
Yaml
my:
  map:
    "[/key1]": "value1"
    "[/key2]": "value2"
    "/key3": "value3"
对于 YAML 文件,括号需要用引号括起来,以便正确解析键。

上述属性将绑定到 with 和 作为映射中的键。 斜杠已被删除,因为它没有被方括号括起来。Map/key1/key2key3key3spring-doc.cn

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

从环境变量绑定

大多数操作系统对可用于环境变量的名称施加了严格的规则。 例如,Linux shell 变量只能包含字母 ( to 或 to )、数字 ( to ) 或下划线字符 ()。 按照惯例,Unix shell 变量的名称也将采用 UPPERCASE。azAZ09_spring-doc.cn

Spring Boot 的宽松绑定规则尽可能地设计为与这些命名限制兼容。spring-doc.cn

要将 canonical-form 中的属性名称转换为环境变量名称,您可以遵循以下规则:spring-doc.cn

例如,configuration 属性将是名为 .spring.main.log-startup-infoSPRING_MAIN_LOGSTARTUPINFOspring-doc.cn

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

例如,configuration 属性将使用名为 .my.service[0].otherMY_SERVICE_0_OTHERspring-doc.cn

缓存

松散绑定使用缓存来提高性能。默认情况下,此缓存仅应用于不可变属性源。 要自定义此行为,例如为可变属性源启用缓存,请使用 .ConfigurationPropertyCachingspring-doc.cn

2.8.7. 合并复杂类型

在多个位置配置列表时,覆盖的工作原理是替换整个列表。spring-doc.cn

例如,假设对象具有 and 属性,默认情况下为 。 以下示例公开了 :MyPojonamedescriptionnullMyPojoMyPropertiesspring-doc.cn

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

}
Kotlin
import org.springframework.boot.context.properties.ConfigurationProperties

@ConfigurationProperties("my")
class MyProperties {

    val list: List<MyPojo> = ArrayList()

}

请考虑以下配置:spring-doc.cn

性能
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
Yaml
my:
  list:
  - name: "my name"
    description: "my description"
---
spring:
  config:
    activate:
      on-profile: "dev"
my:
  list:
  - name: "my another name"

如果配置文件未处于活动状态,则包含一个条目,如前所述。 但是,如果启用了配置文件,则 只包含一个条目(名称 和 描述 )。 此配置不会向列表添加第二个实例,也不会合并项目。devMyProperties.listMyPojodevlistmy another namenullMyPojospring-doc.cn

在多个配置文件中指定 a 时,将使用优先级最高的配置文件(并且仅使用该配置文件)。 请考虑以下示例:Listspring-doc.cn

性能
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
Yaml
my:
  list:
  - name: "my name"
    description: "my description"
  - name: "another name"
    description: "another description"
---
spring:
  config:
    activate:
      on-profile: "dev"
my:
  list:
  - name: "my another name"

在前面的示例中,如果配置文件处于活动状态,则包含一个条目(名称为 ,描述为 )。 对于 YAML,逗号分隔列表和 YAML 列表都可用于完全覆盖列表的内容。devMyProperties.listMyPojomy another namenullspring-doc.cn

对于属性,您可以绑定从多个源提取的属性值。 但是,对于多个来源中的同一属性,将使用优先级最高的属性。 以下示例公开了 from :MapMap<String, MyPojo>MyPropertiesspring-doc.cn

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

}
Kotlin
import org.springframework.boot.context.properties.ConfigurationProperties

@ConfigurationProperties("my")
class MyProperties {

    val map: Map<String, MyPojo> = LinkedHashMap()

}

请考虑以下配置:spring-doc.cn

性能
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
Yaml
my:
  map:
    key1:
      name: "my name 1"
      description: "my description 1"
---
spring:
  config:
    activate:
      on-profile: "dev"
my:
  map:
    key1:
      name: "dev name 1"
    key2:
      name: "dev name 2"
      description: "dev description 2"

如果配置文件未处于活动状态,则包含一个具有键的条目(名称为 ,描述为 )。 但是,如果启用配置文件,则包含两个条目,键(名称为,描述为 )和(名称为 ,描述为 )。devMyProperties.mapkey1my name 1my description 1devmapkey1dev name 1my description 1key2dev name 2dev description 2spring-doc.cn

上述合并规则适用于所有属性源中的属性,而不仅仅是文件。

2.8.8. 属性转换

Spring Boot 在绑定到 bean 时尝试将外部应用程序属性强制为正确的类型。 如果需要自定义类型转换,则可以提供 bean(带有名为 )或自定义属性编辑器(通过 bean)或自定义(bean定义注释为 )。@ConfigurationPropertiesConversionServiceconversionServiceCustomEditorConfigurerConverters@ConfigurationPropertiesBindingspring-doc.cn

由于此 bean 是在应用程序生命周期的早期请求,因此请确保限制您正在使用的依赖项。 通常,您需要的任何依赖项在创建时可能未完全初始化。 如果配置键强制不需要,并且仅依赖于符合 的自定义转换器,则可能需要重命名自定义。ConversionServiceConversionService@ConfigurationPropertiesBinding
转换持续时间

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

请考虑以下示例:spring-doc.cn

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

}
Kotlin
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.convert.DurationUnit
import java.time.Duration
import java.time.temporal.ChronoUnit

@ConfigurationProperties("my")
class MyProperties {

    @DurationUnit(ChronoUnit.SECONDS)
    var sessionTimeout = Duration.ofSeconds(30)

    var readTimeout = Duration.ofMillis(1000)

}

要指定 30 秒的会话超时,则 和 都是等效的。 可以采用以下任何形式指定 500 毫秒的读取超时:和 。30PT30S30s500PT0.5S500msspring-doc.cn

您还可以使用任何受支持的单位。 这些是:spring-doc.cn

默认单位为毫秒,可以使用上面的示例所示进行覆盖。@DurationUnitspring-doc.cn

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

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

}
Kotlin
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.bind.DefaultValue
import org.springframework.boot.convert.DurationUnit
import java.time.Duration
import java.time.temporal.ChronoUnit

@ConfigurationProperties("my")
class MyProperties(@param:DurationUnit(ChronoUnit.SECONDS) @param:DefaultValue("30s") val sessionTimeout: Duration,
        @param:DefaultValue("1000ms") val readTimeout: Duration)
如果要升级属性,请确保定义单位(如果不是毫秒,则使用 )。 这样做提供了透明的升级路径,同时支持更丰富的格式。Long@DurationUnit
转换期间

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

简单格式支持以下单位:spring-doc.cn

该类型从未实际存储周数,它是一个表示“7 天”的快捷方式。java.time.Period
转换数据大小

Spring Framework 具有一个值类型,它以字节为单位表示大小。 如果公开属性,则应用程序属性中的以下格式可用:DataSizeDataSizespring-doc.cn

  • 常规表示形式(除非指定了 a,否则使用 bytes 作为默认单位)long@DataSizeUnitspring-doc.cn

  • 值和单位耦合的可读性更强的格式(表示 10 MB)10MBspring-doc.cn

请考虑以下示例:spring-doc.cn

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

}
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")
class MyProperties {

    @DataSizeUnit(DataUnit.MEGABYTES)
    var bufferSize = DataSize.ofMegabytes(2)

    var sizeThreshold = DataSize.ofBytes(512)

}

指定缓冲区大小为 10 MB,并且等效。 可以将 256 字节的大小阈值指定为 或 。1010MB256256Bspring-doc.cn

您还可以使用任何受支持的单位。 这些是:spring-doc.cn

默认单位是 bytes,可以使用上面的示例所示进行覆盖。@DataSizeUnitspring-doc.cn

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

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

}
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")
class MyProperties(@param:DataSizeUnit(DataUnit.MEGABYTES) @param:DefaultValue("2MB") val bufferSize: DataSize,
        @param:DefaultValue("512B") val sizeThreshold: DataSize)
如果要升级属性,请确保定义单位(如果不是 bytes,则使用 )。 这样做提供了透明的升级路径,同时支持更丰富的格式。Long@DataSizeUnit

2.8.9. @ConfigurationProperties 验证

Spring Boot 尝试在使用 Spring 的 Comments 对类进行 Comments 时对其进行验证。 您可以直接在 configuration 类上使用 JSR-303 约束 Comments。 为此,请确保 Classpath 上具有兼容的 JSR-303 实现,然后将约束 Comments 添加到字段中,如以下示例所示:@ConfigurationProperties@Validatedjakarta.validationspring-doc.cn

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

}
Kotlin
import jakarta.validation.constraints.NotNull
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.validation.annotation.Validated
import java.net.InetAddress

@ConfigurationProperties("my.service")
@Validated
class MyProperties {

    var remoteAddress: @NotNull InetAddress? = null

}
您还可以通过使用 注释创建配置属性的方法来触发验证。@Bean@Validated

要确保始终为嵌套属性触发验证,即使未找到任何属性,也必须为关联的字段添加注释。 以下示例基于前面的示例:@ValidMyPropertiesspring-doc.cn

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

    }

}
Kotlin
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
import java.net.InetAddress

@ConfigurationProperties("my.service")
@Validated
class MyProperties {

    var remoteAddress: @NotNull InetAddress? = null

    @Valid
    val security = Security()

    class Security {

        @NotEmpty
        var username: String? = null

    }

}

您还可以通过创建名为 . 该方法应声明 。 配置属性验证器是在应用程序生命周期的早期创建的,将方法声明为 static 可以创建 bean,而不必实例化该类。 这样做可以避免早期实例化可能导致的任何问题。ValidatorconfigurationPropertiesValidator@Beanstatic@Bean@Configurationspring-doc.cn

该模块包括一个公开所有 bean 的端点。 将 Web 浏览器指向或使用等效的 JMX 终端节点。 有关详细信息,请参阅“生产就绪功能”部分。spring-boot-actuator@ConfigurationProperties/actuator/configprops

2.8.10. @ConfigurationProperties 与 @Value

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

特征 @ConfigurationProperties @Value

松散的装订spring-doc.cn

是的spring-doc.cn

受限(请参阅下面的注释)spring-doc.cn

元数据支持spring-doc.cn

是的spring-doc.cn

spring-doc.cn

SpEL评估spring-doc.cn

spring-doc.cn

是的spring-doc.cn

如果您确实要使用 ,我们建议您使用属性名称的规范形式(kebab 大小写仅使用小写字母)来引用属性名称。 这将允许 Spring Boot 使用与 relaxed binding 时相同的 logic 。@Value@ConfigurationPropertiesspring-doc.cn

例如,将从文件以及系统环境中选取 和 form。 如果你改用,则不会被考虑。@Value("${demo.item-price}")demo.item-pricedemo.itemPriceapplication.propertiesDEMO_ITEMPRICE@Value("${demo.itemPrice}")demo.item-priceDEMO_ITEMPRICEspring-doc.cn

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

SpEL在解析 Application 属性文件和填充环境时,不会处理这些文件中的表达式。 但是,可以在 中编写表达式。 如果应用程序属性文件中的属性值是表达式,则在通过 .SpEL@ValueSpEL@Valuespring-doc.cn

3. 配置文件

Spring 配置文件提供了一种分离应用程序配置的各个部分并使其仅在某些环境中可用的方法。 Any ,或者可以标记为 to limit 何时加载,如以下示例所示:@Component@Configuration@ConfigurationProperties@Profilespring-doc.cn

Java
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

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

    // ...

}
Kotlin
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Profile

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

    // ...

}
如果 bean 是通过而不是自动扫描注册的,则需要在具有 Comments 的类上指定 Comments。 在 被扫描的情况下,可以在类本身上指定。@ConfigurationProperties@EnableConfigurationProperties@Profile@Configuration@EnableConfigurationProperties@ConfigurationProperties@Profile@ConfigurationProperties

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

性能
spring.profiles.active=dev,hsqldb
Yaml
spring:
  profiles:
    active: "dev,hsqldb"

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

如果没有配置文件处于活动状态,则启用默认配置文件。 默认配置文件的名称是 ,并且可以使用 property 进行调整,如以下示例所示:defaultspring.profiles.defaultEnvironmentspring-doc.cn

性能
spring.profiles.default=none
Yaml
spring:
  profiles:
    default: "none"

spring.profiles.active,并且只能在非配置文件特定文档中使用。 这意味着它们不能包含在特定于配置文件的文件或 由 激活的文档中spring.profiles.defaultspring.config.activate.on-profilespring-doc.cn

例如,第二个文档配置无效:spring-doc.cn

性能
# this document is valid
spring.profiles.active=prod
#---
# this document is invalid
spring.config.activate.on-profile=prod
spring.profiles.active=metrics
Yaml
# this document is valid
spring:
  profiles:
    active: "prod"
---
# this document is invalid
spring:
  config:
    activate:
      on-profile: "prod"
  profiles:
    active: "metrics"

3.1. 添加活动配置文件

该属性遵循与其他属性相同的排序规则:最高者优先。 这意味着您可以在 中指定活动配置文件,然后使用命令行开关替换它们。spring.profiles.activePropertySourceapplication.propertiesspring-doc.cn

有时,将属性添加到活动配置文件中而不是替换它们非常有用。 该属性可用于在由该属性激活的用户档案之上添加活动用户档案。 入口点还具有用于设置其他配置文件的 Java API。 参见SpringApplication中的方法。spring.profiles.includespring.profiles.activeSpringApplicationsetAdditionalProfiles()spring-doc.cn

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

性能
spring.profiles.include[0]=common
spring.profiles.include[1]=local
Yaml
spring:
  profiles:
    include:
      - "common"
      - "local"
与 类似,只能在非配置文件特定文档中使用。 这意味着它不能包含在由 激活的特定于配置文件的文件文档中spring.profiles.activespring.profiles.includespring.config.activate.on-profile

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

3.2. 配置文件组

有时,您在应用程序中定义和使用的配置文件过于精细,使用起来变得很麻烦。 例如,您可能拥有用于独立启用数据库和消息传递功能的 and 配置文件。proddbprodmqspring-doc.cn

为了帮助解决这个问题, Spring Boot 允许你定义配置文件组。 配置文件组允许您为相关的配置文件组定义逻辑名称。spring-doc.cn

例如,我们可以创建一个由 our 和 profiles 组成的组。productionproddbprodmqspring-doc.cn

性能
spring.profiles.group.production[0]=proddb
spring.profiles.group.production[1]=prodmq
Yaml
spring:
  profiles:
    group:
      production:
      - "proddb"
      - "prodmq"

现在,我们的应用程序可以开始使用一次性激活 和 用户档案。--spring.profiles.active=productionproductionproddbprodmqspring-doc.cn

3.3. 以编程方式设置 Profile

您可以通过在应用程序运行之前调用 来以编程方式设置活动配置文件。 也可以使用 Spring 的界面激活配置文件。SpringApplication.setAdditionalProfiles(…​)ConfigurableEnvironmentspring-doc.cn

3.4. 特定于 Profile 的配置文件

通过 (或 ) 引用的文件的特定于配置文件的变体被视为文件并加载。 有关详细信息,请参阅“分析特定文件”。application.propertiesapplication.yaml@ConfigurationPropertiesspring-doc.cn

4. 日志记录

Spring Boot 使用 Commons Logging 进行所有内部日志记录,但将底层日志实现保持开放状态。 为 Java Util LoggingLog4j2Logback 提供了默认配置。 在每种情况下,记录器都预先配置为使用控制台输出,并提供可选的文件输出。spring-doc.cn

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

有很多可用于 Java 的日志记录框架。 如果上面的列表看起来令人困惑,请不要担心。 通常,您不需要更改日志记录依赖项,并且 Spring Boot 默认值可以正常工作。
将应用程序部署到 servlet 容器或应用程序服务器时,使用 Java Util Logging API 执行的日志记录不会路由到应用程序的日志中。 这可以防止容器或已部署到容器的其他应用程序执行的日志记录显示在应用程序的日志中。

4.1. 日志格式

Spring Boot 的默认日志输出类似于以下示例:spring-doc.cn

2024-05-23T07:27:53.211Z  INFO 109693 --- [           main] o.s.b.d.f.logexample.MyApplication       : Starting MyApplication using Java 17.0.11 with PID 109693 (/opt/apps/myapp.jar started by myuser in /opt/apps/)
2024-05-23T07:27:53.215Z  INFO 109693 --- [           main] o.s.b.d.f.logexample.MyApplication       : No active profile set, falling back to 1 default profile: "default"
2024-05-23T07:27:55.862Z  INFO 109693 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2024-05-23T07:27:55.901Z  INFO 109693 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2024-05-23T07:27:55.901Z  INFO 109693 --- [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.24]
2024-05-23T07:27:56.124Z  INFO 109693 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2024-05-23T07:27:56.129Z  INFO 109693 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2702 ms
2024-05-23T07:27:56.976Z  INFO 109693 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2024-05-23T07:27:56.996Z  INFO 109693 --- [           main] o.s.b.d.f.logexample.MyApplication       : Started MyApplication in 5.062 seconds (process running for 6.255)

输出以下项目:spring-doc.cn

Logback 没有级别。 它映射到 。FATALERROR

4.2. 控制台输出

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

$ java -jar myapp.jar --debug
您还可以在 .debug=trueapplication.properties

启用调试模式后,将配置一系列核心 Logger(嵌入式容器、Hibernate 和 Spring Boot)以输出更多信息。 启用 debug 模式不会将应用程序配置为记录所有具有 level 的消息。DEBUGspring-doc.cn

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

4.2.1. 颜色编码输出

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

颜色编码是使用转换词配置的。 在最简单的形式中,转换器根据对数级别对输出进行着色,如以下示例所示:%clrspring-doc.cn

%clr(%5p)

下表描述了对数级别到颜色的映射:spring-doc.cn

水平 颜色

FATALspring-doc.cn

spring-doc.cn

ERRORspring-doc.cn

spring-doc.cn

WARNspring-doc.cn

黄色spring-doc.cn

INFOspring-doc.cn

绿spring-doc.cn

DEBUGspring-doc.cn

绿spring-doc.cn

TRACEspring-doc.cn

绿spring-doc.cn

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

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

支持以下颜色和样式:spring-doc.cn

4.3. 文件输出

默认情况下, Spring Boot 仅记录到控制台,不写入日志文件。 如果除了控制台输出之外,还想写入日志文件,则需要设置 or 属性(例如,在您的 中)。logging.file.namelogging.file.pathapplication.propertiesspring-doc.cn

下表显示了如何结合使用这些属性:logging.*spring-doc.cn

表 5.日志记录属性
logging.file.name logging.file.path 描述

(无)spring-doc.cn

(无)spring-doc.cn

仅限控制台日志记录。spring-doc.cn

特定文件spring-doc.cn

(无)spring-doc.cn

my.logspring-doc.cn

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

(无)spring-doc.cn

特定目录spring-doc.cn

/var/logspring-doc.cn

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

日志文件在达到 10 MB 时轮换,与控制台输出一样,默认情况下会记录 -level、-level 和 -level 消息。ERRORWARNINFOspring-doc.cn

日志记录属性独立于实际的日志记录基础结构。 因此,特定的配置键(例如 Logback)不受 Spring Boot 的管理。logback.configurationFile

4.4. 文件旋转

如果您使用的是 Logback,则可以使用 or 文件微调日志轮换设置。 对于所有其他日志记录系统,您需要直接自己配置轮换设置(例如,如果您使用 Log4j2,则可以添加 or 文件)。application.propertiesapplication.yamllog4j2.xmllog4j2-spring.xmlspring-doc.cn

支持以下轮换策略属性:spring-doc.cn

名字 描述

logging.logback.rollingpolicy.file-name-patternspring-doc.cn

用于创建日志存档的文件名模式。spring-doc.cn

logging.logback.rollingpolicy.clean-history-on-startspring-doc.cn

是否应在应用程序启动时进行日志存档清理。spring-doc.cn

logging.logback.rollingpolicy.max-file-sizespring-doc.cn

日志文件存档前的最大大小。spring-doc.cn

logging.logback.rollingpolicy.total-size-capspring-doc.cn

日志存档在被删除之前可以占用的最大大小。spring-doc.cn

logging.logback.rollingpolicy.max-historyspring-doc.cn

要保留的存档日志文件的最大数量(默认为 7)。spring-doc.cn

4.5. 日志级别

所有受支持的日志记录系统都可以在 Spring 中设置 Logger 级别(例如,in ),方法是使用 where 是 TRACE、DEBUG、INFO、WARN、ERROR、FATAL 或 OFF 之一。 可以使用 来配置 Logger。Environmentapplication.propertieslogging.level.<logger-name>=<level>levelrootlogging.level.rootspring-doc.cn

以下示例显示了 中的潜在日志记录设置:application.propertiesspring-doc.cn

性能
logging.level.root=warn
logging.level.org.springframework.web=debug
logging.level.org.hibernate=error
Yaml
logging:
  level:
    root: "warn"
    org.springframework.web: "debug"
    org.hibernate: "error"

还可以使用环境变量设置日志记录级别。 例如,将设置为 .LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_WEB=DEBUGorg.springframework.webDEBUGspring-doc.cn

上述方法仅适用于包级日志记录。 由于松散绑定始终将环境变量转换为小写,因此无法以这种方式为单个类配置日志记录。 如果需要为类配置日志记录,可以使用 SPRING_APPLICATION_JSON 变量。

4.6. 日志组

能够将相关的 logger 分组在一起,以便可以同时配置它们通常很有用。 例如,您可能通常会更改所有与 Tomcat 相关的 Logger 的日志记录级别,但您无法轻松记住顶级包。spring-doc.cn

为了帮助解决这个问题, Spring Boot 允许您在 Spring 中定义 logging groups 。 例如,以下是如何通过将 “tomcat” 组添加到您的 :Environmentapplication.propertiesspring-doc.cn

性能
logging.group.tomcat=org.apache.catalina,org.apache.coyote,org.apache.tomcat
Yaml
logging:
  group:
    tomcat: "org.apache.catalina,org.apache.coyote,org.apache.tomcat"

定义后,您可以使用一行更改组中所有 logger 的级别:spring-doc.cn

性能
logging.level.tomcat=trace
Yaml
logging:
  level:
    tomcat: "trace"

Spring Boot 包括以下预定义的日志记录组,这些组可以开箱即用:spring-doc.cn

名字 Logging

Webspring-doc.cn

org.springframework.core.codec, , , ,org.springframework.httporg.springframework.weborg.springframework.boot.actuate.endpoint.weborg.springframework.boot.web.servlet.ServletContextInitializerBeansspring-doc.cn

SQLspring-doc.cn

org.springframework.jdbc.core, ,org.hibernate.SQLorg.jooq.tools.LoggerListenerspring-doc.cn

4.7. 使用日志关闭钩子

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

性能
logging.register-shutdown-hook=false
Yaml
logging:
  register-shutdown-hook: false

4.8. 自定义日志配置

可以通过在 Classpath 中包含适当的库来激活各种日志记录系统,并且可以通过在 Classpath 的根目录中或以下 Spring 属性指定的位置提供合适的配置文件来进一步自定义:。Environmentlogging.configspring-doc.cn

你可以通过使用system属性来强制 Spring Boot 使用特定的日志记录系统。 该值应为 implementation 的完全限定类名。 您还可以使用值 .org.springframework.boot.logging.LoggingSystemLoggingSystemnonespring-doc.cn

由于日志记录是在创建之前初始化的,因此无法从 Spring 文件中控制日志记录。 更改日志记录系统或完全禁用它的唯一方法是通过 System properties。ApplicationContext@PropertySources@Configuration

根据您的日志记录系统,将加载以下文件:spring-doc.cn

测井系统 定制

Logback (日志返回)spring-doc.cn

logback-spring.xmllogback-spring.groovylogback.xmllogback.groovyspring-doc.cn

日志 4j2spring-doc.cn

log4j2-spring.xmllog4j2.xmlspring-doc.cn

JDK(Java Util 日志记录)spring-doc.cn

logging.propertiesspring-doc.cn

如果可能,我们建议您对日志记录配置使用 variants(例如,而不是 )。 如果使用标准配置位置, Spring 则无法完全控制日志初始化。-springlogback-spring.xmllogback.xml
Java Util Logging 存在已知的类加载问题,这些问题会导致在从“可执行 jar”运行时出现问题。 我们建议您尽可能避免从“可执行 jar”运行时使用它。

为了帮助进行自定义,将一些其他属性从 Spring 属性传输到 System 属性。 这允许记录系统配置来使用属性。例如,在环境变量中设置或设置为环境变量将导致设置 System 属性。 下表描述了传输的属性:Environmentlogging.file.nameapplication.propertiesLOGGING_FILE_NAMELOG_FILEspring-doc.cn

Spring 环境 系统属性 评论

logging.exception-conversion-wordspring-doc.cn

LOG_EXCEPTION_CONVERSION_WORDspring-doc.cn

记录异常时使用的转换字。spring-doc.cn

logging.file.namespring-doc.cn

LOG_FILEspring-doc.cn

如果已定义,则在默认日志配置中使用它。spring-doc.cn

logging.file.pathspring-doc.cn

LOG_PATHspring-doc.cn

如果已定义,则在默认日志配置中使用它。spring-doc.cn

logging.pattern.consolespring-doc.cn

CONSOLE_LOG_PATTERNspring-doc.cn

要在控制台上使用的日志模式 (stdout)。spring-doc.cn

logging.pattern.dateformatspring-doc.cn

LOG_DATEFORMAT_PATTERNspring-doc.cn

日志日期格式的 Appender 模式。spring-doc.cn

logging.charset.consolespring-doc.cn

CONSOLE_LOG_CHARSETspring-doc.cn

用于控制台日志记录的字符集。spring-doc.cn

logging.threshold.consolespring-doc.cn

CONSOLE_LOG_THRESHOLDspring-doc.cn

用于控制台日志记录的日志级别阈值。spring-doc.cn

logging.pattern.filespring-doc.cn

FILE_LOG_PATTERNspring-doc.cn

要在文件中使用的日志模式(如果已启用)。LOG_FILEspring-doc.cn

logging.charset.filespring-doc.cn

FILE_LOG_CHARSETspring-doc.cn

用于文件日志记录的字符集(如果已启用)。LOG_FILEspring-doc.cn

logging.threshold.filespring-doc.cn

FILE_LOG_THRESHOLDspring-doc.cn

用于文件日志记录的日志级别阈值。spring-doc.cn

logging.pattern.levelspring-doc.cn

LOG_LEVEL_PATTERNspring-doc.cn

渲染日志级别时使用的格式 (default )。%5pspring-doc.cn

PIDspring-doc.cn

PIDspring-doc.cn

当前进程 ID(如果可能且尚未定义为 OS 环境变量,则已发现)。spring-doc.cn

如果使用 Logback,则还会传输以下属性:spring-doc.cn

Spring 环境 系统属性 评论

logging.logback.rollingpolicy.file-name-patternspring-doc.cn

LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERNspring-doc.cn

滚动日志文件名的模式(默认)。${LOG_FILE}.%d{yyyy-MM-dd}.%i.gzspring-doc.cn

logging.logback.rollingpolicy.clean-history-on-startspring-doc.cn

LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_STARTspring-doc.cn

是否在启动时清理存档日志文件。spring-doc.cn

logging.logback.rollingpolicy.max-file-sizespring-doc.cn

LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZEspring-doc.cn

最大日志文件大小。spring-doc.cn

logging.logback.rollingpolicy.total-size-capspring-doc.cn

LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAPspring-doc.cn

要保留的日志备份的总大小。spring-doc.cn

logging.logback.rollingpolicy.max-historyspring-doc.cn

LOGBACK_ROLLINGPOLICY_MAX_HISTORYspring-doc.cn

要保留的存档日志文件的最大数量。spring-doc.cn

所有受支持的日志记录系统都可以在解析其配置文件时查阅 System properties。 有关示例,请参阅中的默认配置:spring-boot.jarspring-doc.cn

如果要在日志记录属性中使用占位符,则应使用 Spring Boot 的语法,而不是底层框架的语法。 值得注意的是,如果使用 Logback,则应用作属性名称与其默认值之间的分隔符,而不是使用 。::-spring-doc.cn

您可以通过仅覆盖(或使用 Logback)将 MDC 和其他临时内容添加到日志行中。 例如,如果使用 ,则默认日志格式包含 “user” 的 MDC 条目(如果存在),如以下示例所示。LOG_LEVEL_PATTERNlogging.pattern.levellogging.pattern.level=user:%X{user} %5pspring-doc.cn

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

4.9. Logback 扩展

Spring Boot 包含许多 Logback 扩展,可以帮助进行高级配置。 您可以在配置文件中使用这些扩展。logback-spring.xmlspring-doc.cn

由于标准配置文件加载得太早,因此不能在其中使用扩展。 您需要使用或定义属性。logback.xmllogback-spring.xmllogging.config
这些扩展不能与 Logback 的配置扫描一起使用。 如果尝试这样做,则对配置文件进行更改会导致记录类似于以下内容之一的错误:
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 的配置

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

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

该标签允许您公开 Spring 中的属性,以便在 Logback 中使用。 如果要在 Logback 配置中访问文件中的值,则这样做可能很有用。 该标签的工作方式与 Logback 的标准标签类似。 但是,您不是指定直接 ,而是指定属性的 (来自 )。 如果需要将属性存储在范围以外的其他位置,则可以使用该属性。 如果需要回退值(如果未在 中设置属性),则可以使用该属性。 以下示例显示了如何公开要在 Logback 中使用的属性:<springProperty>Environmentapplication.properties<property>valuesourceEnvironmentlocalscopeEnvironmentdefaultValuespring-doc.cn

<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>
必须在 kebab 大小写中指定 (例如 )。 但是,可以使用宽松规则将属性添加到 中。sourcemy.property-nameEnvironment

4.10. Log4j2 扩展

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

由于标准配置文件加载得太早,因此不能在其中使用扩展。 您需要使用或定义属性。log4j2.xmllog4j2-spring.xmllogging.config
这些扩展取代了 Log4J 提供的 Spring Boot 支持。 您应该确保不要在构建中包含该模块。org.apache.logging.log4j:log4j-spring-boot

4.10.1. 特定于 Profile 的配置

该标记允许您根据活动的 Spring 配置文件选择性地包含或排除配置部分。 元素中的任何位置都支持 Profile 部分。 使用 属性 指定接受配置的配置文件。 标记可以包含配置文件名称(例如 )或配置文件表达式。 配置文件表达式允许表示更复杂的配置文件逻辑,例如 . 有关更多详细信息,请查看 Spring Framework 参考指南。 以下清单显示了三个示例配置文件:<SpringProfile><Configuration>name<SpringProfile>stagingproduction & (eu-central | eu-west)spring-doc.cn

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

如果要在 Log4j2 配置中引用 Spring 中的属性,可以使用带前缀的查找。 如果要在 Log4j2 配置中访问文件中的值,则这样做可能很有用。Environmentspring:application.propertiesspring-doc.cn

以下示例显示如何设置从 Spring 读取的名为 Log4j2 的属性:applicationNamespring.application.nameEnvironmentspring-doc.cn

<Properties>
    <Property name="applicationName">${spring:spring.application.name}</Property>
</Properties>
查找键应以 kebab 大小写指定(例如 )。my.property-name

4.10.3. Log4j2 系统属性

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

Log4j2 初始化后加载的所有系统属性都可以从 Spring 获取。 例如,您可以添加到文件中以在 Windows 上使用 Jansi。Environmentlog4j2.skipJansi=falseapplication.propertiesConsoleAppenderspring-doc.cn

仅当系统属性和 OS 环境变量不包含正在加载的值时,才会考虑 Spring。Environment
在早期 Log4j2 初始化期间加载的系统属性无法引用 Spring 。 例如,在 Spring Environment 可用之前,使用了 Log4j2 用于允许选择默认 Log4j2 实现的属性。Environment

5. 国际化

Spring Boot 支持本地化消息,以便您的应用程序可以满足不同语言偏好的用户。 默认情况下, Spring Boot 在 Classpath 的根目录中查找是否存在资源包。messagesspring-doc.cn

当已配置资源包的默认属性文件可用时(默认情况下),自动配置将适用。 如果您的资源包仅包含特定于语言的属性文件,则需要添加默认值。 如果未找到与任何已配置基本名称匹配的属性文件,则不会有 auto-configured 。messages.propertiesMessageSource

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

性能
spring.messages.basename=messages,config.i18n.messages
spring.messages.fallback-to-system-locale=false
Yaml
spring:
  messages:
    basename: "messages,config.i18n.messages"
    fallback-to-system-locale: false
spring.messages.basename支持逗号分隔的位置列表,可以是 package 限定符或从 Classpath 根解析的资源。

有关更多支持的选项,请参见 MessageSourcePropertiesspring-doc.cn

6. 面向方面的编程

Spring Boot 为面向方面的编程 (AOP) 提供自动配置。 您可以在 Spring Framework 参考文档中了解有关 AOP with Spring 的更多信息。spring-doc.cn

默认情况下,Spring Boot 的自动配置将 Spring AOP 配置为使用 CGLib 代理。 要改用 JDK 代理,请设置为 .configprop:spring.aop.proxy-target-classfalsespring-doc.cn

如果 AspectJ 在 Classpath 上,则 Spring Boot 的自动配置将自动启用 AspectJ 自动代理,因此不是必需的。@EnableAspectJAutoProxyspring-doc.cn

7. JSON

Spring Boot 提供与三个 JSON 映射库的集成:spring-doc.cn

Jackson 是首选和默认库。spring-doc.cn

7.1. Jackson

提供了 Jackson 的自动配置,并且 Jackson 是 的一部分。 当 Jackson 位于 Classpath 上时,将自动配置 bean。 提供了几个配置属性,用于自定义 ObjectMapper 的配置spring-boot-starter-jsonObjectMapperspring-doc.cn

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

如果您使用 Jackson 序列化和反序列化 JSON 数据,则可能需要编写自己的 and 类。 自定义序列化器通常通过模块向 Jackson 注册,但 Spring Boot 提供了一个替代 Comments,可以更轻松地直接注册 Spring Beans。JsonSerializerJsonDeserializer@JsonComponentspring-doc.cn

您可以直接在 或 implementations 上使用注释。 您还可以在包含序列化器/反序列化器作为内部类的类上使用它,如以下示例所示:@JsonComponentJsonSerializerJsonDeserializerKeyDeserializerspring-doc.cn

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

    }

}
Kotlin
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.core.JsonProcessingException
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
import java.io.IOException

@JsonComponent
class MyJsonComponent {

    class Serializer : JsonSerializer<MyObject>() {
        @Throws(IOException::class)
        override fun serialize(value: MyObject, jgen: JsonGenerator, serializers: SerializerProvider) {
            jgen.writeStartObject()
            jgen.writeStringField("name", value.name)
            jgen.writeNumberField("age", value.age)
            jgen.writeEndObject()
        }
    }

    class Deserializer : JsonDeserializer<MyObject>() {
        @Throws(IOException::class, JsonProcessingException::class)
        override fun deserialize(jsonParser: JsonParser, ctxt: DeserializationContext): MyObject {
            val codec = jsonParser.codec
            val tree = codec.readTree<JsonNode>(jsonParser)
            val name = tree["name"].textValue()
            val age = tree["age"].intValue()
            return MyObject(name, age)
        }
    }

}

中的所有 bean 都会自动注册到 Jackson。 因为 是元注释的,所以通常的组件扫描规则适用。@JsonComponentApplicationContext@JsonComponent@Componentspring-doc.cn

Spring Boot 还提供了JsonObjectSerializerJsonObjectDeserializer基类,它们在序列化对象时为标准 Jackson 版本提供了有用的替代方案。 有关详细信息,请参阅 Javadoc 中的 JsonObjectSerializerJsonObjectDeserializerspring-doc.cn

上面的示例可以重写为使用 /,如下所示:JsonObjectSerializerJsonObjectDeserializerspring-doc.cn

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

    }

}
Kotlin
`object`

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
import java.io.IOException

@JsonComponent
class MyJsonComponent {

    class Serializer : JsonObjectSerializer<MyObject>() {
        @Throws(IOException::class)
        override fun serializeObject(value: MyObject, jgen: JsonGenerator, provider: SerializerProvider) {
            jgen.writeStringField("name", value.name)
            jgen.writeNumberField("age", value.age)
        }
    }

    class Deserializer : JsonObjectDeserializer<MyObject>() {
        @Throws(IOException::class)
        override fun deserializeObject(jsonParser: JsonParser, context: DeserializationContext,
                codec: ObjectCodec, tree: JsonNode): MyObject {
            val name = nullSafeValue(tree["name"], String::class.java)
            val age = nullSafeValue(tree["age"], Int::class.java)
            return MyObject(name, age)
        }
    }

}

7.1.2. 混入

Jackson 支持 mixins,可用于将其他注释混合到目标类上已声明的注释中。 Spring Boot 的 Jackson 自动配置将扫描应用程序的包中带有 Comments 的类,并将其注册到自动配置的 . 注册由 Spring Boot 的 .@JsonMixinObjectMapperJsonMixinModulespring-doc.cn

7.2. Gson

提供了 Gson 的自动配置。 当 Gson 位于 Classpath 上时,将自动配置 bean。 提供了多个配置属性用于自定义配置。 为了获得更多控制,可以使用一个或多个 bean。Gsonspring.gson.*GsonBuilderCustomizerspring-doc.cn

7.3. JSON-B

提供了 JSON-B 的自动配置。 当 JSON-B API 和实现在 Classpath 上时,将自动配置一个 bean。 首选的 JSON-B 实现是 Eclipse Yasson,它为其提供了依赖项管理。Jsonbspring-doc.cn

8. 任务执行和调度

在上下文中没有 bean 的情况下, Spring Boot 会自动配置一个合理的默认值,这些默认值可以自动与异步任务执行()和 Spring MVC 异步请求处理相关联。ExecutorThreadPoolTaskExecutor@EnableAsyncspring-doc.cn

如果您在上下文中定义了自定义,则常规任务执行(即)将透明地使用它,但不会配置 Spring MVC 支持,因为它需要一个实现(名为 )。 根据您的目标排列方式,您可以将 your 更改为 a 或同时定义 a 和 an 包装您的自定义 .Executor@EnableAsyncAsyncTaskExecutorapplicationTaskExecutorExecutorThreadPoolTaskExecutorThreadPoolTaskExecutorAsyncConfigurerExecutorspring-doc.cn

自动配置允许您轻松创建实例,这些实例可以重现自动配置默认执行的操作。TaskExecutorBuilderspring-doc.cn

线程池使用 8 个核心线程,这些线程可以根据负载进行扩展和收缩。 可以使用命名空间对这些默认设置进行微调,如以下示例所示:spring.task.executionspring-doc.cn

性能
spring.task.execution.pool.max-size=16
spring.task.execution.pool.queue-capacity=100
spring.task.execution.pool.keep-alive=10s
Yaml
spring:
  task:
    execution:
      pool:
        max-size: 16
        queue-capacity: 100
        keep-alive: "10s"

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

如果需要将 A 与计划任务执行相关联(例如使用),也可以自动配置 A。 默认情况下,线程池使用一个线程,并且可以使用命名空间对其设置进行微调,如以下示例所示:ThreadPoolTaskScheduler@EnableSchedulingspring.task.schedulingspring-doc.cn

性能
spring.task.scheduling.thread-name-prefix=scheduling-
spring.task.scheduling.pool.size=2
Yaml
spring:
  task:
    scheduling:
      thread-name-prefix: "scheduling-"
      pool:
        size: 2

如果需要创建自定义执行程序或调度程序,则 Bean 和 Bean 在上下文中都可用。TaskExecutorBuilderTaskSchedulerBuilderspring-doc.cn

9. 测试

Spring Boot 提供了许多 Utilities 和 Comments,以帮助测试您的应用程序。 测试支持由两个模块提供:包含核心项,并支持测试的自动配置。spring-boot-testspring-boot-test-autoconfigurespring-doc.cn

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

如果您有使用 JUnit 4 的测试,则可以使用 JUnit 5 的 vintage 引擎来运行它们。 要使用 vintage 引擎,请添加对 的依赖项,如以下示例所示:junit-vintage-enginespring-doc.cn

<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:hamcrestspring-boot-starter-testspring-doc.cn

9.1. 测试范围依赖项

“Starter” (在 中) 包含以下提供的库:spring-boot-starter-testtestscopespring-doc.cn

我们通常会发现这些公共库在编写测试时很有用。 如果这些库不符合您的需求,您可以添加自己的其他测试依赖项。spring-doc.cn

9.2. 测试 Spring 应用程序

依赖项注入的主要优点之一是它应该使您的代码更易于进行单元测试。 您可以使用 operator 实例化对象,甚至无需涉及 Spring。 您还可以使用 mock 对象而不是真正的依赖项。newspring-doc.cn

通常,您需要超越 unit testing 并开始集成测试(使用 Spring)。 能够在不需要部署应用程序或不需要连接到其他基础设施的情况下执行集成测试非常有用。ApplicationContextspring-doc.cn

Spring Framework 包括一个用于此类集成测试的专用测试模块。 您可以直接向 “Starter” 声明依赖项,也可以使用 “Starter” 以传递方式拉取它。org.springframework:spring-testspring-boot-starter-testspring-doc.cn

如果您以前没有使用过该模块,则应首先阅读 Spring Framework 参考文档的相关部分spring-testspring-doc.cn

9.3. 测试 Spring Boot 应用程序

Spring Boot 应用程序是 Spring ,因此除了通常使用普通 Spring 上下文所做的操作之外,无需执行任何特别操作来测试它。ApplicationContextspring-doc.cn

默认情况下,Spring Boot 的外部属性、日志记录和其他功能仅在用于创建它时才会安装在上下文中。SpringApplication

Spring Boot 提供了一个 Comments,当您需要 Spring Boot 功能时,可以将其用作标准 Comments 的替代方法。 Comments 的工作原理是通过 SpringApplication 创建测试中使用的ApplicationContext。 除了许多其他注释之外,还提供了用于测试应用程序的更具体切片的注释@SpringBootTestspring-test@ContextConfiguration@SpringBootTestspring-doc.cn

如果您使用的是 JUnit 4,请不要忘记也添加到您的测试中,否则注释将被忽略。 如果您使用的是 JUnit 5,则无需添加等效的 as,并且其他注释已经使用它进行了注释。@RunWith(SpringRunner.class)@ExtendWith(SpringExtension.class)@SpringBootTest@…​Test

默认情况下,不会启动服务器。 您可以使用 的 属性 of 进一步优化测试的运行方式:@SpringBootTestwebEnvironment@SpringBootTestspring-doc.cn

  • MOCK(默认) :加载 Web 并提供模拟 Web 环境。 使用此注释时,嵌入式服务器不会启动。 如果 Web 环境在 Classpath 上不可用,则此模式透明地回退到创建常规的 non-web 。 它可以与 @AutoConfigureMockMvc@AutoConfigureWebTestClient 结合使用,以便对 Web 应用程序进行基于模拟的测试。ApplicationContextApplicationContextspring-doc.cn

  • RANDOM_PORT:加载 并提供真实的 Web 环境。 嵌入式服务器启动并侦听随机端口。WebServerApplicationContextspring-doc.cn

  • DEFINED_PORT:加载 并提供真实的 Web 环境。 嵌入式服务器启动并侦听定义的端口(来自 )或默认端口 。WebServerApplicationContextapplication.properties8080spring-doc.cn

  • NONE:使用 但不提供任何 Web 环境(模拟或其他)加载。ApplicationContextSpringApplicationspring-doc.cn

如果您的测试是 ,则默认情况下,它会在每个测试方法结束时回滚事务。 但是,由于将这种安排与 OR 一起使用会隐式提供真实的 servlet 环境,因此 HTTP 客户端和服务器在单独的线程中运行,因此在单独的事务中运行。 在这种情况下,在服务器上启动的任何事务都不会回滚。@TransactionalRANDOM_PORTDEFINED_PORT
@SpringBootTest如果您的应用程序对 Management Server 使用不同的端口,则 with 还将在单独的随机端口上启动 Management Server。webEnvironment = WebEnvironment.RANDOM_PORT

9.3.1. 检测 Web 应用程序类型

如果 Spring MVC 可用,则配置基于常规 MVC 的应用程序上下文。 如果您只有 Spring WebFlux,我们将检测到该情况并配置基于 WebFlux 的应用程序上下文。spring-doc.cn

如果两者都存在,则 Spring MVC 优先。 如果要在此场景中测试反应式 Web 应用程序,则必须设置以下属性:spring.main.web-application-typespring-doc.cn

Java
import org.springframework.boot.test.context.SpringBootTest;

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

    // ...

}
Kotlin
import org.springframework.boot.test.context.SpringBootTest

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

    // ...

}

9.3.2. 检测测试配置

如果您熟悉 Spring Test Framework,则可能习惯于使用来指定要加载的 Spring。 或者,您可能经常在测试中使用嵌套类。@ContextConfiguration(classes=…​)@Configuration@Configurationspring-doc.cn

在测试 Spring Boot 应用程序时,这通常不是必需的。 Spring Boot 的 Comments 会在您未明确定义主配置时自动搜索主配置。@*Testspring-doc.cn

搜索算法从包含测试的包开始工作,直到找到带有 或 注释的类。 只要你以合理的方式构建你的代码,你的主要配置通常会被找到。@SpringBootApplication@SpringBootConfigurationspring-doc.cn

如果使用 test annotation 来测试应用程序的更具体部分,则应避免在 main 方法的 application 类上添加特定于特定区域的配置设置。spring-doc.cn

的底层组件扫描配置定义了用于确保切片按预期工作的排除过滤器。 如果您在 -annotated 类上使用 explicit 指令,请注意这些过滤器将被禁用。 如果您正在使用切片,则应再次定义它们。@SpringBootApplication@ComponentScan@SpringBootApplicationspring-doc.cn

如果要自定义主配置,可以使用嵌套类。 与嵌套类不同,嵌套类将用于代替应用程序的主配置,而嵌套类则除了应用程序的主配置外,还使用嵌套类。@TestConfiguration@Configuration@TestConfigurationspring-doc.cn

Spring 的测试框架在测试之间缓存应用程序上下文。 因此,只要您的测试共享相同的配置(无论它是如何发现的),加载上下文的潜在耗时过程只会发生一次。

9.3.3. 使用测试配置 main 方法

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

例如,以下是典型 Spring Boot 应用程序的非常常见的 Code Pattern:spring-doc.cn

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

}
Kotlin
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.docs.using.structuringyourcode.locatingthemainclass.MyApplication
import org.springframework.boot.runApplication

@SpringBootApplication
class MyApplication

fun main(args: Array<String>) {
    runApplication<MyApplication>(*args)
}

在上面的示例中,该方法除了委托 . 但是,可以使用更复杂的方法在调用 .mainSpringApplication.runmainSpringApplication.runspring-doc.cn

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

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

}
Kotlin
import org.springframework.boot.Banner
import org.springframework.boot.runApplication
import org.springframework.boot.autoconfigure.SpringBootApplication

@SpringBootApplication
class MyApplication

fun main(args: Array<String>) {
    runApplication<MyApplication>(*args) {
        setBannerMode(Banner.Mode.OFF)
        setAdditionalProfiles("myprofile")
    }
}

由于方法中的自定义可能会影响结果,因此您可能还希望使用该方法在测试中创建 used。 默认情况下,不会调用您的方法,而是直接使用类本身来创建mainApplicationContextmainApplicationContext@SpringBootTestmainApplicationContextspring-doc.cn

如果要更改此行为,可以将 的属性更改为 或 。 设置为 时,如果找不到方法,则测试将失败。 设置为 时,如果可用,则使用方法,否则将使用标准加载机制。useMainMethod@SpringBootTestUseMainMethod.ALWAYSUseMainMethod.WHEN_AVAILABLEALWAYSmainWHEN_AVAILABLEmainspring-doc.cn

例如,以下测试将调用 of 的方法以创建 . 如果 main 方法设置了其他配置文件,则这些配置文件将在启动时处于活动状态。mainMyApplicationApplicationContextApplicationContextspring-doc.cn

Java
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)
class MyApplicationTests {

    @Test
    void exampleTest() {
        // ...
    }

}
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)
class MyApplicationTests {

    @Test
    fun exampleTest() {
        // ...
    }

}

9.3.4. 排除测试配置

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

正如我们之前看到的,可以用于测试的内部类来自定义主要配置。 也可以在顶级类上使用。这样做表示不应通过扫描来选取该类。 然后,您可以在需要的地方显式导入该类,如以下示例所示:@TestConfiguration@TestConfigurationspring-doc.cn

Java
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() {
        // ...
    }

}
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
    fun exampleTest() {
        // ...
    }

}
如果直接使用 (即,不是通过 ),则需要向 它注册 。 有关详细信息,请参阅 Javadoc@ComponentScan@SpringBootApplicationTypeExcludeFilter
导入的 an 比 inner-class 更早处理,而 imported 将在通过组件扫描找到任何配置之前处理。 一般来说,这种 Sequences 的差异没有明显的影响,但是如果你依赖于 bean 覆盖,则需要注意这一点。@TestConfiguration@TestConfiguration@TestConfiguration

9.3.5. 使用应用程序参数

如果您的应用程序需要参数,则可以 使用 attribute 注入它们。@SpringBootTestargsspring-doc.cn

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

}
Kotlin
import org.assertj.core.api.Assertions.assertThat
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

@SpringBootTest(args = ["--app.test=one"])
class MyApplicationArgumentTests {

    @Test
    fun applicationArgumentsPopulated(@Autowired args: ApplicationArguments) {
        assertThat(args.optionNames).containsOnly("app.test")
        assertThat(args.getOptionValues("app.test")).containsOnly("one")
    }

}

9.3.6. 使用 Mock 环境进行测试

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

借助 Spring MVC,我们可以使用 MockMvc 或 查询我们的 Web 端点,如以下示例所示:WebTestClientspring-doc.cn

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

}
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.reactive.server.expectBody
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
import org.springframework.test.web.servlet.result.MockMvcResultMatchers

@SpringBootTest
@AutoConfigureMockMvc
class MyMockMvcTests {

    @Test
    fun testWithMockMvc(@Autowired mvc: MockMvc) {
        mvc.perform(MockMvcRequestBuilders.get("/")).andExpect(MockMvcResultMatchers.status().isOk)
            .andExpect(MockMvcResultMatchers.content().string("Hello World"))
    }

    // If Spring WebFlux is on the classpath, you can drive MVC tests with a WebTestClient

    @Test
    fun testWithWebTestClient(@Autowired webClient: WebTestClient) {
        webClient
            .get().uri("/")
            .exchange()
            .expectStatus().isOk
            .expectBody<String>().isEqualTo("Hello World")
    }

}
如果您只想关注 Web 图层,而不开始 完整 ,请考虑改用 @WebMvcTestApplicationContext

使用 Spring WebFlux 端点,你可以使用WebTestClient,如以下示例所示:spring-doc.cn

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

}
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
import org.springframework.test.web.reactive.server.expectBody

@SpringBootTest
@AutoConfigureWebTestClient
class MyMockWebTestClientTests {

    @Test
    fun exampleTest(@Autowired webClient: WebTestClient) {
        webClient
            .get().uri("/")
            .exchange()
            .expectStatus().isOk
            .expectBody<String>().isEqualTo("Hello World")
    }

}

在模拟环境中进行测试通常比使用完整的 servlet 容器运行更快。 但是,由于模拟发生在 Spring MVC 层,因此无法直接使用 MockMvc 测试依赖于较低级别 servlet 容器行为的代码。spring-doc.cn

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

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

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

该 annotation 可用于将实际使用的端口注入到测试中。 为方便起见,需要对已启动的服务器进行 REST 调用的测试还可以使用 WebTestClient,该客户端解析到正在运行的服务器的相对链接,并附带用于验证响应的专用 API,如以下示例所示:@LocalServerPort@Autowirespring-doc.cn

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

}
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
import org.springframework.test.web.reactive.server.expectBody

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyRandomPortWebTestClientTests {

    @Test
    fun exampleTest(@Autowired webClient: WebTestClient) {
        webClient
            .get().uri("/")
            .exchange()
            .expectStatus().isOk
            .expectBody<String>().isEqualTo("Hello World")
    }

}
WebTestClient还可以与模拟环境一起使用,无需运行服务器,方法是使用 .@AutoConfigureWebTestClient

此设置需要在 classpath 上。 如果你不能或不打算添加 webflux,Spring Boot 还提供了一个工具:spring-webfluxTestRestTemplatespring-doc.cn

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

}
Kotlin
import org.assertj.core.api.Assertions.assertThat
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

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyRandomPortTestRestTemplateTests {

    @Test
    fun exampleTest(@Autowired restTemplate: TestRestTemplate) {
        val body = restTemplate.getForObject("/", String::class.java)
        assertThat(body).isEqualTo("Hello World")
    }

}

9.3.8. 自定义 WebTestClient

要自定义 Bean,请配置 Bean。 任何此类 bean 都使用用于创建 的 调用。WebTestClientWebTestClientBuilderCustomizerWebTestClient.BuilderWebTestClientspring-doc.cn

9.3.9. 使用 JMX

由于测试上下文框架会缓存上下文,因此默认情况下会禁用 JMX,以防止相同的组件在同一域上注册。 如果此类测试需要访问 ,则还要考虑将其标记为 dirty:MBeanServerspring-doc.cn

Java
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");
        // ...
    }

}
Kotlin
import javax.management.MBeanServer

import org.assertj.core.api.Assertions.assertThat
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

@SpringBootTest(properties = ["spring.jmx.enabled=true"])
@DirtiesContext
class MyJmxTests(@Autowired val mBeanServer: MBeanServer) {

    @Test
    fun exampleTest() {
        assertThat(mBeanServer.domains).contains("java.lang")
        // ...
    }

}

9.3.10. 使用度量

无论您的 Classpath 如何,在使用 时,不会自动配置计量注册表(内存中支持的除外)。@SpringBootTestspring-doc.cn

如果需要将指标导出到其他后端作为集成测试的一部分,请使用 .@AutoConfigureObservabilityspring-doc.cn

9.3.11. 使用跟踪

无论您的 Classpath 如何,在使用 时都不会自动配置跟踪。@SpringBootTestspring-doc.cn

如果需要将跟踪作为集成测试的一部分,请使用 .@AutoConfigureObservabilityspring-doc.cn

9.3.12. Mocking 和 Spying Bean

运行测试时,有时需要模拟应用程序上下文中的某些组件。 例如,您可能在某些远程服务上有一个在开发过程中不可用的门面。 当您想要模拟在真实环境中可能难以触发的故障时,模拟也很有用。spring-doc.cn

Spring Boot 包含一个注释,可用于为 . 您可以使用注释添加新的 bean 或替换单个现有的 bean 定义。 注解可以直接用于测试类、测试中的字段或类和字段。 当用于字段时,创建的 mock 的实例也会被注入。 Mock bean 在每个测试方法之后都会自动重置。@MockBeanApplicationContext@Configurationspring-doc.cn

如果您的测试使用 Spring Boot 的 test annotations(例如 ),则会自动启用此功能。 要将此功能与不同的 arrangement 一起使用,必须显式添加侦听器,如以下示例所示:@SpringBootTestspring-doc.cn

Java
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 {

    // ...

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

    // ...

}

以下示例将现有 bean 替换为 mock 实现:RemoteServicespring-doc.cn

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

}
Kotlin
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.mockito.BDDMockito.given
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.mock.mockito.MockBean

@SpringBootTest
class MyTests(@Autowired val reverser: Reverser, @MockBean val remoteService: RemoteService) {

    @Test
    fun exampleTest() {
        given(remoteService.value).willReturn("spring")
        val reverse = reverser.reverseValue // Calls injected RemoteService
        assertThat(reverse).isEqualTo("gnirps")
    }

}
@MockBean不能用于模拟在应用程序上下文刷新期间执行的 bean 的行为。 执行测试时,应用程序上下文刷新已完成,配置模拟行为为时已晚。 在这种情况下,我们建议使用一种方法来创建和配置 mock。@Bean

此外,您还可以使用 Mockito 包装任何现有 bean。 有关完整详细信息,请参阅 Javadoc@SpyBeanspyspring-doc.cn

虽然 Spring 的测试框架在测试之间缓存应用程序上下文,并为共享相同配置的测试重用上下文,但使用或影响缓存键,这很可能会增加上下文的数量。@MockBean@SpyBean
如果用于使用按名称引用参数的方法监视 bean,则必须使用 . 这可确保在监视 Bean 后,参数名称可用于缓存基础结构。@SpyBean@Cacheable-parameters
当您用于监视由 Spring 代理的 bean 时,在某些情况下可能需要删除 Spring 的代理,例如,当使用 or 设置期望时。 用于执行此操作。@SpyBeangivenwhenAopTestUtils.getTargetObject(yourProxiedSpy)

9.3.13. 自动配置的测试

Spring Boot 的自动配置系统适用于应用程序,但有时对于测试来说可能有点太多了。 通常,仅加载测试应用程序的 “slice” 所需的配置部分会有所帮助。 例如,你可能想要测试 Spring MVC 控制器是否正确映射 URL,并且你不想在这些测试中涉及数据库调用,或者你可能想要测试 JPA 实体,并且你对这些测试运行时的 Web 层不感兴趣。spring-doc.cn

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

每个 slice 将组件扫描限制为适当的组件,并加载一组非常受限的 auto-configuration classes。 如果需要排除其中一个,大多数 Comments 都会提供一个属性。 或者,您也可以使用 .@…​TestexcludeAutoConfiguration@ImportAutoConfiguration#exclude
不支持在一个测试中使用多个 Comments 来包含多个 “slice”。 如果您需要多个 “切片”,请选择其中一个注释并手动包含其他 “切片” 的注释。@…​Test@…​Test@AutoConfigure…​
也可以将 Comments 与标准注释一起使用。 如果您对 “切片” 应用程序不感兴趣,但想要一些自动配置的测试 bean,则可以使用此组合。@AutoConfigure…​@SpringBootTest

9.3.14. 自动配置的 JSON 测试

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

附录中提供了 启用的自动配置列表。@JsonTest

如果需要配置自动配置的元素,则可以使用 annotation.@AutoConfigureJsonTestersspring-doc.cn

Spring Boot 包括基于 AssertJ 的帮助程序,这些帮助程序与 JSONAssert 和 JsonPath 库一起使用,以检查 JSON 是否按预期显示。 、、 、 和 类可以分别用于 Jackson、 Gson、 Jsonb 和 Strings。 测试类上的任何帮助程序字段都可以在使用 . 以下示例显示了 Jackson 的 test 类:JacksonTesterGsonTesterJsonbTesterBasicJsonTester@Autowired@JsonTestspring-doc.cn

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

}
Kotlin
import org.assertj.core.api.Assertions.assertThat
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

@JsonTest
class MyJsonTests(@Autowired val json: JacksonTester<VehicleDetails>) {

    @Test
    fun serialize() {
        val details = VehicleDetails("Honda", "Civic")
        // Assert against a `.json` file in the same package as the test
        assertThat(json.write(details)).isEqualToJson("expected.json")
        // Or use JSON path based assertions
        assertThat(json.write(details)).hasJsonPathStringValue("@.make")
        assertThat(json.write(details)).extractingJsonPathStringValue("@.make").isEqualTo("Honda")
    }

    @Test
    fun deserialize() {
        val content = "{\"make\":\"Ford\",\"model\":\"Focus\"}"
        assertThat(json.parse(content)).isEqualTo(VehicleDetails("Ford", "Focus"))
        assertThat(json.parseObject(content).make).isEqualTo("Ford")
    }

}
JSON 帮助程序类也可以直接在标准单元测试中使用。 为此,如果不使用 ,请在您的方法中调用帮助程序的方法。initFields@Before@JsonTest

如果使用 Spring Boot 基于 AssertJ 的帮助程序在给定 JSON 路径上的数字值上断言,则可能无法使用,具体取决于类型。 相反,您可以使用 AssertJ 来断言该值与给定条件匹配。 例如,以下示例断言实际数字是接近偏移量 的 float 值。isEqualTosatisfies0.150.01spring-doc.cn

Java
@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)));
}
Kotlin
@Test
fun someTest() {
    val value = SomeObject(0.152f)
    assertThat(json.write(value)).extractingJsonPathNumberValue("@.test.numberValue")
        .satisfies(ThrowingConsumer { number ->
            assertThat(number.toFloat()).isCloseTo(0.15f, within(0.01f))
        })
}

9.3.15. 自动配置的 Spring MVC 测试

要测试 Spring MVC 控制器是否按预期工作,请使用 Comments。 自动配置 Spring MVC 基础结构,并将扫描的 bean 限制为 、 和 。 使用 Comments 时,不会扫描 Regular 和 bean。 可用于包含 bean。@WebMvcTest@WebMvcTest@Controller@ControllerAdvice@JsonComponentConverterGenericConverterFilterHandlerInterceptorWebMvcConfigurerWebMvcRegistrationsHandlerMethodArgumentResolver@Component@ConfigurationProperties@WebMvcTest@EnableConfigurationProperties@ConfigurationPropertiesspring-doc.cn

附录中提供了启用的自动配置设置的列表。@WebMvcTest
如果需要注册额外的组件,例如 Jackson ,则可以在测试中使用导入其他配置类。Module@Import

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

@WebMvcTest还自动配置 . Mock MVC 提供了一种强大的方法来快速测试 MVC 控制器,而无需启动完整的 HTTP 服务器。MockMvcspring-doc.cn

您还可以在非 - (例如 ) 中自动配置,方法是使用 . 以下示例使用 :MockMvc@WebMvcTest@SpringBootTest@AutoConfigureMockMvcMockMvc
Java
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"));
    }

}
Kotlin
import org.junit.jupiter.api.Test
import org.mockito.BDDMockito.given
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 org.springframework.test.web.servlet.request.MockMvcRequestBuilders
import org.springframework.test.web.servlet.result.MockMvcResultMatchers

@WebMvcTest(UserVehicleController::class)
class MyControllerTests(@Autowired val mvc: MockMvc) {

    @MockBean
    lateinit var userVehicleService: UserVehicleService

    @Test
    fun testExample() {
        given(userVehicleService.getVehicleDetails("sboot"))
            .willReturn(VehicleDetails("Honda", "Civic"))
        mvc.perform(MockMvcRequestBuilders.get("/sboot/vehicle").accept(MediaType.TEXT_PLAIN))
            .andExpect(MockMvcResultMatchers.status().isOk)
            .andExpect(MockMvcResultMatchers.content().string("Honda Civic"))
    }

}
如果需要配置自动配置的元素(例如,何时应应用 servlet 过滤器),则可以在 Comments 中使用属性。@AutoConfigureMockMvc

如果使用 HtmlUnit 和 Selenium,则自动配置还会提供 HtmlUnit bean 和/或 Selenium bean。 下面的示例使用 HtmlUnit:WebClientWebDriverspring-doc.cn

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

}
Kotlin
import com.gargoylesoftware.htmlunit.WebClient
import com.gargoylesoftware.htmlunit.html.HtmlPage
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.mockito.BDDMockito.given
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.boot.test.mock.mockito.MockBean

@WebMvcTest(UserVehicleController::class)
class MyHtmlUnitTests(@Autowired val webClient: WebClient) {

    @MockBean
    lateinit var userVehicleService: UserVehicleService

    @Test
    fun testExample() {
        given(userVehicleService.getVehicleDetails("sboot")).willReturn(VehicleDetails("Honda", "Civic"))
        val page = webClient.getPage<HtmlPage>("/sboot/vehicle.html")
        assertThat(page.body.textContent).isEqualTo("Honda Civic")
    }

}
默认情况下, Spring Boot 将 bean 放在一个特殊的“范围”中,以确保驱动程序在每次测试后退出并注入新实例。 如果您不希望此行为,可以添加到您的定义中。WebDriver@Scope("singleton")WebDriver@Bean
Spring Boot 创建的范围将替换任何用户定义的同名范围。 如果您定义自己的范围,您可能会发现它在使用 .webDriverwebDriver@WebMvcTest

如果您在 Classpath 上安装了 Spring Security,则还将扫描 bean。 您可以使用 Spring Security 的测试支持,而不是完全禁用此类测试的安全性。 有关如何使用 Spring Security 支持的更多详细信息,请参阅此 howto.html操作方法部分。@WebMvcTestWebSecurityConfigurerMockMvcspring-doc.cn

有时编写 Spring MVC 测试是不够的;Spring Boot 可以帮助您使用实际服务器运行完整的端到端测试

9.3.16. 自动配置的 Spring WebFlux 测试

要测试 Spring WebFlux 控制器是否按预期工作,你可以使用 Comments。 自动配置 Spring WebFlux 基础结构,并将扫描的 bean 限制为 、 和 。 使用 Comments 时,不会扫描 Regular 和 bean。 可用于包含 bean。@WebFluxTest@WebFluxTest@Controller@ControllerAdvice@JsonComponentConverterGenericConverterWebFilterWebFluxConfigurer@Component@ConfigurationProperties@WebFluxTest@EnableConfigurationProperties@ConfigurationPropertiesspring-doc.cn

附录中提供了 启用的自动配置列表。@WebFluxTest
如果需要注册额外的组件,例如 Jackson ,则可以使用 on your test 导入其他配置类。Module@Import

通常,仅限于单个控制器,并与 annotation 结合使用,为所需的协作者提供 mock 实现。@WebFluxTest@MockBeanspring-doc.cn

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

您还可以在非 - (例如 ) 中自动配置,方法是使用 . 以下示例显示了一个同时使用 和 a 的类:WebTestClient@WebFluxTest@SpringBootTest@AutoConfigureWebTestClient@WebFluxTestWebTestClient
Java
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");
    }

}
Kotlin
import org.junit.jupiter.api.Test
import org.mockito.BDDMockito.given
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 org.springframework.test.web.reactive.server.expectBody

@WebFluxTest(UserVehicleController::class)
class MyControllerTests(@Autowired val webClient: WebTestClient) {

    @MockBean
    lateinit var userVehicleService: UserVehicleService

    @Test
    fun testExample() {
        given(userVehicleService.getVehicleDetails("sboot"))
            .willReturn(VehicleDetails("Honda", "Civic"))
        webClient.get().uri("/sboot/vehicle").accept(MediaType.TEXT_PLAIN).exchange()
            .expectStatus().isOk
            .expectBody<String>().isEqualTo("Honda Civic")
    }

}
此设置仅受 WebFlux 应用程序支持,因为在模拟的 Web 应用程序中使用目前仅适用于 WebFlux。WebTestClient
@WebFluxTest无法检测通过 Functional Web 框架注册的路由。 要在上下文中测试 bean,请考虑使用 或 using 导入您自己。RouterFunctionRouterFunction@Import@SpringBootTest
@WebFluxTest无法检测注册为 类型 的自定义安全配置 。 要将其包含在测试中,您需要导入使用 或 using 注册 bean 的配置。@BeanSecurityWebFilterChain@Import@SpringBootTest
有时编写 Spring WebFlux 测试是不够的;Spring Boot 可以帮助您使用实际服务器运行完整的端到端测试

9.3.17. 自动配置的 Spring GraphQL 测试

Spring GraphQL 提供了一个专用的测试支持模块;您需要将其添加到您的项目中:spring-doc.cn

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 将根据测试类型自动配置它们:GraphQlTesterspring-doc.cn

  • 在服务器端执行测试,没有客户端或传输ExecutionGraphQlServiceTesterspring-doc.cn

  • 使用连接到服务器的客户端执行测试,无论是否有实时服务器HttpGraphQlTesterspring-doc.cn

Spring Boot 可帮助您使用注释测试 Spring GraphQL 控制器。 自动配置 Spring GraphQL 基础设施,无需任何传输或服务器。 这会将扫描的 bean 限制为 、 和 。 使用 Comments 时,不会扫描 Regular 和 bean。 可用于包含 bean。@GraphQlTest@GraphQlTest@ControllerRuntimeWiringConfigurerJsonComponentConverterGenericConverterDataFetcherExceptionResolverInstrumentationGraphQlSourceBuilderCustomizer@Component@ConfigurationProperties@GraphQlTest@EnableConfigurationProperties@ConfigurationPropertiesspring-doc.cn

附录中提供了 启用的自动配置列表。@GraphQlTest

通常,仅限于一组控制器,并与 annotation 结合使用,为所需的协作者提供 mock 实现。@GraphQlTest@MockBeanspring-doc.cn

Java
import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.docs.web.graphql.runtimewiring.GreetingController;
import org.springframework.boot.test.autoconfigure.graphql.GraphQlTest;
import org.springframework.graphql.test.tester.GraphQlTester;

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

}
Kotlin
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.docs.web.graphql.runtimewiring.GreetingController
import org.springframework.boot.test.autoconfigure.graphql.GraphQlTest
import org.springframework.graphql.test.tester.GraphQlTester

@GraphQlTest(GreetingController::class)
internal class GreetingControllerTests {

    @Autowired
    lateinit var graphQlTester: GraphQlTester

    @Test
    fun shouldGreetWithSpecificName() {
        graphQlTester.document("{ greeting(name: \"Alice\") } ").execute().path("greeting").entity(String::class.java)
                .isEqualTo("Hello, Alice!")
    }

    @Test
    fun shouldGreetWithDefaultName() {
        graphQlTester.document("{ greeting } ").execute().path("greeting").entity(String::class.java)
                .isEqualTo("Hello, Spring!")
    }

}

@SpringBootTest测试是完整的集成测试,涉及整个应用程序。 当使用随机或定义的端口时,将配置一个实时服务器并自动提供一个 bean,以便您可以使用它来测试您的服务器。 配置 MOCK 环境后,您还可以通过使用以下 Comments 来请求测试类 Bean :HttpGraphQlTesterHttpGraphQlTester@AutoConfigureHttpGraphQlTesterspring-doc.cn

Java
import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.graphql.tester.AutoConfigureHttpGraphQlTester;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.graphql.test.tester.HttpGraphQlTester;

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

}
Kotlin
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.graphql.tester.AutoConfigureHttpGraphQlTester
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.graphql.test.tester.HttpGraphQlTester
import org.springframework.http.HttpHeaders
import org.springframework.test.web.reactive.server.WebTestClient

@AutoConfigureHttpGraphQlTester
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
class GraphQlIntegrationTests {

    @Test
    fun shouldGreetWithSpecificName(@Autowired graphQlTester: HttpGraphQlTester) {
        val authenticatedTester = graphQlTester.mutate()
            .webTestClient { client: WebTestClient.Builder ->
                client.defaultHeaders { headers: HttpHeaders ->
                    headers.setBasicAuth("admin", "ilovespring")
                }
            }.build()
        authenticatedTester.document("{ greeting(name: \"Alice\") } ").execute()
            .path("greeting").entity(String::class.java).isEqualTo("Hello, Alice!")
    }
}

9.3.18. 自动配置的 Data Cassandra 测试

可用于测试 Cassandra 应用程序。 默认情况下,它配置一个 ,扫描类,并配置 Spring Data Cassandra 存储库。 使用 Comments 时,不会扫描 Regular 和 bean。 可用于包含 bean。 (有关将 Cassandra 与 Spring Boot 结合使用的更多信息,请参阅“data.html”。@DataCassandraTestCassandraTemplate@Table@Component@ConfigurationProperties@DataCassandraTest@EnableConfigurationProperties@ConfigurationPropertiesspring-doc.cn

附录中提供了启用的自动配置设置的列表。@DataCassandraTest

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

Java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.cassandra.DataCassandraTest;

@DataCassandraTest
class MyDataCassandraTests {

    @Autowired
    private SomeRepository repository;

}
Kotlin
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.data.cassandra.DataCassandraTest

@DataCassandraTest
class MyDataCassandraTests(@Autowired val repository: SomeRepository)

9.3.19. 自动配置的数据 Couchbase 测试

您可以使用它来测试 Couchbase 应用程序。 默认情况下,它配置或扫描类,并配置 Spring Data Couchbase 存储库。 使用 Comments 时,不会扫描 Regular 和 bean。 可用于包含 bean。 (有关将 Couchbase 与 Spring Boot 结合使用的更多信息,请参阅本章前面的“data.html”。@DataCouchbaseTestCouchbaseTemplateReactiveCouchbaseTemplate@Document@Component@ConfigurationProperties@DataCouchbaseTest@EnableConfigurationProperties@ConfigurationPropertiesspring-doc.cn

附录中提供了启用的自动配置设置的列表。@DataCouchbaseTest

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

Java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.couchbase.DataCouchbaseTest;

@DataCouchbaseTest
class MyDataCouchbaseTests {

    @Autowired
    private SomeRepository repository;

    // ...

}
Kotlin
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.data.couchbase.DataCouchbaseTest

@DataCouchbaseTest
class MyDataCouchbaseTests(@Autowired val repository: SomeRepository) {

    // ...

}

9.3.20. 自动配置的数据 Elasticsearch 测试

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

附录中提供了启用的自动配置设置的列表。@DataElasticsearchTest

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

Java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.elasticsearch.DataElasticsearchTest;

@DataElasticsearchTest
class MyDataElasticsearchTests {

    @Autowired
    private SomeRepository repository;

    // ...

}
Kotlin
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.data.elasticsearch.DataElasticsearchTest

@DataElasticsearchTest
class MyDataElasticsearchTests(@Autowired val repository: SomeRepository) {

    // ...

}

9.3.21. 自动配置的数据 JPA 测试

您可以使用注释来测试 JPA 应用程序。 默认情况下,它会扫描类并配置 Spring Data JPA 存储库。 如果 Classpath 上有嵌入式数据库可用,则它也会配置一个。 默认情况下,通过将属性设置为 SQL 查询来记录 SQL 查询。 可以使用 annotation 的属性禁用此功能。@DataJpaTest@Entityspring.jpa.show-sqltrueshowSqlspring-doc.cn

使用 Comments 时,不会扫描 Regular 和 bean。 可用于包含 bean。@Component@ConfigurationProperties@DataJpaTest@EnableConfigurationProperties@ConfigurationPropertiesspring-doc.cn

附录中提供了启用的自动配置设置的列表。@DataJpaTest

默认情况下,数据 JPA 测试是事务性的,并在每次测试结束时回滚。 有关更多详细信息,请参阅 Spring Framework Reference Documentation 中的相关部分。 如果这不是您想要的,则可以禁用测试或整个类的事务 management,如下所示:spring-doc.cn

Java
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 {

    // ...

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

    // ...

}

数据 JPA 测试还可以注入 TestEntityManager Bean,它为专为测试设计的标准 JPA 提供了替代方案。EntityManagerspring-doc.cn

TestEntityManager也可以通过添加 . 执行此操作时,请确保您的测试在事务中运行,例如通过添加测试类或方法。@AutoConfigureTestEntityManager@Transactional

如果您需要,也可以使用 A。 以下示例显示了正在使用的注释:JdbcTemplate@DataJpaTestspring-doc.cn

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

}
Kotlin
import org.assertj.core.api.Assertions.assertThat
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

@DataJpaTest
class MyRepositoryTests(@Autowired val entityManager: TestEntityManager, @Autowired val repository: UserRepository) {

    @Test
    fun testExample() {
        entityManager.persist(User("sboot", "1234"))
        val user = repository.findByUsername("sboot")
        assertThat(user?.username).isEqualTo("sboot")
        assertThat(user?.employeeNumber).isEqualTo("1234")
    }

}

内存嵌入式数据库通常适用于测试,因为它们速度很快且不需要任何安装。 但是,如果您希望对实际数据库运行测试,则可以使用 Comments,如以下示例所示:@AutoConfigureTestDatabasespring-doc.cn

Java
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 {

    // ...

}
Kotlin
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest

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

    // ...

}

9.3.22. 自动配置的 JDBC 测试

@JdbcTest类似于,但适用于只需要 Spring Data JDBC 而不使用 Spring Data JDBC 的测试。 默认情况下,它会配置一个内存中嵌入式数据库和一个 . 使用 Comments 时,不会扫描 Regular 和 bean。 可用于包含 bean。@DataJpaTestDataSourceJdbcTemplate@Component@ConfigurationProperties@JdbcTest@EnableConfigurationProperties@ConfigurationPropertiesspring-doc.cn

附录中提供了 启用的自动配置列表。@JdbcTest

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

Java
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 {

}
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

如果您希望测试针对实际数据库运行,则可以像使用 Comments 一样使用 Comments。 (请参阅“自动配置的数据 JPA 测试”)@AutoConfigureTestDatabase@DataJpaTestspring-doc.cn

9.3.23. 自动配置的数据 JDBC 测试

@DataJdbcTest类似于,但适用于使用 Spring Data JDBC 存储库的测试。 默认情况下,它配置内存中嵌入式数据库、 和 Spring Data JDBC 存储库。 使用 Comments 时仅扫描子类,不扫描 regular 和 bean。 可用于包含 bean。@JdbcTestJdbcTemplateAbstractJdbcConfiguration@DataJdbcTest@Component@ConfigurationProperties@EnableConfigurationProperties@ConfigurationPropertiesspring-doc.cn

附录中提供了 启用的自动配置列表。@DataJdbcTest

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

如果您希望测试针对实际数据库运行,则可以像使用 Comments 一样使用 Comments。 (请参阅“自动配置的数据 JPA 测试”)@AutoConfigureTestDatabase@DataJpaTestspring-doc.cn

9.3.24. 自动配置的数据 R2DBC 测试

@DataR2dbcTest类似于,但适用于使用 Spring Data R2DBC 存储库的测试。 默认情况下,它配置内存中的嵌入式数据库、 和 Spring Data R2DBC 存储库。 使用 Comments 时,不会扫描 Regular 和 bean。 可用于包含 bean。@DataJdbcTestR2dbcEntityTemplate@Component@ConfigurationProperties@DataR2dbcTest@EnableConfigurationProperties@ConfigurationPropertiesspring-doc.cn

附录中提供了 启用的自动配置列表。@DataR2dbcTest

默认情况下,Data R2DBC 测试不是事务性的。spring-doc.cn

如果您希望测试针对实际数据库运行,则可以像使用 Comments 一样使用 Comments。 (请参阅“自动配置的数据 JPA 测试”)@AutoConfigureTestDatabase@DataJpaTestspring-doc.cn

9.3.25. 自动配置的 jOOQ 测试

您可以以与 jOOQ 相关的测试类似的方式使用。 由于 jOOQ 严重依赖与数据库架构相对应的基于 Java 的架构,因此使用 existing。 如果要将其替换为内存中数据库,可以使用 覆盖这些设置。 (有关在 Spring Boot 中使用 jOOQ 的更多信息,请参阅“data.html”。 使用 Comments 时,不会扫描 Regular 和 bean。 可用于包含 bean。@JooqTest@JdbcTestDataSource@AutoConfigureTestDatabase@Component@ConfigurationProperties@JooqTest@EnableConfigurationProperties@ConfigurationPropertiesspring-doc.cn

附录中提供了 启用的自动配置列表。@JooqTest

@JooqTest配置 . 以下示例显示了正在使用的注释:DSLContext@JooqTestspring-doc.cn

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

    // ...

}
Kotlin
import org.jooq.DSLContext
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.jooq.JooqTest

@JooqTest
class MyJooqTests(@Autowired val dslContext: DSLContext) {

    // ...

}

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

9.3.26. 自动配置的数据 MongoDB 测试

可用于测试 MongoDB 应用程序。 默认情况下,它会配置一个 、 扫描类,并配置 Spring Data MongoDB 存储库。 使用 Comments 时,不会扫描 Regular 和 bean。 可用于包含 bean。 (有关将 MongoDB 与 Spring Boot 结合使用的更多信息,请参阅“data.html”。@DataMongoTestMongoTemplate@Document@Component@ConfigurationProperties@DataMongoTest@EnableConfigurationProperties@ConfigurationPropertiesspring-doc.cn

附录中提供了启用的自动配置设置的列表。@DataMongoTest

下面的类显示了正在使用的 Annotation:@DataMongoTestspring-doc.cn

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

    // ...

}
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 val mongoTemplate: MongoTemplate) {

    // ...

}

9.3.27. 自动配置的数据 Neo4j 测试

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

附录中提供了启用的自动配置设置的列表。@DataNeo4jTest

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

Java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest;

@DataNeo4jTest
class MyDataNeo4jTests {

    @Autowired
    private SomeRepository repository;

    // ...

}
Kotlin
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest

@DataNeo4jTest
class MyDataNeo4jTests(@Autowired val repository: SomeRepository) {

    // ...

}

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

Java
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 {

}
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
反应式访问不支持事务性测试。 如果使用此样式,则必须如上所述配置测试。@DataNeo4jTest

9.3.28. 自动配置的数据 Redis 测试

您可以使用它来测试 Redis 应用程序。 默认情况下,它会扫描类并配置 Spring Data Redis 存储库。 使用 Comments 时,不会扫描 Regular 和 bean。 可用于包含 bean。 (有关将 Redis 与 Spring Boot 结合使用的更多信息,请参阅“data.html”。@DataRedisTest@RedisHash@Component@ConfigurationProperties@DataRedisTest@EnableConfigurationProperties@ConfigurationPropertiesspring-doc.cn

附录中提供了启用的自动配置设置的列表。@DataRedisTest

以下示例显示了正在使用的注释:@DataRedisTestspring-doc.cn

Java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest;

@DataRedisTest
class MyDataRedisTests {

    @Autowired
    private SomeRepository repository;

    // ...

}
Kotlin
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest

@DataRedisTest
class MyDataRedisTests(@Autowired val repository: SomeRepository) {

    // ...

}

9.3.29. 自动配置的数据 LDAP 测试

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

附录中提供了启用的自动配置设置的列表。@DataLdapTest

以下示例显示了正在使用的注释:@DataLdapTestspring-doc.cn

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

    // ...

}
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 val ldapTemplate: LdapTemplate) {

    // ...

}

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

Java
import org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration;
import org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest;

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

    // ...

}
Kotlin
import org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration
import org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest

@DataLdapTest(excludeAutoConfiguration = [EmbeddedLdapAutoConfiguration::class])
class MyDataLdapTests {

    // ...

}

9.3.30. 自动配置的 REST 客户端

您可以使用注释来测试 REST 客户端。 默认情况下,它会自动配置 Jackson、GSON 和 Jsonb 支持,配置 ,并添加对 . 使用 Comments 时,不会扫描 Regular 和 bean。 可用于包含 bean。@RestClientTestRestTemplateBuilderMockRestServiceServer@Component@ConfigurationProperties@RestClientTest@EnableConfigurationProperties@ConfigurationPropertiesspring-doc.cn

附录中提供了启用的自动配置设置的列表。@RestClientTest

应使用 的 or 属性指定要测试的特定 bean,如以下示例所示:valuecomponents@RestClientTestspring-doc.cn

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

}
Kotlin
import org.assertj.core.api.Assertions.assertThat
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 org.springframework.test.web.client.match.MockRestRequestMatchers
import org.springframework.test.web.client.response.MockRestResponseCreators

@RestClientTest(RemoteVehicleDetailsService::class)
class MyRestClientTests(
    @Autowired val service: RemoteVehicleDetailsService,
    @Autowired val server: MockRestServiceServer) {

    @Test
    fun getVehicleDetailsWhenResultIsSuccessShouldReturnDetails() {
        server.expect(MockRestRequestMatchers.requestTo("/greet/details"))
            .andRespond(MockRestResponseCreators.withSuccess("hello", MediaType.TEXT_PLAIN))
        val greeting = service.callRestService()
        assertThat(greeting).isEqualTo("hello")
    }

}

9.3.31. 自动配置的 Spring REST Docs 测试

您可以使用注释在带有 Mock MVC、REST Assure 或 WebTestClient 的测试中使用 Spring REST Docs。 它消除了 Spring REST Docs 中对 JUnit 扩展的需求。@AutoConfigureRestDocsspring-doc.cn

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

使用模拟 MVC 自动配置的 Spring REST 文档测试

@AutoConfigureRestDocs自定义 Bean 以在测试基于 servlet 的 Web 应用程序时使用 Spring REST Docs。 你可以通过使用它来注入它,并在测试中使用它,就像你通常使用 Mock MVC 和 Spring REST Docs 时一样,如以下示例所示:MockMvc@Autowiredspring-doc.cn

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

}
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.restdocs.mockmvc.MockMvcRestDocumentation
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
import org.springframework.test.web.servlet.result.MockMvcResultMatchers

@WebMvcTest(UserController::class)
@AutoConfigureRestDocs
class MyUserDocumentationTests(@Autowired val mvc: MockMvc) {

    @Test
    fun listUsers() {
        mvc.perform(MockMvcRequestBuilders.get("/users").accept(MediaType.TEXT_PLAIN))
            .andExpect(MockMvcResultMatchers.status().isOk)
            .andDo(MockMvcRestDocumentation.document("list-users"))
    }

}

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

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

}
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)
class MyRestDocsConfiguration : RestDocsMockMvcConfigurationCustomizer {

    override fun customize(configurer: MockMvcRestDocumentationConfigurer) {
        configurer.snippets().withTemplateFormat(TemplateFormats.markdown())
    }

}

如果你想利用 Spring REST Docs 对参数化输出目录的支持,你可以创建一个 bean。 使用此结果处理程序的 auto-configuration 调用,从而导致每个调用自动生成默认代码段。 以下示例显示了一个 being defined:RestDocumentationResultHandleralwaysDoMockMvcRestDocumentationResultHandlerspring-doc.cn

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

}
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)
class MyResultHandlerConfiguration {

    @Bean
    fun restDocumentation(): RestDocumentationResultHandler {
        return MockMvcRestDocumentation.document("{method-name}")
    }

}
使用 WebTestClient 自动配置的 Spring REST Docs 测试

@AutoConfigureRestDocs也可以在测试反应式 Web 应用程序时使用。 你可以通过使用 using 来注入它,并在测试中使用它,就像你通常使用 Spring REST Docs 时一样,如以下示例所示:WebTestClient@Autowired@WebFluxTestspring-doc.cn

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

}
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.restdocs.webtestclient.WebTestClientRestDocumentation
import org.springframework.test.web.reactive.server.WebTestClient

@WebFluxTest
@AutoConfigureRestDocs
class MyUsersDocumentationTests(@Autowired val webTestClient: WebTestClient) {

    @Test
    fun listUsers() {
        webTestClient
            .get().uri("/")
            .exchange()
            .expectStatus()
            .isOk
            .expectBody()
            .consumeWith(WebTestClientRestDocumentation.document("list-users"))
    }

}

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

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

}
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)
class MyRestDocsConfiguration : RestDocsWebTestClientConfigurationCustomizer {

    override fun customize(configurer: WebTestClientRestDocumentationConfigurer) {
        configurer.snippets().withEncoding("UTF-8")
    }

}

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

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

}
Kotlin
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.boot.test.web.reactive.server.WebTestClientBuilderCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation
import org.springframework.test.web.reactive.server.WebTestClient

@TestConfiguration(proxyBeanMethods = false)
class MyWebTestClientBuilderCustomizerConfiguration {

    @Bean
    fun restDocumentation(): WebTestClientBuilderCustomizer {
        return WebTestClientBuilderCustomizer { builder: WebTestClient.Builder ->
            builder.entityExchangeResultConsumer(
                WebTestClientRestDocumentation.document("{method-name}")
            )
        }
    }

}
使用 REST Assured 自动配置的 Spring REST Docs 测试

@AutoConfigureRestDocs使预配置为使用 Spring REST Docs 的 bean 可用于您的测试。 你可以通过使用它来注入它,并在测试中使用它,就像你通常使用 REST Assured 和 Spring REST Docs 时一样,如以下示例所示:RequestSpecification@Autowiredspring-doc.cn

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

}
Kotlin
import io.restassured.RestAssured
import io.restassured.specification.RequestSpecification
import org.hamcrest.Matchers
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 org.springframework.restdocs.restassured.RestAssuredRestDocumentation

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureRestDocs
class MyUserDocumentationTests {

    @Test
    fun listUsers(@Autowired documentationSpec: RequestSpecification?, @LocalServerPort port: Int) {
        RestAssured.given(documentationSpec)
            .filter(RestAssuredRestDocumentation.document("list-users"))
            .`when`()
            .port(port)["/"]
            .then().assertThat()
            .statusCode(Matchers.`is`(200))
    }

}

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

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

}
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)
class MyRestDocsConfiguration : RestDocsRestAssuredConfigurationCustomizer {

    override fun customize(configurer: RestAssuredRestDocumentationConfigurer) {
        configurer.snippets().withTemplateFormat(TemplateFormats.markdown())
    }

}

9.3.32. 自动配置的 Spring Web 服务测试

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

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

附录中提供了启用的自动配置设置的列表。@WebServiceClientTest

以下示例显示了正在使用的注释:@WebServiceClientTestspring-doc.cn

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

}
Kotlin
import org.assertj.core.api.Assertions.assertThat
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.ws.test.client.RequestMatchers
import org.springframework.ws.test.client.ResponseCreators
import org.springframework.xml.transform.StringSource

@WebServiceClientTest(SomeWebService::class)
class MyWebServiceClientTests(@Autowired val server: MockWebServiceServer, @Autowired val someWebService: SomeWebService) {

    @Test
    fun mockServerCall() {
        server
            .expect(RequestMatchers.payload(StringSource("<request/>")))
            .andRespond(ResponseCreators.withPayload(StringSource("<response><status>200</status></response>")))
        assertThat(this.someWebService.test()).extracting(Response::status).isEqualTo(200)
    }

}
自动配置的 Spring Web 服务服务器测试

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

附录中提供了启用的自动配置设置的列表。@WebServiceServerTest

以下示例显示了正在使用的注释:@WebServiceServerTestspring-doc.cn

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

}
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 val client: MockWebServiceClient) {

    @Test
    fun mockServerCall() {
        client
            .sendRequest(RequestCreators.withPayload(StringSource("<ExampleRequest/>")))
            .andExpect(ResponseMatchers.payload(StringSource("<ExampleResponse>42</ExampleResponse>")))
    }

}

9.3.33. 其他自动配置和切片

每个切片都提供一个或多个注释,即定义应作为切片的一部分包含的自动配置。 通过创建自定义注释或添加到测试,可以逐个测试添加其他自动配置,如以下示例所示:@AutoConfigure…​@AutoConfigure…​@ImportAutoConfigurationspring-doc.cn

Java
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 {

}
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
确保不要使用常规 Comments 来导入自动配置,因为它们是由 Spring Boot 以特定方式处理的。@Import

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

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

在此示例中,在每个带有 .com.example.IntegrationAutoConfiguration@JdbcTestspring-doc.cn

您可以在此文件中使用 Comments。#
切片或批注可以通过这种方式进行自定义,只要它使用 .@AutoConfigure…​@ImportAutoConfiguration

9.3.34. 用户配置和切片

如果您以合理的方式构建代码,则默认情况下会使用您的类作为测试的配置。@SpringBootApplicationspring-doc.cn

因此,重要的是不要在应用程序的主类中混淆特定于其特定功能区域的配置设置。spring-doc.cn

假设您使用的是 Spring Data MongoDB,您依赖于它的自动配置,并且您已启用审计。 您可以按如下方式定义 your :@SpringBootApplicationspring-doc.cn

Java
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.mongodb.config.EnableMongoAuditing;

@SpringBootApplication
@EnableMongoAuditing
public class MyApplication {

    // ...

}
Kotlin
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.data.mongodb.config.EnableMongoAuditing

@SpringBootApplication
@EnableMongoAuditing
class MyApplication {

    // ...

}

因为这个类是测试的源配置,所以任何切片测试实际上都会尝试启用 Mongo 审计,这绝对不是你想要的。 建议的方法是将特定于区域的配置移动到与应用程序位于同一级别的单独类,如以下示例所示:@Configurationspring-doc.cn

Java
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.EnableMongoAuditing;

@Configuration(proxyBeanMethods = false)
@EnableMongoAuditing
public class MyMongoConfiguration {

    // ...

}
Kotlin
import org.springframework.context.annotation.Configuration
import org.springframework.data.mongodb.config.EnableMongoAuditing

@Configuration(proxyBeanMethods = false)
@EnableMongoAuditing
class MyMongoConfiguration {

    // ...

}
根据应用程序的复杂程度,您可能有一个用于自定义的类,或者每个域区域有一个类。 后一种方法允许您在其中一个测试中启用它(如有必要),并使用 annotation。 有关何时可能需要为 slice 测试启用特定类的更多详细信息,请参阅此操作方法部分@Configuration@Import@Configuration

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

Java
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() {
            // ...
        };
    }

}
Kotlin
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer

@Configuration(proxyBeanMethods = false)
class MyWebConfiguration {

    @Bean
    fun testConfigurer(): WebMvcConfigurer {
        return object : WebMvcConfigurer {
            // ...
        }
    }

}

但是,下面的配置将导致测试切片加载自定义。WebMvcConfigurerspring-doc.cn

Java
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Component
public class MyWebMvcConfigurer implements WebMvcConfigurer {

    // ...

}
Kotlin
import org.springframework.stereotype.Component
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer

@Component
class MyWebMvcConfigurer : WebMvcConfigurer {

    // ...

}

另一个混淆的来源是 Classpath scanning。 假设您以合理的方式构建了代码,但需要扫描其他包。 您的应用程序可能类似于以下代码:spring-doc.cn

Java
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

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

    // ...

}
Kotlin
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.context.annotation.ComponentScan

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

    // ...

}

这样做可以有效地覆盖默认的组件 scan 指令,其副作用是扫描这两个包,而不管你选择了哪个 slice。 例如,a 似乎突然扫描了应用程序的组件和用户配置。 同样,将 custom 指令移动到单独的类是解决此问题的好方法。@DataJpaTestspring-doc.cn

如果这不是您的选项,则可以在测试的层次结构中创建一个 somewhere ,以便改用它。 或者,您可以为测试指定一个源,这将禁用查找默认源的行为。@SpringBootConfiguration

9.3.35. 使用 Spock 测试 Spring Boot 应用程序

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

9.4. 测试容器

Testcontainers 库提供了一种管理在 Docker 容器中运行的服务的方法。 它与 JUnit 集成,允许您编写一个测试类,该类可以在任何测试运行之前启动容器。 Testcontainers 对于编写与实际后端服务(如 MySQL、MongoDB、Cassandra 等)通信的集成测试特别有用。spring-doc.cn

Testcontainers 可以在 Spring Boot 测试中使用,如下所示:spring-doc.cn

Java
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

import org.springframework.boot.test.context.SpringBootTest;

@Testcontainers
@SpringBootTest
class MyIntegrationTests {

    @Container
    static Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:5");

    @Test
    void myTest() {
        // ...
    }

}
Kotlin
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import org.testcontainers.containers.Neo4jContainer
import org.testcontainers.junit.jupiter.Container
import org.testcontainers.junit.jupiter.Testcontainers

@Testcontainers
@SpringBootTest
class MyIntegrationTests {

    @Test
    fun myTest() {
        // ...
    }

    companion object {
        @Container
        val neo4j = Neo4jContainer("neo4j:5")
    }

}

这将在运行任何测试之前启动运行 Neo4j(如果 Docker 在本地运行)的 docker 容器。 在大多数情况下,您需要配置应用程序以连接到容器中运行的服务。spring-doc.cn

9.4.1. 服务连接

服务连接是与任何远程服务的连接。 Spring Boot 的自动配置可以使用服务连接的详细信息,并使用它们来建立与远程服务的连接。 执行此操作时,连接详细信息优先于任何与连接相关的配置属性。spring-doc.cn

使用 Testcontainers 时,可以通过在 test 类中注释 container 字段,为容器中运行的服务自动创建连接详细信息。spring-doc.cn

Java
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;

@Testcontainers
@SpringBootTest
class MyIntegrationTests {

    @Container
    @ServiceConnection
    static Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:5");

    @Test
    void myTest() {
        // ...
    }

}
Kotlin
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.testcontainers.service.connection.ServiceConnection
import org.testcontainers.containers.Neo4jContainer
import org.testcontainers.junit.jupiter.Container
import org.testcontainers.junit.jupiter.Testcontainers

@Testcontainers
@SpringBootTest
class MyIntegrationTests {

    @Test
    fun myTest() {
        // ...
    }

    companion object {

        @Container
        @ServiceConnection
        val neo4j = Neo4jContainer("neo4j:5")

    }

}

多亏了,上述配置允许应用程序中与 Neo4j 相关的 bean 与在 Testcontainers 管理的 Docker 容器中运行的 Neo4j 进行通信。 这是通过自动定义一个 bean 来完成的,然后由 Neo4j 自动配置使用,覆盖任何与连接相关的配置属性。@ServiceConnectionNeo4jConnectionDetailsspring-doc.cn

您需要将模块添加为测试依赖项,以便将服务连接与 Testcontainers 一起使用。spring-boot-testcontainers

服务连接注释由向 注册的类处理。 A 可以基于特定的子类或 Docker 镜像名称创建 Bean。ContainerConnectionDetailsFactoryspring.factoriesContainerConnectionDetailsFactoryConnectionDetailsContainerspring-doc.cn

jar 中提供了以下服务连接工厂:spring-boot-testcontainersspring-doc.cn

连接详细信息 匹配时间

CassandraConnectionDetailsspring-doc.cn

类型的容器CassandraContainerspring-doc.cn

CouchbaseConnectionDetailsspring-doc.cn

类型的容器CouchbaseContainerspring-doc.cn

ElasticsearchConnectionDetailsspring-doc.cn

类型的容器ElasticsearchContainerspring-doc.cn

FlywayConnectionDetailsspring-doc.cn

类型的容器JdbcDatabaseContainerspring-doc.cn

JdbcConnectionDetailsspring-doc.cn

类型的容器JdbcDatabaseContainerspring-doc.cn

KafkaConnectionDetailsspring-doc.cn

类型为 或KafkaContainerRedpandaContainerspring-doc.cn

LiquibaseConnectionDetailsspring-doc.cn

类型的容器JdbcDatabaseContainerspring-doc.cn

MongoConnectionDetailsspring-doc.cn

类型的容器MongoDBContainerspring-doc.cn

Neo4jConnectionDetailsspring-doc.cn

类型的容器Neo4jContainerspring-doc.cn

R2dbcConnectionDetailsspring-doc.cn

类型为 、 、 、 或MariaDBContainerMSSQLServerContainerMySQLContainerOracleContainerPostgreSQLContainerspring-doc.cn

RabbitConnectionDetailsspring-doc.cn

类型的容器RabbitMQContainerspring-doc.cn

RedisConnectionDetailsspring-doc.cn

名为 “redis” 的容器spring-doc.cn

ZipkinConnectionDetailsspring-doc.cn

名为 “openzipkin/zipkin” 的容器spring-doc.cn

默认情况下,将为给定的 . 例如,a 将同时创建 和 。ContainerPostgreSQLContainerJdbcConnectionDetailsR2dbcConnectionDetailsspring-doc.cn

如果只想创建适用类型的子集,则可以使用 的属性 .type@ServiceConnectionspring-doc.cn

默认情况下,用于获取用于查找连接详细信息的名称。 只要 Spring Boot 能够获取 instance 的实例,这就可以工作,例如上例中所示的字段。Container.getDockerImageName()Containerstaticspring-doc.cn

如果你正在使用方法, Spring Boot 不会调用 bean 方法来获取 Docker 镜像名称,因为这会导致急切的初始化问题。 相反,使用 bean 方法的返回类型来找出应该使用哪个连接详细信息。 只要你使用的是类型化容器,这就可以正常工作,例如 或。 如果你正在使用 ,例如与 Redis 一起使用,这将停止工作,如以下示例所示:@BeanNeo4jContainerRabbitMQContainerGenericContainerspring-doc.cn

Java
import org.testcontainers.containers.GenericContainer;

import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.context.annotation.Bean;

@TestConfiguration(proxyBeanMethods = false)
public class MyRedisConfiguration {

    @Bean
    @ServiceConnection(name = "redis")
    public GenericContainer<?> redisContainer() {
        return new GenericContainer<>("redis:7");
    }

}
Kotlin
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.boot.testcontainers.service.connection.ServiceConnection
import org.springframework.context.annotation.Bean
import org.testcontainers.containers.GenericContainer

@TestConfiguration(proxyBeanMethods = false)
class MyRedisConfiguration {

    @Bean
    @ServiceConnection(name = "redis")
    fun redisContainer(): GenericContainer<*> {
        return GenericContainer("redis:7")
    }

}

Spring Boot 无法判断使用了哪个容器镜像,因此必须使用属性from来提供该提示。GenericContainername@ServiceConnectionspring-doc.cn

您还可以使用属性 of 来覆盖将使用的连接详细信息,例如在使用自定义图像时。 如果您使用的是 Docker 镜像 ,您将用于确保已创建。name@ServiceConnectionregistry.mycompany.com/mirror/myredis@ServiceConnection(name="redis")RedisConnectionDetailsspring-doc.cn

9.4.2. 动态属性

与服务连接相比,一个稍微详细但更灵活的替代方案是 。 static 方法允许向 Spring Environment 添加动态属性值。@DynamicPropertySource@DynamicPropertySourcespring-doc.cn

Java
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;

@Testcontainers
@SpringBootTest
class MyIntegrationTests {

    @Container
    static Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:5");

    @Test
    void myTest() {
        // ...
    }

    @DynamicPropertySource
    static void neo4jProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.neo4j.uri", neo4j::getBoltUrl);
    }

}
Kotlin
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.DynamicPropertyRegistry
import org.springframework.test.context.DynamicPropertySource
import org.testcontainers.containers.Neo4jContainer
import org.testcontainers.junit.jupiter.Container
import org.testcontainers.junit.jupiter.Testcontainers

@Testcontainers
@SpringBootTest
class MyIntegrationTests {

    @Test
    fun myTest() {
        // ...
    }

    companion object {

        @Container
        val neo4j = Neo4jContainer("neo4j:5")

        @DynamicPropertySource
        fun neo4jProperties(registry: DynamicPropertyRegistry) {
            registry.add("spring.neo4j.uri") { neo4j.boltUrl }
        }

    }

}

上述配置允许应用程序中与 Neo4j 相关的 bean 与在 Testcontainers 管理的 Docker 容器内运行的 Neo4j 进行通信。spring-doc.cn

9.5. 测试工具

在测试应用程序时通常有用的一些测试实用程序类打包为 的一部分。spring-bootspring-doc.cn

9.5.1. ConfigDataApplicationContextInitializer

ConfigDataApplicationContextInitializer是可以应用于测试以加载 Spring Boot 文件。 当您不需要 提供的完整功能集时,可以使用它,如以下示例所示:ApplicationContextInitializerapplication.properties@SpringBootTestspring-doc.cn

Java
import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer;
import org.springframework.test.context.ContextConfiguration;

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

    // ...

}
Kotlin
import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer
import org.springframework.test.context.ContextConfiguration

@ContextConfiguration(classes = [Config::class], initializers = [ConfigDataApplicationContextInitializer::class])
class MyConfigFileTests {

    // ...

}
单独使用不支持注射。 它唯一的工作是确保将文件加载到 Spring 的 . 要获得支持,您需要额外配置 a 或使用 ,这将为您自动配置 一个。ConfigDataApplicationContextInitializer@Value("${…​}")application.propertiesEnvironment@ValuePropertySourcesPlaceholderConfigurer@SpringBootTest

9.5.2. TestPropertyValues

TestPropertyValues用于快速向 或 添加属性。 您可以使用字符串调用它,如下所示:ConfigurableEnvironmentConfigurableApplicationContextkey=valuespring-doc.cn

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

}
Kotlin
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.boot.test.util.TestPropertyValues
import org.springframework.mock.env.MockEnvironment

class MyEnvironmentTests {

    @Test
    fun testPropertySources() {
        val environment = MockEnvironment()
        TestPropertyValues.of("org=Spring", "name=Boot").applyTo(environment)
        assertThat(environment.getProperty("name")).isEqualTo("Boot")
    }

}

9.5.3. 输出捕获

OutputCapture是可用于捕获和输出的 JUnit。 要使用它,请将 add 和 inject 作为参数添加到您的测试类构造函数或测试方法中,如下所示:ExtensionSystem.outSystem.err@ExtendWith(OutputCaptureExtension.class)CapturedOutputspring-doc.cn

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

}
Kotlin
import org.assertj.core.api.Assertions.assertThat
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

@ExtendWith(OutputCaptureExtension::class)
class MyOutputCaptureTests {

    @Test
    fun testName(output: CapturedOutput?) {
        println("Hello World!")
        assertThat(output).contains("World")
    }

}

9.5.4. TestRestTemplate

TestRestTemplate是 Spring 的便捷替代方案,在集成测试中很有用。 你可以获取一个 vanilla 模板或发送 Basic HTTP 身份验证的模板(带有用户名和密码)。 在任一情况下,模板都是容错的。 这意味着它的行为对测试友好,不会在 4xx 和 5xx 错误上引发异常。 相反,可以通过返回的 state code 及其 status code 来检测此类错误。RestTemplateResponseEntityspring-doc.cn

Spring Framework 5.0 提供了一个适用于 WebFlux 集成测试以及 WebFlux 和 MVC 端到端测试的新功能。 它为断言提供了流畅的 API,这与 .WebTestClientTestRestTemplate

建议使用 Apache HTTP 客户端(版本 5.1 或更高版本),但并非强制性要求。 如果你在 Classpath 上有它,则通过适当地配置 Client 端来响应。 如果您确实使用 Apache 的 HTTP 客户端,则会启用一些其他测试友好功能:TestRestTemplatespring-doc.cn

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

  • Cookie 将被忽略(因此模板是无状态的)。spring-doc.cn

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

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

}
Kotlin
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.boot.test.web.client.TestRestTemplate

class MyTests {

    private val template = TestRestTemplate()

    @Test
    fun testRequest() {
        val headers = template.getForEntity("https://myhost.example.com/example", String::class.java)
        assertThat(headers.headers.location).hasHost("other.example.com")
    }

}

或者,如果将注释与 或 一起使用,则可以注入完全配置的注释并开始使用它。 如有必要,可以通过 Bean 应用其他定制。 任何未指定主机和端口的 URL 都会自动连接到嵌入式服务器,如以下示例所示:@SpringBootTestWebEnvironment.RANDOM_PORTWebEnvironment.DEFINED_PORTTestRestTemplateRestTemplateBuilderspring-doc.cn

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

    }

}
Kotlin
import org.assertj.core.api.Assertions.assertThat
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 java.time.Duration

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MySpringBootTests(@Autowired val template: TestRestTemplate) {

    @Test
    fun testRequest() {
        val headers = template.getForEntity("/example", String::class.java).headers
        assertThat(headers.location).hasHost("other.example.com")
    }

    @TestConfiguration(proxyBeanMethods = false)
    internal class RestTemplateBuilderConfiguration {

        @Bean
        fun restTemplateBuilder(): RestTemplateBuilder {
            return RestTemplateBuilder().setConnectTimeout(Duration.ofSeconds(1))
                .setReadTimeout(Duration.ofSeconds(1))
        }

    }

}

10. Docker Compose 支持

Docker Compose 是一种流行的技术,可用于为应用程序所需的服务定义和管理多个容器。 通常在应用程序旁边创建一个文件,用于定义和配置服务容器。compose.ymlspring-doc.cn

Docker Compose 的典型工作流是运行,在应用程序上运行,将其连接到已启动的服务,然后在完成后运行。docker compose updocker compose downspring-doc.cn

该模块可以包含在项目中,以支持使用 Docker Compose 处理容器。 将模块依赖项添加到您的构建中,如以下 Maven 和 Gradle 清单所示:spring-boot-docker-composespring-doc.cn

Maven 系列
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-docker-compose</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>
Gradle
dependencies {
    developmentOnly("org.springframework.boot:spring-boot-docker-compose")
}

当此模块作为依赖项包含在内时, Spring Boot 将执行以下操作:spring-doc.cn

  • 在工作目录中搜索 a 和其他常见的 compose 文件名compose.ymlspring-doc.cn

  • 与发现的docker compose upcompose.ymlspring-doc.cn

  • 为每个支持的容器创建服务连接 Beanspring-doc.cn

  • 应用程序关闭时调用docker compose stopspring-doc.cn

如果在启动应用程序时 Docker Compose 服务已经在运行,则 Spring Boot 将仅为每个支持的容器创建服务连接 bean。 它不会再次调用,也不会在应用程序关闭时调用。docker compose updocker compose stopspring-doc.cn

默认情况下,Spring Boot 的 Docker Compose 支持在运行测试时处于禁用状态。 要启用它,请设置为 。spring.docker.compose.skip.in-testsfalse
默认情况下,重新打包的存档不包含 Spring Boot 的 Docker Compose。 如果您想使用此支持,则需要包含它。 使用 Maven 插件时,请将属性设置为 。 使用 Gradle 插件时,请配置任务的 Classpath 以包含 developmentOnly 配置excludeDockerComposefalse

10.1. 先决条件

您需要在路径上安装 和 (或 ) CLI 应用程序。 支持的最低 Docker Compose 版本为 2.2.0。dockerdocker composedocker-composespring-doc.cn

10.2. 服务连接

服务连接是与任何远程服务的连接。 Spring Boot 的自动配置可以使用服务连接的详细信息,并使用它们来建立与远程服务的连接。 执行此操作时,连接详细信息优先于任何与连接相关的配置属性。spring-doc.cn

当使用 Spring Boot 的 Docker Compose 支持时,将建立与容器映射的端口的服务连接。spring-doc.cn

Docker Compose 的使用方式通常是将容器内的端口映射到计算机上的临时端口。 例如,Postgres 服务器可以使用端口 5432 在容器内运行,但在本地映射到完全不同的端口。 服务连接将始终发现并使用本地映射的端口。

使用容器的映像名称建立服务连接。 目前支持以下服务连接:spring-doc.cn

连接详细信息 匹配时间

CassandraConnectionDetailsspring-doc.cn

名为 “cassandra” 的容器spring-doc.cn

ElasticsearchConnectionDetailsspring-doc.cn

名为 “elasticsearch” 的容器spring-doc.cn

JdbcConnectionDetailsspring-doc.cn

名为 “gvenzl/oracle-xe”、“mariadb”、“mssql/server”、“mysql” 或 “postgres” 的容器spring-doc.cn

MongoConnectionDetailsspring-doc.cn

名为 “mongo” 的容器spring-doc.cn

R2dbcConnectionDetailsspring-doc.cn

名为 “gvenzl/oracle-xe”、“mariadb”、“mssql/server”、“mysql” 或 “postgres” 的容器spring-doc.cn

RabbitConnectionDetailsspring-doc.cn

名为 “rabbitmq” 的容器spring-doc.cn

RedisConnectionDetailsspring-doc.cn

名为 “redis” 的容器spring-doc.cn

ZipkinConnectionDetailsspring-doc.cn

名为 “openzipkin/zipkin” 的容器。spring-doc.cn

10.3. 自定义镜像

有时,您可能需要使用自己的映像版本来提供服务。 您可以使用任何自定义映像,只要其行为方式与标准映像相同即可。 具体而言,标准映像支持的任何环境变量也必须在自定义映像中使用。spring-doc.cn

如果您的映像使用不同的名称,则可以在文件中使用标签,以便 Spring Boot 可以提供服务连接。 使用 name 的标签提供服务名称。compose.ymlorg.springframework.boot.service-connectionspring-doc.cn

例如:spring-doc.cn

services:
  redis:
    image: 'mycompany/mycustomredis:7.0'
    ports:
      - '6379'
    labels:
      org.springframework.boot.service-connection: redis

10.4. 跳过特定容器

如果您在 中定义了一个不希望连接到应用程序的容器镜像,则可以使用标签来忽略它。 任何带有 label with 的容器都将被 Spring Boot 忽略。compose.ymlorg.springframework.boot.ignorespring-doc.cn

例如:spring-doc.cn

services:
  redis:
    image: 'redis:7.0'
    ports:
      - '6379'
    labels:
      org.springframework.boot.ignore: true

10.5. 使用特定的 Compose 文件

如果您的 compose 文件与应用程序不在同一目录中,或者名称不同,则可以使用 in 或 来指向其他文件。 属性可以定义为精确路径或相对于应用程序的路径。spring.docker.compose.fileapplication.propertiesapplication.yamlspring-doc.cn

例如:spring-doc.cn

性能
spring.docker.compose.file=../my-compose.yml
Yaml
spring:
  docker:
    compose:
      file: "../my-compose.yml"

10.6. 等待容器就绪

由 Docker Compose 启动的容器可能需要一些时间才能完全准备就绪。 检查就绪情况的推荐方法是在文件中的服务定义下添加一个部分。healthcheckcompose.ymlspring-doc.cn

由于文件中省略配置的情况并不少见,因此 Spring Boot 还直接检查服务就绪情况。 默认情况下,当可以与容器的映射端口建立 TCP/IP 连接时,容器被视为准备就绪。healthcheckcompose.ymlspring-doc.cn

您可以通过在文件中添加标签来按容器禁用此功能。org.springframework.boot.readiness-check.tcp.disablecompose.ymlspring-doc.cn

例如:spring-doc.cn

services:
  redis:
    image: 'redis:7.0'
    ports:
      - '6379'
    labels:
      org.springframework.boot.readiness-check.tcp.disable: true

您还可以更改 or 文件中的超时值:application.propertiesapplication.yamlspring-doc.cn

性能
spring.docker.compose.readiness.tcp.connect-timeout=10s
spring.docker.compose.readiness.tcp.read-timeout=5s
Yaml
spring:
  docker:
    compose:
      readiness:
        tcp:
          connect-timeout: 10s
          read-timeout: 5s

总超时可使用 进行配置。spring.docker.compose.readiness.timeoutspring-doc.cn

10.7. 控制 Docker Compose 生命周期

默认情况下, Spring Boot 会在应用程序启动时和关闭时调用。 如果您希望使用不同的生命周期管理,则可以使用该属性。docker compose updocker compose stopspring.docker.compose.lifecycle-managementspring-doc.cn

支持以下值:spring-doc.cn

  • none- 不要启动或停止 Docker Composespring-doc.cn

  • start-only- 在应用程序启动时启动 Docker Compose 并保持运行spring-doc.cn

  • start-and-stop- 在应用程序启动时启动 Docker Compose,在 JVM 退出时停止它spring-doc.cn

此外,还可以使用该属性来更改是否使用 or。 允许您配置 if 或 is used。spring.docker.compose.start.commanddocker compose updocker compose startspring.docker.compose.stop.commanddocker compose downdocker compose stopspring-doc.cn

以下示例显示了如何配置生命周期管理:spring-doc.cn

性能
spring.docker.compose.lifecycle-management=start-and-stop
spring.docker.compose.start.command=start
spring.docker.compose.stop.command=down
spring.docker.compose.stop.timeout=1m
Yaml
spring:
  docker:
    compose:
      lifecycle-management: start-and-stop
      start:
        command: start
      stop:
        command: down
        timeout: 1m

10.8. 激活 Docker Compose 配置文件

Docker Compose 配置文件与 Spring 配置文件类似,因为它们允许您针对特定环境调整 Docker Compose 配置。 如果要激活特定的 Docker Compose 配置文件,可以在 or 文件中使用该属性:spring.docker.compose.profiles.activeapplication.propertiesapplication.yamlspring-doc.cn

性能
spring.docker.compose.profiles.active=myprofile
Yaml
spring:
  docker:
    compose:
      profiles:
        active: "myprofile"

11. Testcontainers 支持

除了使用 Testcontainers 进行集成测试外,还可以在开发时使用它们。 接下来的部分将提供有关这方面的更多详细信息。spring-doc.cn

11.1. 在开发时使用 Testcontainers

这种方法允许开发人员为应用程序所依赖的服务快速启动容器,无需手动预置数据库服务器等内容。 以这种方式使用 Testcontainers 可提供类似于 Docker Compose 的功能,但您的容器配置是 Java 而不是 YAML。spring-doc.cn

要在开发时使用 Testcontainers,您需要使用 “test” classpath 而不是 “main” 来启动应用程序。 这将允许您访问所有声明的测试依赖项,并为您提供一个自然的位置来编写测试配置。spring-doc.cn

要创建应用程序的测试可启动版本,您应该在目录中创建一个 “Application” 类。 例如,如果您的主应用程序位于 中,则应创建src/testsrc/main/java/com/example/MyApplication.javasrc/test/java/com/example/TestMyApplication.javaspring-doc.cn

该类可以使用该方法启动真实的应用程序:TestMyApplicationSpringApplication.from(…​)spring-doc.cn

Java
import org.springframework.boot.SpringApplication;

public class TestMyApplication {

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

}
Kotlin
import org.springframework.boot.fromApplication

fun main(args: Array<String>) {
    fromApplication<MyApplication>().run(*args)
}

您还需要定义要与应用程序一起启动的实例。 为此,您需要确保已将模块添加为依赖项。 完成后,您可以创建一个类,用于为要启动的容器声明方法。Containerspring-boot-testcontainerstest@TestConfiguration@Beanspring-doc.cn

你也可以用 for create bean 来注释你的方法。 有关支持的技术的详细信息,请参阅服务连接部分。@Bean@ServiceConnectionConnectionDetailsspring-doc.cn

典型的 Testcontainers 配置如下所示:spring-doc.cn

Java
import org.testcontainers.containers.Neo4jContainer;

import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.context.annotation.Bean;

@TestConfiguration(proxyBeanMethods = false)
public class MyContainersConfiguration {

    @Bean
    @ServiceConnection
    public Neo4jContainer<?> neo4jContainer() {
        return new Neo4jContainer<>("neo4j:5");
    }

}
Kotlin
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.boot.testcontainers.service.connection.ServiceConnection
import org.springframework.context.annotation.Bean
import org.testcontainers.containers.Neo4jContainer

@TestConfiguration(proxyBeanMethods = false)
class MyContainersConfiguration {

    @Bean
    @ServiceConnection
    fun neo4jContainer(): Neo4jContainer<*> {
        return Neo4jContainer("neo4j:5")
    }

}
bean 的生命周期由 Spring Boot 自动管理。 容器将自动启动和停止。Container

定义测试配置后,您可以使用该方法将其附加到测试Starters:with(…​)spring-doc.cn

Java
import org.springframework.boot.SpringApplication;

public class TestMyApplication {

    public static void main(String[] args) {
        SpringApplication.from(MyApplication::main).with(MyContainersConfiguration.class).run(args);
    }

}
Kotlin
import org.springframework.boot.fromApplication
import org.springframework.boot.with

fun main(args: Array<String>) {
    fromApplication<MyApplication>().with(MyContainersConfiguration::class).run(*args)
}

现在,您可以像启动任何常规 Java 方法应用程序一样启动应用程序,以启动应用程序及其需要运行的容器。TestMyApplicationmainspring-doc.cn

您可以使用 Maven 目标或 Gradle 任务从命令行执行此操作。spring-boot:test-runbootTestRun

11.1.1. 在开发时贡献动态属性

如果您想在开发时从方法中提供动态属性,可以通过注入 . 其工作方式与您可以在测试中使用的 @DynamicPropertySource 注解类似。 它允许您添加在容器启动后将变为可用的属性。Container@BeanDynamicPropertyRegistryspring-doc.cn

典型的配置如下所示:spring-doc.cn

Java
import org.testcontainers.containers.MongoDBContainer;

import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.DynamicPropertyRegistry;

@TestConfiguration(proxyBeanMethods = false)
public class MyContainersConfiguration {

    @Bean
    public MongoDBContainer mongoDbContainer(DynamicPropertyRegistry properties) {
        MongoDBContainer container = new MongoDBContainer("mongo:5.0");
        properties.add("spring.data.mongodb.host", container::getHost);
        properties.add("spring.data.mongodb.port", container::getFirstMappedPort);
        return container;
    }

}
Kotlin
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.context.annotation.Bean
import org.springframework.test.context.DynamicPropertyRegistry
import org.testcontainers.containers.MongoDBContainer

@TestConfiguration(proxyBeanMethods = false)
class MyContainersConfiguration {

    @Bean
    fun monogDbContainer(properties: DynamicPropertyRegistry): MongoDBContainer {
        var container = MongoDBContainer("mongo:5.0")
        properties.add("spring.data.mongodb.host", container::getHost)
        properties.add("spring.data.mongodb.port", container::getFirstMappedPort)
        return container
    }

}
建议尽可能使用 a,但是,对于尚不支持的技术,动态属性可能是一个有用的后备。@ServiceConnection@ServiceConnection

11.1.2. 导入 Testcontainer 声明类

使用 Testcontainers 时的一种常见模式是将实例声明为静态字段。 通常,这些字段直接在 test 类上定义。 它们也可以在父类或测试实现的接口上声明。Containerspring-doc.cn

例如,以下接口声明和容器:MyContainersmongoneo4jspring-doc.cn

import org.testcontainers.containers.MongoDBContainer;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;

import org.springframework.boot.testcontainers.service.connection.ServiceConnection;

public interface MyContainers {

    @Container
    @ServiceConnection
    MongoDBContainer mongoContainer = new MongoDBContainer("mongo:5.0");

    @Container
    @ServiceConnection
    Neo4jContainer<?> neo4jContainer = new Neo4jContainer<>("neo4j:5");

}

如果您已经以这种方式定义了容器,或者您只是喜欢这种样式,则可以导入这些声明类,而不是将容器定义为方法。 为此,请将注释添加到您的测试配置类中:@Bean@ImportTestcontainersspring-doc.cn

Java
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.context.ImportTestcontainers;

@TestConfiguration(proxyBeanMethods = false)
@ImportTestcontainers(MyContainers.class)
public class MyContainersConfiguration {

}
Kotlin
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.boot.testcontainers.context.ImportTestcontainers

@TestConfiguration(proxyBeanMethods = false)
@ImportTestcontainers(MyContainers::class)
class MyContainersConfiguration
如果您不打算使用服务连接功能,但想改用 @DynamicPropertySource,请从字段中删除注释。 您还可以将带注释的方法添加到声明类中。@ServiceConnectionContainer@DynamicPropertySource

11.1.3. 在开发时将 DevTools 与 Testcontainers 一起使用

使用 devtools 时,可以使用 . 当 devtools 重新启动应用程序时,不会重新创建此类 bean。 这对于 Testcontainer bean 特别有用,因为尽管应用程序重新启动,它们仍保持其状态。@RestartScopeContainerspring-doc.cn

Java
import org.testcontainers.containers.MongoDBContainer;

import org.springframework.boot.devtools.restart.RestartScope;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.context.annotation.Bean;

@TestConfiguration(proxyBeanMethods = false)
public class MyContainersConfiguration {

    @Bean
    @RestartScope
    @ServiceConnection
    public MongoDBContainer mongoDbContainer() {
        return new MongoDBContainer("mongo:5.0");
    }

}
Kotlin
import org.springframework.boot.devtools.restart.RestartScope
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.boot.testcontainers.service.connection.ServiceConnection
import org.springframework.context.annotation.Bean
import org.testcontainers.containers.MongoDBContainer

@TestConfiguration(proxyBeanMethods = false)
class MyContainersConfiguration {

    @Bean
    @RestartScope
    @ServiceConnection
    fun monogDbContainer(): MongoDBContainer {
        return MongoDBContainer("mongo:5.0")
    }

}
如果你使用的是 Gradle 并希望使用此功能,则需要将依赖项的配置从 更改为 。 使用默认范围 ,该任务不会获取代码中的更改,因为 devtools 未处于活动状态。spring-boot-devtoolsdevelopmentOnlytestImplementationdevelopmentOnlybootTestRun

12. 创建您自己的自动配置

如果您在开发共享库的公司工作,或者如果您从事开源或商业库的工作,则可能需要开发自己的自动配置。 自动配置类可以捆绑在外部 jar 中,并且仍然由 Spring Boot 拾取。spring-doc.cn

Auto-configuration 可以与 “starter” 相关联,该 “starter” 提供 auto-configuration 代码以及您将与之一起使用的典型 libraries。 我们首先介绍构建自己的自动配置所需了解的内容,然后我们继续介绍创建自定义Starters所需的典型步骤spring-doc.cn

12.1. 了解自动配置的 bean

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

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

12.2. 查找 Auto-configuration Candidate

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

com.mycorp.libx.autoconfigure.LibXAutoConfiguration
com.mycorp.libx.autoconfigure.LibXWebAutoConfiguration
您可以使用该字符向 imports 文件添加注释。#
自动配置只能通过在 imports 文件中命名来加载。 确保它们在特定的包空间中定义,并且它们永远不会成为组件扫描的目标。 此外,自动配置类不应启用组件扫描来查找其他组件。 应改用特定注释。@Import

如果您的配置需要按特定顺序应用,则可以在 @AutoConfiguration 注释或专用的 @AutoConfigureBefore 和 @AutoConfigureAfter 注释上使用 、 和 属性。 例如,如果您提供特定于 Web 的配置,则可能需要在 .beforebeforeNameafterafterNameWebMvcAutoConfigurationspring-doc.cn

如果要订购某些不应直接了解彼此的自动配置,也可以使用 。 该 annotation 与常规 annotation 具有相同的语义,但为 auto-configuration 类提供了专用的顺序。@AutoConfigureOrder@Orderspring-doc.cn

与标准类一样,应用自动配置类的顺序仅影响其 bean 的定义顺序。 这些 bean 的后续创建顺序不受影响,并且由每个 bean 的依赖关系和任何关系决定。@Configuration@DependsOnspring-doc.cn

12.3. 条件注解

您几乎总是希望在 auto-configuration 类中包含一个或多个 Comments。 注解是一个常见的示例,用于允许开发人员在对您的默认值不满意时覆盖自动配置。@Conditional@ConditionalOnMissingBeanspring-doc.cn

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

12.3.1. 类条件

和 注解允许根据特定类的存在与否来包含类。 由于注释元数据是使用 ASM 解析的,因此您可以使用该属性来引用实际类,即使该类实际上可能并未出现在正在运行的应用程序类路径上。 如果您希望通过使用值来指定类名,也可以使用该属性。@ConditionalOnClass@ConditionalOnMissingClass@ConfigurationvaluenameStringspring-doc.cn

此机制不适用于通常返回类型是条件目标的方法:在方法的条件应用之前,JVM 将加载类和可能处理的方法引用,如果类不存在,则这些引用将失败。@Beanspring-doc.cn

若要处理此方案,可以使用单独的类来隔离条件,如以下示例所示:@Configurationspring-doc.cn

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

    }

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

@Configuration(proxyBeanMethods = false)
// Some conditions ...
class MyAutoConfiguration {

    // Auto-configured beans ...
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(SomeService::class)
    class SomeServiceConfiguration {

        @Bean
        @ConditionalOnMissingBean
        fun someService(): SomeService {
            return SomeService()
        }

    }

}
如果使用 或作为元注释的一部分来编写自己的组合注释,则必须使用,因为在这种情况下不会处理对类的引用。@ConditionalOnClass@ConditionalOnMissingClassname

12.3.2. Bean 条件

和 注解允许根据特定 bean 的存在与否来包含 bean。 您可以使用该属性按类型指定 bean 或按名称指定 bean。 该属性允许您限制搜索 bean 时应考虑的层次结构。@ConditionalOnBean@ConditionalOnMissingBeanvaluenamesearchApplicationContextspring-doc.cn

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

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

}
Kotlin
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    fun someService(): SomeService {
        return SomeService()
    }

}

在前面的示例中,如果 .someServiceSomeServiceApplicationContextspring-doc.cn

您需要非常小心 bean 定义的添加顺序,因为这些条件是根据到目前为止已处理的内容进行评估的。 因此,我们建议仅在自动配置类上使用 and 注释(因为可以保证在添加任何用户定义的 bean 定义后加载这些 Comments)。@ConditionalOnBean@ConditionalOnMissingBean
@ConditionalOnBean并且不会阻止创建类。 在类级别使用这些条件与使用 Comments 标记每个包含的方法之间的唯一区别是,如果条件不匹配,前者会阻止将类注册为 Bean。@ConditionalOnMissingBean@Configuration@Bean@Configuration
声明方法时,请在方法的 return 类型中提供尽可能多的类型信息。 例如,如果 Bean 的具体类实现了一个接口,则 Bean 方法的返回类型应该是具体类,而不是接口。 在使用 Bean 条件时,在方法中提供尽可能多的类型信息尤为重要,因为它们的评估只能依赖于方法签名中可用的类型信息。@Bean@Bean

12.3.3. 属性条件

该注释允许根据 Spring Environment 属性包含配置。 使用 and 属性指定应检查的属性。 默认情况下,将匹配存在且不等于的任何属性。 您还可以使用 和 属性创建更高级的检查。@ConditionalOnPropertyprefixnamefalsehavingValuematchIfMissingspring-doc.cn

如果属性中给出了多个名称,则所有属性都必须通过测试才能匹配条件。namespring-doc.cn

12.3.4. 资源条件

该注释允许仅在存在特定资源时包含配置。 可以使用通常的 Spring 约定指定资源,如以下示例所示:。@ConditionalOnResourcefile:/home/user/test.datspring-doc.cn

12.3.5. Web 应用程序条件

和 annotations 允许根据应用程序是否为 Web 应用程序来包含配置。 基于 servlet 的 Web 应用程序是使用 Spring 、定义范围或具有 . 反应式 Web 应用程序是使用 . 或具有 .@ConditionalOnWebApplication@ConditionalOnNotWebApplicationWebApplicationContextsessionConfigurableWebEnvironmentReactiveWebApplicationContextConfigurableReactiveWebEnvironmentspring-doc.cn

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

12.3.6. SPEL 表达式条件

该 Comments 允许根据 SPEL 表达式的结果包含配置。@ConditionalOnExpressionspring-doc.cn

在表达式中引用 bean 将导致该 bean 在上下文刷新处理中非常早地初始化。 因此,bean 将不符合后处理条件(例如配置属性绑定),并且其状态可能不完整。

12.4. 测试您的 Auto-configuration

自动配置可能受许多因素影响:用户配置(定义和自定义)、条件评估(存在特定库)等。 具体来说,每个测试都应该创建一个定义明确的 Well Defined,用于表示这些自定义项的组合。 提供了实现此目的的好方法。@BeanEnvironmentApplicationContextApplicationContextRunnerspring-doc.cn

ApplicationContextRunner在本机映像中运行测试时不起作用。

ApplicationContextRunner通常定义为 Test 类的字段,用于收集基本、通用的配置。 以下示例确保始终调用该 API:MyServiceAutoConfigurationspring-doc.cn

Java
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
    .withConfiguration(AutoConfigurations.of(MyServiceAutoConfiguration.class));
Kotlin
val contextRunner = ApplicationContextRunner()
    .withConfiguration(AutoConfigurations.of(MyServiceAutoConfiguration::class.java))
如果必须定义多个 auto-configurations,则无需对它们的声明进行排序,因为它们的调用顺序与运行应用程序时的顺序完全相同。

每个测试都可以使用运行程序来表示特定的使用案例。 例如,下面的示例调用用户配置 () 并检查自动配置是否正确退出。 调用提供了可与 一起使用的回调上下文。UserConfigurationrunAssertJspring-doc.cn

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

}
Kotlin
@Test
fun defaultServiceBacksOff() {
    contextRunner.withUserConfiguration(UserConfiguration::class.java)
        .run { context: AssertableApplicationContext ->
            assertThat(context).hasSingleBean(MyService::class.java)
            assertThat(context).getBean("myCustomService")
                .isSameAs(context.getBean(MyService::class.java))
        }
}

@Configuration(proxyBeanMethods = false)
internal class UserConfiguration {

    @Bean
    fun myCustomService(): MyService {
        return MyService("mine")
    }

}

还可以轻松自定义 ,如以下示例所示:Environmentspring-doc.cn

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

运行程序还可用于显示 . 报表可以打印 或 级别。 以下示例显示如何使用 在 auto-configuration tests 中打印报告。ConditionEvaluationReportINFODEBUGConditionEvaluationReportLoggingListenerspring-doc.cn

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

}
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.assertj.AssertableApplicationContext
import org.springframework.boot.test.context.runner.ApplicationContextRunner

class MyConditionEvaluationReportingTests {

    @Test
    fun autoConfigTest() {
        ApplicationContextRunner()
            .withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))
            .run { context: AssertableApplicationContext? -> }
    }

}

12.4.1. 模拟 Web 上下文

如果需要测试仅在 servlet 或反应式 Web 应用程序上下文中运行的自动配置,请分别使用 or。WebApplicationContextRunnerReactiveWebApplicationContextRunnerspring-doc.cn

12.4.2. 覆盖 Classpath

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

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

12.5. 创建您自己的 Starter

典型的 Spring Boot Starters包含用于自动配置和自定义给定技术基础设施的代码,我们称之为 “acme”。 为了使其易于扩展,可以将专用命名空间中的许多 Configuration Key 公开给环境。 最后,提供了一个 “starter” 依赖项,以帮助用户尽可能轻松地入门。spring-doc.cn

具体来说,自定义Starters可以包含以下内容:spring-doc.cn

  • 包含 “acme” 的自动配置代码的模块。autoconfigurespring-doc.cn

  • 为模块提供依赖项的模块以及 “acme” 和通常有用的任何其他依赖项。 简而言之,添加 starter 应该提供开始使用该库所需的一切。starterautoconfigurespring-doc.cn

这种分为两个模块的做法是完全没有必要的。 如果 “acme” 有多种风格、选项或可选功能,那么最好将自动配置分开,因为您可以清楚地表达某些功能是可选的。 此外,您还可以制作一个 starter 来提供有关这些可选依赖项的意见。 与此同时,其他人可以只依赖该模块,并制作自己的不同意见的Starters。autoconfigurespring-doc.cn

如果自动配置相对简单且没有可选功能,那么在 starter 中合并两个模块绝对是一种选择。spring-doc.cn

12.5.1. 命名

您应该确保为 starter 提供适当的命名空间。 不要以 , 以 开头的模块名称,即使您使用不同的 Maven 也是如此。 将来,我们可能会为您自动配置的事物提供官方支持。spring-bootgroupIdspring-doc.cn

根据经验,您应该在 starter 之后命名组合模块。 例如,假设您正在为 “acme” 创建一个Starters,并将 auto-configure 模块命名为 starter 和 starter 。 如果您只有一个模块将两者组合在一起,请将其命名为 。acme-spring-bootacme-spring-boot-starteracme-spring-boot-starterspring-doc.cn

12.5.2. 配置键

如果您的 starter 提供 Configuration Key,请为它们使用唯一的命名空间。 特别是,不要在 Spring Boot 使用的名称空间中包含您的键(例如、、、等)。 如果你使用相同的命名空间,我们将来可能会以破坏你的模块的方式修改这些命名空间。 根据经验,请在所有键前加上您拥有的 namespace (例如 )。servermanagementspringacmespring-doc.cn

通过为每个属性添加字段 javadoc 来确保记录配置键,如以下示例所示:spring-doc.cn

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

}
Kotlin
import org.springframework.boot.context.properties.ConfigurationProperties
import java.time.Duration

@ConfigurationProperties("acme")
class AcmeProperties(

    /**
     * Whether to check the location of acme resources.
     */
    var isCheckLocation: Boolean = true,

    /**
     * Timeout for establishing a connection to the acme server.
     */
    var loginTimeout:Duration = Duration.ofSeconds(3))
您应该只使用带有字段 Javadoc 的纯文本,因为它们在添加到 JSON 之前不会进行处理。@ConfigurationProperties

以下是我们在内部遵循的一些规则,以确保描述一致:spring-doc.cn

  • 请勿以 “The” 或 “A” 开头描述。spring-doc.cn

  • 对于类型,请以 “Whether” 或 “Enable” 开始描述。booleanspring-doc.cn

  • 对于基于集合的类型,以 “Comma-separated list” 开始描述spring-doc.cn

  • 如果默认单位与毫秒不同,请使用 instead instead and 并描述默认单位,例如“如果未指定持续时间后缀,则将使用秒”。java.time.Durationlongspring-doc.cn

  • 除非必须在运行时确定,否则不要在描述中提供默认值。spring-doc.cn

确保触发元数据生成,以便 IDE 帮助也可用于您的密钥。 您可能需要查看生成的元数据 () 以确保您的密钥已正确记录。 在兼容的 IDE 中使用您自己的 starter 也是验证元数据质量的好主意。META-INF/spring-configuration-metadata.jsonspring-doc.cn

12.5.3. “autoconfigure” 模块

该模块包含开始使用该库所需的一切。 它还可能包含配置键定义(例如 )和可用于进一步自定义组件初始化方式的任何回调接口。autoconfigure@ConfigurationPropertiesspring-doc.cn

您应该将库的依赖项标记为可选,以便可以更轻松地将模块包含在项目中。 如果这样做,则不会提供库,并且默认情况下, Spring Boot 会退缩。autoconfigure

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

使用 Maven 构建时,建议在包含 auto-configurations 的模块中添加以下依赖项:spring-doc.cn

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

如果您直接在应用程序中定义了 auto-configurations,请确保配置 以防止目标将依赖项添加到 fat jar 中:spring-boot-maven-pluginrepackagespring-doc.cn

<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 时,应在配置中声明依赖项,如以下示例所示:annotationProcessorspring-doc.cn

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

12.5.4. Starter 模块

Starters真的是一个空罐子。 它的唯一目的是提供使用库所需的依赖项。 您可以将其视为对开始所需内容的固执己见的看法。spring-doc.cn

不要对添加起始项的项目做出假设。 如果要自动配置的库通常需要其他启动程序,请同时提及它们。 如果可选依赖项的数量很高,则可能很难提供一组适当的默认依赖项,因为您应该避免包含对于库的典型使用不必要的依赖项。 换句话说,您不应包含可选依赖项。spring-doc.cn

无论哪种方式,你的 starter 都必须直接或间接引用核心 Spring Boot starter () (如果你的 starter 依赖于另一个 starter,则无需添加它)。 如果项目是仅使用您的自定义Starters创建的,则 Spring Boot 的核心功能将因核心Starters的存在而得到尊重。spring-boot-starter

13. Kotlin 支持

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

Spring Boot 通过利用其他 Spring 项目(如 Spring Framework、Spring Data 和 Reactor)中的支持来提供 Kotlin 支持。 有关更多信息,请参阅 Spring Framework Kotlin 支持文档spring-doc.cn

开始使用 Spring Boot 和 Kotlin 的最简单方法是遵循此综合教程。 您可以使用 start.spring.io 创建新的 Kotlin 项目。 如果您需要支持,请随时加入 Kotlin Slack 的 #spring 频道,或者在 Stack Overflow 上使用 和 标签提问。springkotlinspring-doc.cn

13.1. 要求

Spring Boot 至少需要 Kotlin 1.7.x,并通过依赖项管理管理合适的 Kotlin 版本。 要使用 Kotlin,并且必须存在于 Classpath 中。 变体 和 也可以使用。org.jetbrains.kotlin:kotlin-stdliborg.jetbrains.kotlin:kotlin-reflectkotlin-stdlibkotlin-stdlib-jdk7kotlin-stdlib-jdk8spring-doc.cn

由于 Kotlin 类默认是 final,因此您可能希望配置 kotlin-spring 插件,以便自动打开 Spring 注释的类,以便可以代理它们。spring-doc.cn

在 Kotlin 中序列化/反序列化 JSON 数据需要 Jackson 的 Kotlin 模块。 在 Classpath 上找到它时,它会自动注册。 如果存在 Jackson 和 Kotlin,但不存在 Jackson Kotlin 模块,则会记录一条警告消息。spring-doc.cn

如果在 start.spring.io 上引导 Kotlin 项目,则默认提供这些依赖项和插件。

13.2. 空安全

Kotlin 的主要功能之一是 null 安全。 它在编译时处理值,而不是将问题推迟到运行时并遇到 . 这有助于消除常见的错误来源,而无需支付像 . Kotlin 还允许使用具有可为 null 值的函数结构,如本 Kotlin 中的 null 安全性综合指南中所述。nullNullPointerExceptionOptionalspring-doc.cn

尽管 Java 不允许在其类型系统中表达 null 安全性,但 Spring Framework、Spring Data 和 Reactor 现在通过工具友好的注释提供其 API 的 null 安全性。 默认情况下,Kotlin 中使用的 Java API 中的类型被识别为放宽了 null 检查的平台类型Kotlin 对 JSR 305 注释的支持与可为 null 性注释相结合,为 Kotlin 中的相关 Spring API 提供了空安全性。spring-doc.cn

可以通过添加编译器标志和以下选项来配置 JSR 305 检查:. 默认行为与 相同。 在从 Spring API 推断的 Kotlin 类型中,需要考虑 null-safety 该值,但应在知道 Spring API 可空性声明甚至在次要版本之间演变,并且将来可能会添加更多检查的情况下使用该值。-Xjsr305-Xjsr305={strict|warn|ignore}-Xjsr305=warnstrictspring-doc.cn

尚不支持泛型类型参数、varargs 和数组元素可为 null 性。 有关最新信息,请参阅 SPR-15942。 另请注意,Spring Boot 自己的 API 尚未注释

13.3. Kotlin API

13.3.1. runApplication

Spring Boot 提供了一种惯用的方式来运行应用程序,如以下示例所示:runApplication<MyApplication>(*args)spring-doc.cn

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)spring-doc.cn

runApplication<MyApplication>(*args) {
    setBannerMode(OFF)
}

13.3.2. 扩展

Kotlin 扩展提供了使用其他功能扩展现有类的功能。 Spring Boot Kotlin API 利用这些扩展为现有 API 添加新的 Kotlin 特定便利。spring-doc.cn

TestRestTemplate提供了扩展,类似于 Spring Framework 为 Spring Framework 提供的扩展。 此外,这些扩展还可以利用 Kotlin 具体化类型参数。RestOperationsspring-doc.cn

13.4. 依赖项管理

为了避免在 Classpath 上混合不同版本的 Kotlin 依赖项, Spring Boot 导入了 Kotlin BOM。spring-doc.cn

使用 Maven,可以通过设置属性来自定义 Kotlin 版本,并为 . 使用 Gradle 时,Spring Boot 插件会自动与 Kotlin 插件的版本保持一致。kotlin.versionkotlin-maven-pluginkotlin.versionspring-doc.cn

Spring Boot 还通过导入 Kotlin Coroutines BOM 来管理 Coroutines 依赖项的版本。 可以通过设置属性来自定义版本。kotlin-coroutines.versionspring-doc.cn

org.jetbrains.kotlinx:kotlinx-coroutines-reactor如果引导 Kotlin 项目时至少有一个对 start.spring.io 的反应式依赖项,则默认提供依赖项。

13.5. @ConfigurationProperties

@ConfigurationProperties当与构造函数结合使用时,绑定支持具有不可变属性的类,如以下示例所示:valspring-doc.cn

@ConfigurationProperties("example.kotlin")
data class KotlinExampleProperties(
        val name: String,
        val description: String,
        val myService: MyService) {

    data class MyService(
            val apiToken: String,
            val uri: URI
    )
}
要使用 annotation 处理器生成您自己的元数据应该为 kapt 配置依赖项。 请注意,由于 kapt 提供的模型的限制,某些功能(例如检测默认值或已弃用的项目)无法正常工作。spring-boot-configuration-processor

13.6. 测试

虽然可以使用 JUnit 4 来测试 Kotlin 代码,但 JUnit 5 是默认提供的,建议使用 JUnit 5。 JUnit 5 允许测试类实例化一次,并重复用于该类的所有测试。 这使得在非静态方法上使用 and 注解成为可能,这非常适合 Kotlin。@BeforeAll@AfterAllspring-doc.cn

要模拟 Kotlin 类,建议使用 MockK。 如果你需要 Mockito 特定的 @MockBean@SpyBean 注释的等效项,你可以使用 SpringMockK,它提供类似的 COMMENTS 。MockK@MockkBean@SpykBeanspring-doc.cn

14. SSL认证

Spring Boot 提供了配置 SSL 信任材料的能力,该材料可以应用于多种类型的连接,以支持安全通信。 带有前缀的配置属性可用于指定命名的信任材料和相关信息集。spring.ssl.bundlespring-doc.cn

14.1. 使用 Java KeyStore 文件配置 SSL

带有前缀的配置属性可用于配置使用 Java 实用程序创建并以 JKS 或 PKCS12 格式存储在 Java KeyStore 文件中的信任材料包。 每个捆绑包都有一个用户提供的名称,可用于引用捆绑包。spring.ssl.bundle.jkskeytoolspring-doc.cn

当用于保护嵌入式 Web 服务器时,通常配置包含证书和私钥的 Java KeyStore,如以下示例所示:keystorespring-doc.cn

性能
spring.ssl.bundle.jks.mybundle.key.alias=application
spring.ssl.bundle.jks.mybundle.keystore.location=classpath:application.p12
spring.ssl.bundle.jks.mybundle.keystore.password=secret
spring.ssl.bundle.jks.mybundle.keystore.type=PKCS12
Yaml
spring:
  ssl:
    bundle:
      jks:
        mybundle:
          key:
            alias: "application"
          keystore:
            location: "classpath:application.p12"
            password: "secret"
            type: "PKCS12"

当用于保护客户端连接时,通常配置包含服务器证书的 Java KeyStore,如以下示例所示:truststorespring-doc.cn

性能
spring.ssl.bundle.jks.mybundle.truststore.location=classpath:server.p12
spring.ssl.bundle.jks.mybundle.truststore.password=secret
Yaml
spring:
  ssl:
    bundle:
      jks:
        mybundle:
          truststore:
            location: "classpath:server.p12"
            password: "secret"

有关完整的受支持属性集,请参阅 JksSslBundlePropertiesspring-doc.cn

14.2. 使用 PEM 编码的证书配置 SSL

带有前缀的配置属性可用于以 PEM 编码文本的形式配置信任材料包。 每个捆绑包都有一个用户提供的名称,可用于引用捆绑包。spring.ssl.bundle.pemspring-doc.cn

当用于保护嵌入式 Web 服务器时,通常配置有证书和私钥,如以下示例所示:keystorespring-doc.cn

性能
spring.ssl.bundle.pem.mybundle.keystore.certificate=classpath:application.crt
spring.ssl.bundle.pem.mybundle.keystore.private-key=classpath:application.key
Yaml
spring:
  ssl:
    bundle:
      pem:
        mybundle:
          keystore:
            certificate: "classpath:application.crt"
            private-key: "classpath:application.key"

当用于保护客户端连接时,通常使用服务器证书配置 a,如以下示例所示:truststorespring-doc.cn

性能
spring.ssl.bundle.pem.mybundle.truststore.certificate=classpath:server.crt
Yaml
spring:
  ssl:
    bundle:
      pem:
        mybundle:
          truststore:
            certificate: "classpath:server.crt"

PEM 内容可以直接用于 和 属性。 如果属性值包含 和 标记,则它们将被视为 PEM 内容,而不是资源位置。certificateprivate-keyBEGINENDspring-doc.cn

以下示例显示了如何定义信任库证书:spring-doc.cn

性能
spring.ssl.bundle.pem.mybundle.truststore.certificate=\
-----BEGIN CERTIFICATE-----\n\
MIID1zCCAr+gAwIBAgIUNM5QQv8IzVQsgSmmdPQNaqyzWs4wDQYJKoZIhvcNAQEL\n\
BQAwezELMAkGA1UEBhMCWFgxEjAQBgNVBAgMCVN0YXRlTmFtZTERMA8GA1UEBwwI\n\
...\n\
V0IJjcmYjEZbTvpjFKznvaFiOUv+8L7jHQ1/Yf+9c3C8gSjdUfv88m17pqYXd+Ds\n\
HEmfmNNjht130UyjNCITmLVXyy5p35vWmdf95U3uEbJSnNVtXH8qRmN9oK9mUpDb\n\
ngX6JBJI7fw7tXoqWSLHNiBODM88fUlQSho8\n\
-----END CERTIFICATE-----\n
Yaml
spring:
  ssl:
    bundle:
      pem:
        mybundle:
          truststore:
            certificate: |
              -----BEGIN CERTIFICATE-----
              MIID1zCCAr+gAwIBAgIUNM5QQv8IzVQsgSmmdPQNaqyzWs4wDQYJKoZIhvcNAQEL
              BQAwezELMAkGA1UEBhMCWFgxEjAQBgNVBAgMCVN0YXRlTmFtZTERMA8GA1UEBwwI
              ...
              V0IJjcmYjEZbTvpjFKznvaFiOUv+8L7jHQ1/Yf+9c3C8gSjdUfv88m17pqYXd+Ds
              HEmfmNNjht130UyjNCITmLVXyy5p35vWmdf95U3uEbJSnNVtXH8qRmN9oK9mUpDb
              ngX6JBJI7fw7tXoqWSLHNiBODM88fUlQSho8
              -----END CERTIFICATE-----

有关完整的受支持属性集,请参阅 PemSslBundlePropertiesspring-doc.cn

14.3. 应用 SSL 捆绑包

使用属性配置后,可以在 Spring Boot 自动配置的各种类型的连接的配置属性中按名称引用 SSL 捆绑包。 有关详细信息,请参阅有关嵌入式 Web 服务器数据技术和 REST 客户端的部分。spring-doc.cn

14.4. 使用 SSL 捆绑包

Spring Boot 自动配置一个类型的 bean,该 bean 提供对使用属性配置的每个命名捆绑包的访问。SslBundlesspring.ssl.bundlespring-doc.cn

可以从自动配置的 bean 中检索 an,并用于创建用于在 Client 端库中配置 SSL 连接的对象。 提供了获取这些 SSL 对象的分层方法:SslBundleSslBundlesSslBundlespring-doc.cn

  • getStores()提供对密钥存储和信任存储实例以及任何必需的密钥存储密码的访问。java.security.KeyStorespring-doc.cn

  • getManagers()提供对 AND 实例以及它们创建的 AND 数组的访问。java.net.ssl.KeyManagerFactoryjava.net.ssl.TrustManagerFactoryjava.net.ssl.KeyManagerjava.net.ssl.TrustManagerspring-doc.cn

  • createSslContext()提供了一种获取新实例的便捷方法。java.net.ssl.SSLContextspring-doc.cn

此外,它还提供有关正在使用的密钥、要使用的协议以及应应用于 SSL 引擎的任何选项的详细信息。SslBundlespring-doc.cn

以下示例显示了如何检索 an 并使用它来创建一个 :SslBundleSSLContextspring-doc.cn

Java
import javax.net.ssl.SSLContext;

import org.springframework.boot.ssl.SslBundle;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.stereotype.Component;

@Component
public class MyComponent {

    public MyComponent(SslBundles sslBundles) {
        SslBundle sslBundle = sslBundles.getBundle("mybundle");
        SSLContext sslContext = sslBundle.createSslContext();
        // do something with the created sslContext
    }

}
Kotlin
import org.springframework.boot.ssl.SslBundles
import org.springframework.stereotype.Component

@Component
class MyComponent(sslBundles: SslBundles) {

    init {
        val sslBundle = sslBundles.getBundle("mybundle")
        val sslContext = sslBundle.createSslContext()
        // do something with the created sslContext
    }

}

15. 下一步要读什么

如果您想了解有关本节中讨论的任何类的更多信息,请参阅 Spring Boot API 文档,或者您可以直接浏览源代码。 如果您有具体问题,请参阅操作方法部分。spring-doc.cn

如果您对 Spring Boot 的核心功能感到满意,则可以继续阅读有关生产就绪功能的信息。spring-doc.cn