0%

SpringBoot官方文档翻译-SpringBoot功能

Spring Boot Features

本节详细介绍Spring引导。在这里,您可以了解您可能想要使用和自定义的关键特性。如果您还没有这样做,那么您可能需要阅读入门使用,使您有了良好的基础知识。

version 2.3.4.RELEASE GA

Spring应用程序

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
.   ____          _            __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: v2.1.1.RELEASE

2013-07-31 00:08:16.117 INFO 56603 --- [ main] o.s.b.s.app.SampleApplication : Starting SampleApplication v0.1.0 on mycomputer with PID 56603 (/apps/myapp.jar started by pwebb)
2013-07-31 00:08:16.166 INFO 56603 --- [ main] ationConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.ser[emailprotected]6e5a8246: startup date [Wed Jul 31 00:08:16 PDT 2013]; root of context hierarchy
2014-03-04 13:09:54.912 INFO 41370 --- [ main] .t.TomcatServletWebServerFactory : Server initialized with port: 8080
2014-03-04 13:09:56.501 INFO 41370 --- [ main] o.s.b.s.app.SampleApplication : Started SampleApplication in 2.992 seconds (JVM running for 3.658)

默认情况下,显示INFO级别日志记录消息,包括一些相关的启动详细信息,例如启动该应用程序的用户。如果您需要INFO以外的其他日志级别,则可以按照第 26.4 节“日志级别”中的说明进行设置,

启动失败

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

1
2
3
4
5
6
7
8
9
10
11
***************************
APPLICATION FAILED TO START
***************************

Description:

Embedded servlet container failed to start. Port 8080 was already in use.

Action:

Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.

Note

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

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

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

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

自定义banner

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

banner.txt文件中,您可以使用以下任何占位符:

表 23.1 标语变量

Variable Description
${application.version} MANIFEST.MF中声明的应用程序的版本号。例如,Implementation-Version: 1.0被打印为1.0
${application.formatted-version} 您的应用程序的版本号,以MANIFEST.MF声明,并设置为显示格式(用方括号括起来并以v作为前缀)。例如(v1.0)
${spring-boot.version} 您正在使用的 Spring Boot 版本。例如2.1.1.RELEASE
${spring-boot.formatted-version} 您正在使用的 Spring Boot 版本,已格式化以用于显示(用方括号括起来,并以v作为前缀)。例如(v2.1.1.RELEASE)
${Ansi.NAME}(或${AnsiColor.NAME}${AnsiBackground.NAME}${AnsiStyle.NAME}) 其中NAME是 ANSI 转义代码的名称。有关详情,请参见AnsiPropertySource
${application.title} MANIFEST.MF中声明的应用程序标题。例如Implementation-Title: MyApp被打印为MyApp

Tip

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

您还可以使用spring.main.banner-mode属性来确定 banner 是否必须打印在System.out(console)上,发送到配置的 Logger(log)或根本不打印(off)。

打印的 banner 以以下名称注册为单例 bean:springBootBanner

自定义SpringApplication

如果您不喜欢默认的SpringApplication,则可以创建一个本地实例并对其进行自定义。例如,要关闭 banner,您可以编写:

1
2
3
4
5
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MySpringConfiguration.class);
app.setBannerMode(Banner.Mode.OFF);
app.run(args);
}

Note

传递给SpringApplication的构造函数参数是 Spring bean 的配置源。在大多数情况下,这些是对@Configuration类的引用,但它们也可以是对 XML 配置或应扫描的程序包的引用。

也可以通过使用application.properties文件来配置SpringApplication。有关详细信息,请参见 第 24 章,外部化配置

有关配置选项的完整列表,请参见SpringApplication Javadoc

流式构建器API

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

SpringApplicationBuilder使您可以将多个方法调用链接在一起,并包括parentchild方法,这些方法使您可以创建层次结构,如以下示例所示:

1
2
3
4
5
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);

Note

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

应用程序可用性

当部署在平台上时,应用程序可以使用Kubernetes探针等基础设施向平台提供关于其可用性的信息。Spring引导包括对常用的“活跃”和“准备就绪”可用状态的开箱即用支持。如果您正在使用Spring Boot的“actuator”支持,那么这些状态将作为运行状况端点组公开。

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

Liveness状态

应用程序的“活动”状态告诉它的内部状态是否允许它正确地工作,或者如果它当前失败了,它自己恢复。中断的“活动”状态意味着应用程序处于无法恢复的状态,基础设施应该重新启动应用程序。

通常,“活动”状态不应该基于外部检查,比如运行状况检查。如果是这样,失败的外部系统(数据库、Web API、外部缓存)将触发大规模重启和跨平台的级联故障。

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

Readiness状态

应用程序的“准备就绪”状态告诉应用程序是否准备好处理流量。失败的“准备就绪”状态告诉平台现在不应该将流量路由到应用程序。这通常发生在启动时,当CommandLineRunnerApplicationRunner组件正在处理,或在任何时候,如果应用程序认为它处理额外的流量太忙。

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

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

管理应用程序可用状态

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

例如,我们可以导出应用程序的“准备就绪”状态到一个文件,以便Kubernetes的“exec探针”可以查看这个文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Component
public class ReadinessStateExporter {

@EventListener
public void onStateChange(AvailabilityChangeEvent<ReadinessState> event) {
switch (event.getState()) {
case ACCEPTING_TRAFFIC:
// create file /tmp/healthy
break;
case REFUSING_TRAFFIC:
// remove file /tmp/healthy
break;
}
}

}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Component
public class LocalCacheVerifier {

private final ApplicationEventPublisher eventPublisher;

public LocalCacheVerifier(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}

public void checkLocalCache() {
try {
//...
}
catch (CacheCompletelyBrokenException ex) {
AvailabilityChangeEvent.publish(this.eventPublisher, ex, LivenessState.BROKEN);
}
}

}

Spring Boot为执行器运行状况端点的“活动”和“准备就绪”提供了Kubernetes HTTP探针。在专门的部分中,您可以获得关于在Kubernetes上部署Spring引导应用程序的更多指导。

应用程序事件和侦听器

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

Note

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

如果希望这些监听器自动注册,而不管创建应用程序的方式如何,都可以将META-INF/spring.factories文件添加到项目中,并使用org.springframework.context.ApplicationListener键引用您的监听器,如以下示例所示:

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

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

  1. ApplicationStartingEvent在运行开始时但在进行任何处理之前(侦听器和初始化器的注册除外)发送。
  2. ApplicationEnvironmentPreparedEvent在上下文中使用的环境已知但在创建上下文之前发送。
  3. 当准备好ApplicationContext并且调用了ApplicationContextInitializedEvent,但在加载任何bean定义之前发送applicationcontextinitialalizer
  4. ApplicationPreparedEvent是在刷新启动之前但加载bean定义之后发送的。
  5. ApplicationStartedEvent是在刷新上下文之后,在调用任何应用程序和命令行运行器之前发送的。
  6. 然后用AvailabilityChangeEvent发送一个`LivenessState.CORRECT,表示应用程序是活动的。
  7. 在调用任何应用程序和command-line runners之后发送一个ApplicationReadyEvent
  8. 然后,AvailabilityChangeEvent发送一个ReadinessState.ACCEPTING_TRAFFIC,表示应用程序已准备好为请求提供服务。
  9. 如果启动时出现异常,则发送ApplicationFailedEvent

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

  • WebServerInitializedEvent在WebServer准备好之后发送。ServletWebServerInitializedEventReactiveWebServerInitializedEvent分别是servlet和反应变量。
  • 当刷新ApplicationContext时发送ContextRefreshedEvent

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

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

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

Web环境

SpringApplication尝试代表您创建正确的ApplicationContext类型。确定WebApplicationType的算法非常简单:

  • 如果存在 Spring MVC,则使用AnnotationConfigServletWebServerApplicationContext
  • 如果不存在Spring MVC且存在Spring WebFlux,则使用AnnotationConfigReactiveWebServerApplicationContext
  • 否则,使用AnnotationConfigApplicationContext

这意味着,如果您在同一应用程序中使用 Spring MVC 和 Spring WebFlux 的新WebClient,则默认使用 Spring MVC。您可以通过调用setWebApplicationType(WebApplicationType)轻松覆盖它。

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

Tip

在 JUnit 测试中使用SpringApplication时,通常希望调用setWebApplicationType(WebApplicationType.NONE)

访问应用程序参数

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import org.springframework.boot.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.stereotype.*;

@Component
public class MyBean {

@Autowired
public MyBean(ApplicationArguments args) {
boolean debug = args.containsOption("debug");
List<String> files = args.getNonOptionArgs();
// if run with "--debug logfile.txt" debug=true, files=["logfile.txt"]
}

}

Tip

Spring Boot 还向 Spring Environment注册了一个CommandLinePropertySource。这样,您还可以使用@Value注解注入单个应用程序参数。

使用ApplicationRunner或CommandLineRunner

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

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

1
2
3
4
5
6
7
8
9
10
11
import org.springframework.boot.*;
import org.springframework.stereotype.*;

@Component
public class MyBean implements CommandLineRunner {

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

}

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

应用退出

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@SpringBootApplication
public class ExitCodeApplication {

@Bean
public ExitCodeGenerator exitCodeGenerator() {
return () -> 42;
}

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

}

此外,ExitCodeGenerator接口可能会通过异常实现。遇到此类异常时,Spring Boot 将返回已实现的getExitCode()方法提供的退出代码。

管理员功能

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

Tip

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

Warning

启用此功能时要小心,因为 MBean 公开了一种关闭应用程序的方法。

外部化配置

Spring Boot使您可以外部化配置,以便可以在不同环境中使用相同的应用程序代码。您可以使用属性文件,YAML文件,环境变量和命令行参数来外部化配置。可以使用@Value注解将属性值直接注入到您的bean中,可以通过Spring的环境抽象进行访问,也可以通过@ConfigurationProperties绑定到结构化对象。

Spring Boot使用一个非常特殊的PropertySource顺序,该顺序旨在允许合理地覆盖值。按以下顺序考虑属性:

  1. 处于活动状态时,$HOME/.config/spring-boot目录中的Devtools全局设置属性。
  2. 测试上的@TestPropertySource注解。
  3. 测试中的properties属性。在@SpringBootTest和测试注解上可用,用于测试应用程序的特定部分
  4. 命令行参数。
  5. 来自SPRING_APPLICATION_JSON的属性(嵌入在环境变量或系统属性中的内联JSON)。
  6. ServletConfig的初始化参数。
  7. ServletContext的初始化参数。
  8. 来自java:comp/env的JNDI属性。
  9. Java系统属性(System.getProperties())。
  10. 操作系统环境变量。
  11. 一个RandomValuePropertySource,仅具有random.*属性。
  12. 打包的jar之外的特定于配置文件的应用程序属性application-{profile}.properties和YAML变体)。
  13. 打包在jar中的特定于配置文件的应用程序属性application-{profile}.properties和YAML变体)。
  14. 打包的jar之外的应用程序属性application.properties和YAML变体)。
  15. 打包在jar中的应用程序属性application.properties和YAML变体)。
  16. @Configuration类上的@PropertySource注解。请注意,在刷新应用程序上下文之前,不会将此类属性源添加到环境中。现在配置某些属性(如logging.*spring.main.*)为时已晚,这些属性在刷新开始之前就已读取。
  17. 默认属性(通过设置SpringApplication.setDefaultProperties`指定)。

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

1
2
3
4
5
6
7
8
9
10
11
12
import org.springframework.stereotype.*;
import org.springframework.beans.factory.annotation.*;

@Component
public class MyBean {

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

// ...

}

在您的应用程序 Classpath 上(例如,在 jar 内),您可以拥有一个application.properties文件,该文件为name提供了合理的默认属性值。在新环境中运行时,可以在 jar 外部提供application.properties文件,该文件将覆盖name。对于一次性测试,可以使用特定的命令行开关(例如java -jar app.jar --name="Spring")启动。

Tip

SPRING_APPLICATION_JSON属性可以在命令行中提供环境变量。例如,您可以在UNIX shell中使用以下行:

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

在前面的示例中,您在 SpringEnvironment中以acme.name=test结尾。您还可以在 System 属性中以spring.application.json的形式提供 JSON,如以下示例所示:

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

您还可以使用命令行参数来提供 JSON,如以下示例所示:

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

您还可以将 JSON 作为 JNDI 变量提供,如下所示:java:comp/env/spring.application.json

配置随机值

RandomValuePropertySource可用于注入随机值(例如,Importing 到机密或测试用例中)。它可以产生整数,longs,uuid 或字符串,如以下示例所示:

1
2
3
4
5
6
my.secret=${random.value}
my.number=${random.int}
my.bignumber=${random.long}
my.uuid=${random.uuid}
my.number.less.than.ten=${random.int(10)}
my.number.in.range=${random.int[1024,65536]}

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

访问命令行属性

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

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

应用程序属性文件

SpringApplication从以下位置的application.properties文件中加载属性,并将它们添加到 Spring Environment中:

  • 当前目录的/config子目录
  • 当前目录
  • Classpath/config
  • Classpath 根

该列表按优先级排序(在列表较高位置定义的属性会覆盖在较低位置定义的属性)。

Note

您也可以使用 YAML(‘.yml’)文件替代“ .properties”。

如果您不喜欢application.properties作为配置文件名,则可以通过指定spring.config.name环境属性来切换到另一个文件名。您还可以使用spring.config.location环境属性(这是目录位置或文件路径的逗号分隔列表)来引用显式位置。下面的示例演示如何指定其他文件名:

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

下面的示例演示如何指定两个位置:

1
$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties

Warning

spring.config.namespring.config.location很早就用于确定必须加载哪些文件,因此必须将它们定义为环境属性(通常是 OS 环境变量,系统属性或命令行参数)。

如果spring.config.location包含目录(而不是文件),则它们应以/结尾(并且在运行时,应在加载之前附加从spring.config.name生成的名称,包括特定于配置文件的文件名)。 spring.config.location中指定的文件按原样使用,不支持特定于配置文件的变体,并且被任何特定于配置文件的属性覆盖。

配置位置以相反的顺序搜索。默认情况下,配置的位置是classpath:/,classpath:/config/,file:./,file:./config/。结果搜索顺序如下:

  • file:./config/
  • file:./
  • classpath:/config/
  • classpath:/

使用spring.config.location配置自定义配置位置后,它们将替换默认位置。例如,如果将spring.config.location配置为值classpath:/custom-config/,file:./custom-config/,则搜索顺序如下:

  • file:./custom-config/
  • classpath:custom-config/

或者,当使用spring.config.additional-location配置自定义配置位置时,除默认位置外还使用它们。在默认位置之前搜索其他位置。例如,如果配置了classpath:/custom-config/,file:./custom-config/的其他位置,则搜索顺序如下:

  • file:./custom-config/
  • classpath:custom-config/
  • file:./config/
  • file:./
  • classpath:/config/
  • classpath:/

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

Note

如果使用环境变量而不是系统属性,则大多数操作系统都不允许使用句点分隔的键名,但可以使用下划线代替(例如,SPRING_CONFIG_NAME代替spring.config.name)。

Note

如果您的应用程序在容器中运行,则可以使用 JNDI 属性(在java:comp/env中)或 servlet 上下文初始化参数来代替环境变量或系统属性,也可以使用它们。

特定于配置文件的属性

除了application.properties个文件之外,还可以使用以下命名约定来定义特定于配置文件的属性:application-{profile}.propertiesEnvironment具有一组默认配置文件(默认情况下为[default]),如果未设置任何 Active 配置文件,则使用这些配置文件。换句话说,如果未显式激活任何配置文件,则将加载application-default.properties中的属性。

特定于配置文件的属性是从与标准application.properties相同的位置加载的,特定于配置文件的文件总是会覆盖非特定文件,无论特定于配置文件的文件是在打包 jar 的内部还是外部。

如果指定了多个配置文件,则采用后赢策略。例如,由spring.profiles.active属性指定的配置文件将添加到通过SpringApplication API 配置的配置文件之后,因此具有优先权。

Note

如果您在spring.config.location中指定了任何文件,则不会考虑这些文件的特定于配置文件的变体。如果您还想使用特定于配置文件的属性,请使用spring.config.location中的目录。

属性中的占位符

application.properties中的值在使用时会通过现有的Environment进行过滤,因此您可以参考以前定义的值(例如,从“系统”属性中)。

1
2
app.name=MyApp
app.description=${app.name} is a Spring Boot application

Tip

您还可以使用此技术来创建现有 Spring Boot 属性的“简短”变体。有关详细信息,请参见 “使用’短’命令行参数” 操作方法。

加密属性

Spring Boot 不提供对加密属性值的任何内置支持,但是,它确实提供了修改 Spring Environment中包含的值所必需的钩子点。 EnvironmentPostProcessor界面允许您在应用程序启动之前操纵Environment。有关详情,请参见“在启动前自定义环境或 ApplicationContext”

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

使用YAML代替属性

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

Note

如果您使用“Starter”,则spring-boot-starter自动提供 SnakeYAML。

加载YAML

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

例如,考虑以下 YAML 文档:

1
2
3
4
5
6
7
environments:
dev:
url: http://dev.example.com
name: Developer Setup
prod:
url: http://another.example.com
name: My Cool App

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

1
2
3
4
environments.dev.url=http://dev.example.com
environments.dev.name=Developer Setup
environments.prod.url=http://another.example.com
environments.prod.name=My Cool App

YAML 列表表示为带有[index]解引用器的属性键。例如,考虑以下 YAML:

1
2
3
4
my:
servers:
- dev.example.com
- another.example.com

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

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

要使用 Spring Boot 的BinderUtil(即@ConfigurationProperties所做的)绑定到类似的属性,您需要在java.util.List(或Set)类型的目标 bean 中具有一个属性,并且需要提供 setter 或使用 a 初始化它。可变值。例如,以下示例绑定到前面显示的属性:

1
2
3
4
5
6
7
8
9
@ConfigurationProperties(prefix="my")
public class Config {

private List<String> servers = new ArrayList<String>();

public List<String> getServers() {
return this.servers;
}
}

在Spring环境中将YAML公开为属性

YamlPropertySourceLoader类可用于在 Spring Environment中将 YAML 公开为PropertySource。这样做使您可以将@Value注解与占位符语法一起使用以访问 YAML 属性。

多配置文件YAML文档

您可以使用spring.profiles键在一个文件中指定多个特定于配置文件的 YAML 文档,以指示何时应用该文档,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
server:
address: 192.168.1.100
---
spring:
profiles: development
server:
address: 127.0.0.1
---
spring:
profiles: production & eu-central
server:
address: 192.168.1.120

在前面的示例中,如果development配置文件处于 Active 状态,则server.address属性为127.0.0.1。同样,如果productioneu-central配置文件处于 Active 状态,则server.address属性为192.168.1.120。如果developmentproductioneu-central配置文件未启用,则该属性的值为192.168.1.100

Note

因此spring.profiles可以包含一个简单的配置文件名称(例如production)或一个配置文件表达式。配置文件表达式允许表达更复杂的配置文件逻辑,例如production & (eu-central | eu-west)。查看reference guide以获取更多详细信息。

如果在启动应用程序上下文时未明确激活任何 Active,则会激活默认配置文件。因此,在以下 YAML 中,我们为spring.security.user.password设置了一个值,该值仅在“默认”配置文件中可用:

1
2
3
4
5
6
7
8
server:
port: 8000
---
spring:
profiles: default
security:
user:
password: weak

而在以下示例中,始终设置密码是因为该密码未附加到任何配置文件,并且必须根据需要在所有其他配置文件中将其显式重置:

1
2
3
4
5
6
server:
port: 8000
spring:
security:
user:
password: weak

Spring配置文件可以被spring.profile元素通过使用!字符被随意否定。如果为单个文档同时指定了否定配置文件和非否定配置文件,则必须至少匹配一个非否定配置文件,并且不能匹配任何否定配置文件。

YAML缺点

无法使用@PropertySource注解加载YAML文件。因此,在需要以这种方式加载值的情况下,需要使用属性文件。

类型安全的配置属性

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

参考@ConfigurationProperties与@Value的不同

JavaBean属性绑定

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.example;

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("acme")
public class AcmeProperties {

private boolean enabled;

private InetAddress remoteAddress;

private final Security security = new Security();

public boolean isEnabled() { ... }

public void setEnabled(boolean enabled) { ... }

public InetAddress getRemoteAddress() { ... }

public void setRemoteAddress(InetAddress remoteAddress) { ... }

public Security getSecurity() { ... }

public static class Security {

private String username;

private String password;

private List<String> roles = new ArrayList<>(Collections.singleton("USER"));

public String getUsername() { ... }

public void setUsername(String username) { ... }

public String getPassword() { ... }

public void setPassword(String password) { ... }

public List<String> getRoles() { ... }

public void setRoles(List<String> roles) { ... }

}
}

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

  • acme.enabled,默认值为false
  • acme.remote-address,其类型可以从String强制转换。
  • acme.security.username,带有嵌套的“安全”对象,其名称由属性名称确定。特别是,返回类型在那里根本不使用,可能是SecurityProperties
  • acme.security.password .
  • acme.security.roles,集合为String

Note

映射到Spring Boot中可用的@ConfigurationProperties类的属性(通过属性文件、YAML文件、环境变量等配置)是公共API,但类本身的访问器(getter /setter)并不打算直接使用。

Note

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

  • 映射,只要它们被初始化,就需要一个getter,但不一定是setter,因为它们可以被绑定器改变。
  • 可以通过索引(通常使用YAML)或使用逗号分隔的值(属性)访问集合和数组。在后一种情况下,setter是必需的。我们建议始终为此类类型添加setter。如果初始化一个集合,请确保它不是不可变的(如前面的示例所示)。
  • 如果初始化了嵌套的POJO属性(如前面示例中的Security字段),则不需要setter。如果希望绑定器使用其默认构造函数动态创建实例,则需要一个setter。

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

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

构造器绑定

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.example;

import java.net.InetAddress;
import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
import org.springframework.boot.context.properties.bind.DefaultValue;

@ConstructorBinding
@ConfigurationProperties("acme")
public class AcmeProperties {

private final boolean enabled;

private final InetAddress remoteAddress;

private final Security security;

public AcmeProperties(boolean enabled, InetAddress remoteAddress, Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}

public boolean isEnabled() { ... }

public InetAddress getRemoteAddress() { ... }

public Security getSecurity() { ... }

public static class Security {

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

public String getUsername() { ... }

public String getPassword() { ... }

public List<String> getRoles() { ... }

}

}

在这个设置中,@ConstructorBinding注解用于指示应该使用构造函数绑定。这意味着绑定器将期望找到具有您希望绑定的参数的构造器。

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

可以使用@DefaultValue指定默认值,并且将应用相同的转换服务将字符串值强制转换为缺失属性的目标类型。默认情况下,如果没有属性绑定到安全性,则AcmeProperties实例将包含用于安全性的null。如果你希望你返回一个非空的安全实例,即使没有属性绑定到它,你可以使用一个空的@DefaultValue注解这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.example;
import java.net.InetAddress;
import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
import org.springframework.boot.context.properties.bind.DefaultValue;

@ConstructorBinding
@ConfigurationProperties("acme")
public class AcmeProperties {

private final boolean enabled;

private final InetAddress remoteAddress;

private final Security security;

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

Note

要使用构造函数绑定,必须使用@EnableConfigurationProperties或配置属性扫描启用该类。不能使用构造函数绑定由常规Spring机制创建的bean(例如@Component bean、通过@Bean方法创建的bean或使用@Import加载的bean)

Tips

如果您的类有多个构造函数,您也可以在应该绑定的构造函数上直接使用@ConstructorBinding

Note

java.util.Optional@ConfigurationProperties一块使用是不推荐使用,因为它主要用于作为返回类型。因此,它并不非常适合配置属性注入。为了与其他类型的属性保持一致,如果您声明了一个Optional属性,但它没有值,那么将绑定null而不是空Optional属性。

开启ConfigurationProperties-annotated注解类型

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

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

1
2
3
4
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(AcmeProperties.class)
public class MyConfiguration {
}

要使用配置属性扫描,请在应用程序中添加@ConfigurationPropertiesScan注解。通常,它被添加到用@SpringBootApplication注解的主应用程序类中,但是它可以添加到任何@Configuration类中。默认情况下,扫描将从声明注解的类的包中进行。如果您想要定义特定的包来扫描,您可以这样做,如下面的例子所示:

1
2
3
4
@SpringBootApplication
@ConfigurationPropertiesScan({ "com.example.app", "org.acme.another" })
public class MyApplication {
}

Note

@ConfigurationProperties bean注册使用配置属性扫描或通过@EnableConfigurationProperties bean有一个惯用名称:<prefix>-<fqn>, <prefix>是环境关键@ConfigurationProperties注解中指定的前缀和< fqn >是完全限定的bean的名称。如果注解不提供任何前缀,则只使用bean的完全限定名。

上面示例中的bean名是acme-com.example.AcmeProperties

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

使用ConfigurationProperties-annotated注解类型

这种配置风格在SpringApplication的外部YAML配置中工作得特别好,如下面的示例所示:

1
2
3
4
5
6
7
8
9
10
11
# application.yml

acme:
remote-address: 192.168.1.1
security:
username: admin
roles:
- USER
- ADMIN

# additional configuration as required

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Service
public class MyService {

private final AcmeProperties properties;

@Autowired
public MyService(AcmeProperties properties) {
this.properties = properties;
}

//...

@PostConstruct
public void openConnection() {
Server server = new Server(this.properties.getRemoteAddress());
// ...
}

}

Note

使用@ConfigurationProperties还可以让您生成元数据文件,IDEs可以使用这些元数据文件为您自己的键提供自动完成功能。详见附录

第三方配置

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

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

1
2
3
4
5
@ConfigurationProperties(prefix = "another")
@Bean
public AnotherComponent anotherComponent() {
...
}

another前缀定义的任何属性都以类似于前面AcmeProperties示例的方式 Map 到该AnotherComponent bean。

宽松绑定

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

例如,考虑以下@ConfigurationProperties类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@ConfigurationProperties(prefix="acme.my-project.person")
public class OwnerProperties {

private String firstName;

public String getFirstName() {
return this.firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

}

在前面的示例中,可以全部使用以下属性名称:

表 24.1. Relaxed绑定

Property Note
acme.my-project.person.first-name Kebab 情况,建议在.properties.yml文件中使用。
acme.myProject.person.firstName 标准驼峰式语法。
acme.my_project.person.first_name 下划线表示法,是在.properties.yml文件中使用的另一种格式。
ACME_MYPROJECT_PERSON_FIRSTNAME 大写格式,使用系统环境变量时建议使用。

Note

注解*的prefix值必须为 kebab(小写并由-分隔,例如acme.my-project.person)。

表 24.2. 每个资源来源的宽松绑定规则

Property Source Simple List
Properties Files 骆驼案,烤肉串案或下划线 使用[ ]或逗号分隔值的标准列表语法
YAML Files 骆驼案,烤肉串案或下划线 标准 YAML 列表语法或逗号分隔的值
Environment Variables 以下划线作为定界符的大写格式。 _不应在属性名称中使用 带有下划线的数字值,例如MY_ACME_1_OTHER = my.acme[1].other
System properties 骆驼案,烤肉串案或下划线 使用[ ]或逗号分隔值的标准列表语法

Tip

我们建议,如果可能的话,属性以小写的 kebab 格式存储,例如my.property-name=acme

Binding Maps

绑定到Map属性时,如果key包含小写字母数字字符或-以外的任何内容,则需要使用方括号表示法,以便保留原始值。如果键没有被[]包围,则所有非字母数字或-的字符都将被删除。例如,考虑将以下属性绑定到Map

1
2
3
4
5
acme:
map:
"[/key1]": value1
"[/key2]": value2
/key3: value3

上面的属性将绑定到Map,其中/key1/key2key3作为 Map 中的键。

从环境变量绑定

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

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

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

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

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

  • 转换为大写。

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

Note

下划线不能用于替换属性名称中的破折号。如果您尝试在上面的示例中使用SPRING_MAIN_LOG_STARTUP_INFO,则不会绑定任何值。

在绑定到对象列表时,也可以使用环境变量。要绑定到列表,元素号应该在变量名中用下划线包围。

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

合并复杂类型

如果在多个位置配置了列表,则通过替换整个列表来进行覆盖。

例如,假设一个MyPojo对象的namedescription属性默认为null。以下示例公开了AcmeProperties中的MyPojo个对象的列表:

1
2
3
4
5
6
7
8
9
10
@ConfigurationProperties("acme")
public class AcmeProperties {

private final List<MyPojo> list = new ArrayList<>();

public List<MyPojo> getList() {
return this.list;
}

}

考虑以下配置:

1
2
3
4
5
6
7
8
9
10
acme:
list:
- name: my name
description: my description
---
spring:
profiles: dev
acme:
list:
- name: my another name

如果dev配置文件无效,则AcmeProperties.list包含一个MyPojo条目,如先前所定义。但是,如果启用了dev配置文件,则list 仍然仅包含一个条目(名称为my another name和描述为null)。此配置不会将第二个MyPojo实例添加到列表中,并且不会合并项目。

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

1
2
3
4
5
6
7
8
9
10
11
12
acme:
list:
- name: my name
description: my description
- name: another name
description: another description
---
spring:
profiles: dev
acme:
list:
- name: my another name

在前面的示例中,如果dev配置文件处于 Active 状态,则AcmeProperties.list包含 one MyPojo条目(名称为my another name且描述为null)。对于 YAML,可以使用逗号分隔的列表和 YAML 列表来完全覆盖列表的内容。

对于Map属性,您可以绑定从多个来源获取的属性值。但是,对于多个源中的同一属性,将使用优先级最高的属性。以下示例从AcmeProperties公开Map<String, MyPojo>

1
2
3
4
5
6
7
8
9
10
@ConfigurationProperties("acme")
public class AcmeProperties {

private final Map<String, MyPojo> map = new HashMap<>();

public Map<String, MyPojo> getMap() {
return this.map;
}

}

考虑以下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
acme:
map:
key1:
name: my name 1
description: my description 1
---
spring:
profiles: dev
acme:
map:
key1:
name: dev name 1
key2:
name: dev name 2
description: dev description 2

如果dev配置文件未激活,则AcmeProperties.map包含一个键为key1的条目(名称为my name 1和描述为my description 1)。但是,如果启用了dev配置文件,则map包含两个条目,其中包含键key1(名称为dev name 1my description 1的描述)和key2(名称为dev name 2dev description 2的描述)。

Note

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

属性转换

当 Spring Boot 绑定到@ConfigurationProperties bean 时,它尝试将外部应用程序属性强制为正确的类型。如果需要自定义类型转换,则可以提供ConversionService bean(使用名为conversionService的 bean)或自定义属性编辑器(通过CustomEditorConfigurer bean)或自定义Converters(将 bean 定义标注为@ConfigurationPropertiesBinding)。

Note

由于在应用程序生命周期中非常早就请求了此 bean,因此请确保限制您的ConversionService使用的依赖项。通常,您需要的任何依赖项可能在创建时未完全初始化。如果配置键强制不需要自定义ConversionService,而只依赖于具有@ConfigurationPropertiesBinding限定的自定义转换器,则可能要重命名。

Convertingdurations

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

  • 常规long表示形式(使用毫秒作为默认单位,除非已指定@DurationUnit)
  • 标准 ISO-8601 格式由 java.util.Duration 使用
  • 值和单位相结合的更易读的格式(例如10s表示 10 秒)

考虑以下示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@ConfigurationProperties("app.system")
public class AppSystemProperties {

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

private Duration readTimeout = Duration.ofMillis(1000);

public Duration getSessionTimeout() {
return this.sessionTimeout;
}

public void setSessionTimeout(Duration sessionTimeout) {
this.sessionTimeout = sessionTimeout;
}

public Duration getReadTimeout() {
return this.readTimeout;
}

public void setReadTimeout(Duration readTimeout) {
this.readTimeout = readTimeout;
}

}

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

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

  • ns纳秒
  • us微秒
  • ms毫秒
  • s
  • m分钟
  • h小时
  • d

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

Tip

如果要从仅使用Long表示持续时间的先前版本进行升级,请确保在切换到Duration的时间不是毫秒的情况下(使用@DurationUnit)定义单位。这样做可以提供透明的升级路径,同时支持更丰富的格式。

转换数据大小

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

  • 常规的long表示形式(除非已指定@DataSizeUnit,否则使用字节作为默认单位)
  • 值和单位耦合在一起的更具可读性的格式(例如10MB表示 10 兆字节)

考虑以下示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@ConfigurationProperties("app.io")
public class AppIoProperties {

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

private DataSize sizeThreshold = DataSize.ofBytes(512);

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

}

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

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

  • B个字节
  • KB千字节
  • MB代表兆字节
  • GB代表千兆字节
  • TB代表兆兆字节

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

Tip

如果要从仅使用Long表示大小的先前版本进行升级,请确保在切换到DataSize的旁边不是字节的情况下定义单位(使用@DataSizeUnit)。这样做可以提供透明的升级路径,同时支持更丰富的格式。

ConfigurationProperties注解验证

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

1
2
3
4
5
6
7
8
9
10
@ConfigurationProperties(prefix="acme")
@Validated
public class AcmeProperties {

@NotNull
private InetAddress remoteAddress;

// ... getters and setters

}

Tip

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

尽管嵌套属性在绑定时也会被验证,但是最好将关联的字段注解为@Valid。这样可以确保即使没有嵌套属性也可以触发验证。以下示例基于前面的AcmeProperties示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@ConfigurationProperties(prefix="acme")
@Validated
public class AcmeProperties {

@NotNull
private InetAddress remoteAddress;

@Valid
private final Security security = new Security();

// ... getters and setters

public static class Security {

@NotEmpty
public String username;

// ... getters and setters

}

}

您还可以通过创建名为configurationPropertiesValidator的 bean 定义来添加自定义 Spring Validator@Bean方法应声明为static。配置属性验证器是在应用程序生命周期的早期创建的,并且将@Bean方法声明为静态方法可以使 Bean 得以创建而不必实例化@Configuration类。这样做可以避免因早期实例化而引起的任何问题。有一个属性验证 samples显示了如何进行设置。

Tip

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

ConfigurationProperties注解与Value注解

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

Feature @ConfigurationProperties @Value
Relaxed binding Yes No
Meta-data support Yes No
SpEL评估 No Yes

如果您为自己的组件定义了一组配置键,我们建议您将它们组合在以@ConfigurationProperties注解的 POJO 中。您还应该意识到,由于@Value不支持宽松的绑定,因此如果您需要使用环境变量来提供值,则它不是很好的选择。

最后,尽管您可以在@Value中编写SpEL表达式,但不会从应用程序属性文件处理此类表达式。

Profiles

Spring Profiles 提供了一种隔离应用程序配置的各部分并使之仅在某些环境中可用的方法。可以用@Profile标记任何@Component@Configuration以限制其什么时候被加载,如以下示例所示:

1
2
3
4
5
6
7
@Configuration
@Profile("production")
public class ProductionConfiguration {

// ...

}

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

1
spring.profiles.active=dev,hsqldb

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

添加Active配置文件

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

有时,将特定于配置文件的属性“添加”到 Active 配置文件而不是替换它们很有用。 spring.profiles.include属性可用于无条件添加 Active 配置文件。 SpringApplication入口点还具有 Java API,用于设置其他配置文件(即,在spring.profiles.active属性激活的配置文件之上)。请参见SpringApplication中的setAdditionalProfiles()方法。

例如,当使用开关--spring.profiles.active=prod运行具有以下属性的应用程序时,还将激活proddbprodmq配置文件:

1
2
3
4
5
6
7
---
my.property: fromyamlfile
---
spring.profiles: prod
spring.profiles.include:
- proddb
- prodmq

Note

请记住,可以在 YAML 文档中定义spring.profiles属性,以确定何时将该特定文档包括在配置中。有关更多详细信息,请参见“根据环境更改配置”

以编程方式设置配置文件

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

特定于配置文件的配置文件

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

日志

Spring引导对所有内部日志使用Commons Logging,但保留底层日志实现。为Java Util 记录Log4J2Logback提供了默认配置。在每种情况下,Logger 都已预先配置为使用控制台输出,同时还提供可选文件输出。

默认情况下,如果使用“启动器”,则使用 Logback 进行日志记录。还包括适当的 Logback 路由,以确保使用 Java Util Logging,Commons Logging,Log4J 或 SLF4J 的从属库均能正常工作。

Tip

有许多可用于 Java 的日志记录框架。如果上面的列表看起来令人困惑,请不要担心。通常,您不需要更改日志记录依赖项,并且 Spring Boot 默认值可以正常工作。

日志格式

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

1
2
3
4
5
2014-03-05 10:57:51.112  INFO 45469 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/7.0.52
2014-03-05 10:57:51.253 INFO 45469 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2014-03-05 10:57:51.253 INFO 45469 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1358 ms
2014-03-05 10:57:51.698 INFO 45469 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2014-03-05 10:57:51.702 INFO 45469 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]

输出以下项目:

  • 日期和时间:毫秒精度,易于排序。
  • 日志级别:ERRORWARNINFODEBUGTRACE
  • Process ID.
  • ---分隔符用于区分实际日志消息的开始。
  • 线程名称:用方括号括起来(对于控制台输出可能会被截断)。
  • Logger 名称:这通常是源类名称(通常缩写)。
  • 日志消息。

Note

Logback 没有FATAL级别。它 Map 到ERROR

控制台输出

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

1
$ java -jar myapp.jar --debug

Note

您也可以在application.properties中指定debug=true

启用调试模式后,将配置一些核心 Logger(嵌入式容器,Hibernate 和 Spring Boot)以输出更多信息。启用调试模式不会将您的应用程序配置为记录所有具有DEBUG级的消息。

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

颜色编码的输出

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

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

1
%clr(%5p)

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

Level Color
FATAL Red
ERROR Red
WARN Yellow
INFO Green
DEBUG Green
TRACE Green

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

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

支持以下颜色和样式:

  • blue
  • cyan
  • faint
  • green
  • magenta
  • red
  • yellow

文件输出

默认情况下,Spring Boot 仅记录到控制台,不写日志文件。如果除了控制台输出外还想写入日志文件,则需要设置logging.filelogging.path属性(例如,在application.properties中)。

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

表 26.1 记录属性

logging.file logging.path Example Description
(none) (none) 仅控制台记录。
Specific file (none) my.log 写入指定的日志文件。名称可以是确切的位置,也可以相对于当前目录。
(none) Specific directory /var/log spring.log写入指定的目录。名称可以是确切的位置,也可以相对于当前目录。

日志文件达到 10 MB 时会旋转,并且与控制台输出一样,默认记录ERROR -level,WARN -level 和INFO -level 消息。大小限制可以使用logging.file.max-size属性更改。除非已设置logging.file.max-history属性,否则以前旋转的文件将无限期存档。

Note

日志记录系统在应用程序生命周期的早期进行了初始化。因此,在通过@PropertySource注解加载的属性文件中找不到日志记录属性。

Tip

日志记录属性与实际的日志记录基础结构无关。结果,Spring Boot 不会管理特定的配置密钥(例如 Log 的logback.configurationFile)。

日志级别

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

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

1
2
3
logging.level.root=WARN
logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=ERROR

日志组

能够将相关 Logger 组合在一起通常很有用,以便可以同时配置它们。例如,您可能通常会更改与 Tomcat 相关的所有 Logger 的日志记录级别,但是您不容易记住顶级软件包。

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

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

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

1
logging.level.tomcat=TRACE

Spring Boot 包含以下 sched 义的日志记录组,它们可以直接使用:

Name Loggers
web org.springframework.core.codec , org.springframework.http , org.springframework.web
sql org.springframework.jdbc.core , org.hibernate.SQL

自定义日志配置

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

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

Note

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

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

Logging System Customization
Logback logback-spring.xmllogback-spring.groovylogback.xmllogback.groovy
Log4j2 log4j2-spring.xmllog4j2.xml
JDK(Java Util 日志记录) logging.properties

Note

如果可能,我们建议您将-spring变体用于日志记录配置(例如logback-spring.xml而不是logback.xml)。如果使用标准配置位置,Spring 将无法完全控制日志初始化。

Warning

从“可执行 jar”运行时,Java Util Logging 存在一些已知的类加载问题,这些问题会引起问题。我们建议您尽可能从“可执行 jar”运行时避免使用它。

为了帮助进行自定义,如下表所述,一些其他属性从 Spring Environment转移到 System 属性:

Spring Environment System Property Comments
logging.exception-conversion-word LOG_EXCEPTION_CONVERSION_WORD 记录异常时使用的转换字。
logging.file LOG_FILE 如果定义,它将在默认日志配置中使用。
logging.file.max-size LOG_FILE_MAX_SIZE 最大日志文件大小(如果启用了 LOG_FILE)。 (仅默认登录设置支持.)
logging.file.max-history LOG_FILE_MAX_HISTORY 要保留的最大归档日志文件数(如果启用了 LOG_FILE)。 (仅默认登录设置支持.)
logging.path LOG_PATH 如果定义,它将在默认日志配置中使用。
logging.pattern.console CONSOLE_LOG_PATTERN 在控制台上使用的日志模式(stdout)。 (仅默认登录设置支持.)
logging.pattern.dateformat LOG_DATEFORMAT_PATTERN 记录日期格式的附加模式。 (仅默认登录设置支持.)
logging.pattern.file FILE_LOG_PATTERN 文件中使用的日志模式(如果启用了LOG_FILE)。 (仅默认登录设置支持.)
logging.pattern.level LOG_LEVEL_PATTERN 渲染日志级别时使用的格式(默认为%5p)。 (仅默认登录设置支持.)
PID PID 当前进程 ID(如果可能,并且尚未将其定义为 OS 环境变量时发现)。

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

Tip

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

Tip

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

1
2
2015-09-30 12:30:04.031 user:someone INFO 22174 --- [  nio-8080-exec-0] demo.Controller
Handling authenticated request

Logback扩展

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

Note

由于标准logback.xml配置文件加载时间过早,因此无法在其中使用 extensions。您需要使用logback-spring.xml或定义logging.config属性。

Warning

这些扩展不能与 Logback 的configuration scanning一起使用。如果尝试这样做,则对配置文件进行更改将导致类似于以下记录之一的错误记录:

1
2
ERROR in [emailprotected]:71 - no applicable action for [springProperty], current ElementPath is [[configuration][springProperty]]
ERROR in [emailprotected]:71 - no applicable action for [springProfile], current ElementPath is [[configuration][springProfile]]

特定于配置文件的配置

<springProfile>标签可让您根据有效的 Spring 配置文件有选择地包括或排除配置部分。 <configuration>元素中任何位置都支持概要文件部分。使用name属性指定哪个配置文件接受配置。 <springProfile>标记可以包含一个简单的配置文件名称(例如staging)或一个配置文件表达式。配置文件表达式允许表达更复杂的配置文件逻辑,例如production & (eu-central | eu-west)。查看reference guide以获取更多详细信息。以下 Lists 显示了三个 samples 概要文件:

1
2
3
4
5
6
7
8
9
10
11
<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>

环境属性

<springProperty>标签可让您公开 Spring Environment中的属性,以供在 Logback 中使用。如果要从 Logback 配置中访问application.properties文件中的值,则这样做很有用。该标记的工作方式类似于 Logback 的标准<property>标记。但是,不是指定直接的value,而是指定属性的source(来自Environment)。如果需要将属性存储在local范围以外的其他位置,则可以使用scope属性。如果需要回退值(如果未在Environment中设置该属性),则可以使用defaultValue属性。以下示例显示如何公开用于 Logback 的属性:

1
2
3
4
5
6
<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>

Note

source必须在烤肉串情况下指定(例如my.property-name)。但是,可以使用宽松规则将属性添加到Environment

国际化

Spring Boot支持本地化消息,这样您的应用程序就可以满足不同语言偏好的用户。默认情况下,Spring Boot在类路径的根查找是否存在消息资源束。

Note

当配置的资源包的默认属性文件可用时(默认message.properties),自动配置就会应用。如果资源包只包含特定于语言的属性文件,则需要添加缺省值。如果没有找到匹配任何配置的基本名称的属性文件,那么就不会有自动配置的MessageSource

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

1
2
spring.messages.basename=messages,config.i18n.messages
spring.messages.fallback-to-system-locale=false

spring.messages.basename支持以逗号分隔的位置列表,可以是包限定符,也可以是从类路径根解析出来的资源。

关更多受支持的选项,请参见MessageSourceProperties

JSON

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

  • Gson
  • Jackson
  • JSON-B

Jackson 是首选的默认库。

Jackson

提供了 Jackson 的自动配置功能,并且 Jackson 是spring-boot-starter-json的一部分。当 Jackson 放在 Classpath 上时,会自动配置ObjectMapper bean。为定制 ObjectMapper 的配置提供了几个配置属性。

Gson

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

JSON-B

提供了 JSON-B 的自动配置。当 JSON-B API 和实现位于 Classpath 上时,将自动配置Jsonb bean。首选的 JSON-B 实现是提供依赖 Management 的 Apache Johnzon。

开发Web应用程序

Spring Boot 非常适合 Web 应用程序开发。您可以使用嵌入式 Tomcat,Jetty,Undertow 或 Netty 创建独立的 HTTP 服务器。大多数 Web 应用程序都使用spring-boot-starter-web模块来快速启动和运行。您还可以选择使用spring-boot-starter-webflux模块来构建响应式 Web 应用程序。

如果尚未开发 Spring Boot Web 应用程序,则可以遵循“ Hello World!”。 Getting started部分中的示例。

SpringWebMVC框架

Spring Web MVC 框架(通常简称为“ Spring MVC”)是一个丰富的“模型视图控制器” Web 框架。 Spring MVC 使您可以创建特殊的@Controller@RestController bean 来处理传入的 HTTP 请求。控制器中的方法通过使用@RequestMapping注解Map 到 HTTP。

以下代码显示了提供 JSON 数据的典型@RestController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@RestController
@RequestMapping(value="/users")
public class MyRestController {

@RequestMapping(value="/{user}", method=RequestMethod.GET)
public User getUser(@PathVariable Long user) {
// ...
}

@RequestMapping(value="/{user}/customers", method=RequestMethod.GET)
List<Customer> getUserCustomers(@PathVariable Long user) {
// ...
}

@RequestMapping(value="/{user}", method=RequestMethod.DELETE)
public User deleteUser(@PathVariable Long user) {
// ...
}

}

Spring MVC 是核心 Spring Framework 的一部分,有关详细信息,请参见reference documentationspring.io/guides提供了一些涵盖 Spring MVC 的指南。

SpringMVC自动配置

Spring Boot 为 Spring MVC 提供了自动配置,可与大多数应用程序完美配合。

自动配置在 Spring 的默认值之上添加了以下功能:

  • 包括ContentNegotiatingViewResolverBeanNameViewResolverbean。
  • 支持提供静态资源,包括对 WebJars 的支持(覆盖本文档后面
  • 自动注册ConverterGenericConverterFormatter bean。
  • 支持HttpMessageConverters(包含本文档后面
  • 自动注册MessageCodesResolver(已发现本文档后面
  • 静态index.html支持。
  • 自定义Favicon支持(包含本文档后面
  • 自动使用ConfigurableWebBindingInitializer bean(包含本文档后面

如果您想保留 Spring Boot MVC 功能,并且想要添加其他MVC configuration(拦截器,格式化程序,视图控制器和其他功能),则可以添加自己的@Configuration类,类型为WebMvcConfigurer,但是没有 @EnableWebMvc。如果希望提供RequestMappingHandlerMappingRequestMappingHandlerAdapterExceptionHandlerExceptionResolver的自定义实例,则可以声明WebMvcRegistrationsAdapter实例以提供此类组件。

如果要完全控制 Spring MVC,则可以添加自己的@Configuration并以@EnableWebMvc注解。

HttpMessageConverters

Spring MVC 使用HttpMessageConverter接口转换 HTTP 请求和响应。开箱即用中包含明智的默认设置。例如,可以将对象自动转换为 JSON(通过使用 Jackson 库)或 XML(通过使用 Jackson XML 扩展(如果可用)或通过使用 JAXB(如果 Jackson XML 扩展不可用))。默认情况下,字符串以UTF-8编码。

如果需要添加或定制转换器,则可以使用 Spring Boot 的HttpMessageConverters类,如以下 Lists 所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.context.annotation.*;
import org.springframework.http.converter.*;

@Configuration
public class MyConfiguration {

@Bean
public HttpMessageConverters customConverters() {
HttpMessageConverter<?> additional = ...
HttpMessageConverter<?> another = ...
return new HttpMessageConverters(additional, another);
}

}

上下文中存在的任何HttpMessageConverter bean 都将添加到转换器列表中。您也可以用相同的方法覆盖默认转换器。

自定义JSON序列化器和反序列化器

如果使用 Jackson 来序列化和反序列化 JSON 数据,则可能要编写自己的JsonSerializerJsonDeserializer类。自定义序列化器通常是通过模块在 Jackson 注册,但是 Spring Boot 提供了@JsonComponentComments,这使得直接注册 Spring Bean 更加容易。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.io.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import org.springframework.boot.jackson.*;

@JsonComponent
public class Example {

public static class Serializer extends JsonSerializer<SomeObject> {
// ...
}

public static class Deserializer extends JsonDeserializer<SomeObject> {
// ...
}

}

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

Spring Boot 还提供了JsonObjectSerializerJsonObjectDeserializerBase Class,这些 Base Class 在序列化对象时为标准 Jackson 版本提供了有用的替代方法。有关详细信息,请参见 Javadoc 中的JsonObjectSerializerJsonObjectDeserializer

MessageCodesResolver

Spring MVC 有一种生成错误代码的策略,该错误代码用于从绑定错误MessageCodesResolver渲染错误消息。如果设置spring.mvc.message-codes-resolver.format属性PREFIX_ERROR_CODEPOSTFIX_ERROR_CODE,Spring Boot 会为您创建一个(请参见DefaultMessageCodesResolver.Format中的枚举)。

静态内容

默认情况下,Spring Boot 从 Classpath 中名为/static(或/public/resources/META-INF/resources)的目录或ServletContext的根目录中提供静态内容。它使用 Spring MVC 中的ResourceHttpRequestHandler,因此您可以通过添加自己的WebMvcConfigurer并覆盖addResourceHandlers方法来修改该行为。

在独立的 Web 应用程序中,还启用了容器中的默认 servlet,并将其用作后备,如果 Spring 决定不处理ServletContext的根,则从ServletContext的根开始提供内容。在大多数情况下,这不会发生(除非您修改默认的 MVC 配置),因为 Spring 始终可以通过DispatcherServlet处理请求。

默认情况下,资源 Map 在/**上,但是您可以使用spring.mvc.static-path-pattern属性对其进行调整。例如,将所有资源重定位到/resources/**可以实现如下:

1
spring.mvc.static-path-pattern=/resources/**

您还可以使用spring.resources.static-locations属性来自定义静态资源位置(用目录位置列表替换默认值)。根 Servlet 上下文路径"/"也会自动添加为位置。

除了前面提到的“标准”静态资源位置以外,还对Webjars content进行了特殊处理。如果 jar 文件以 Webjars 格式打包,则从 jar 文件提供带有/webjars/**路径的任何资源。

Tip

如果您的应用程序打包为 jar,则不要使用src/main/webapp目录。尽管此目录是一个通用标准,但它仅在 war 打包中有效,并且在生成 jar 时,大多数构建工具都将其忽略。

Spring Boot 还支持Spring MVC提供的高级资源处理功能,允许使用案例,例如缓存清除静态资源或对 Webjars 使用版本无关的 URL。

要对 Webjar 使用版本无关的 URL,请添加webjars-locator-core依赖项。然后声明您的 Webjar。以 jQuery 为例,在"/webjars/jquery/x.y.z/jquery.min.js"中添加"/webjars/jquery/jquery.min.js"结果。其中x.y.z是 Webjar 版本。

Note

如果使用 JBoss,则需要声明webjars-locator-jboss-vfs依赖性而不是webjars-locator-core。否则,所有 Webjar 都解析为404

要使用缓存清除,以下配置为所有静态资源配置了缓存清除解决方案,从而有效地在 URL 中添加了内容哈希,例如<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>

1
2
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**

Note

得益于为 Thymeleaf 和 FreeMarker 自动配置的ResourceUrlEncodingFilter,在运行时将资源链接重写为模板。使用 JSP 时,您应该手动声明此过滤器。当前不自动支持其他模板引擎,但可以与自定义模板宏/帮助器一起使用,并可以使用ResourceUrlProvider

例如,当使用 JavaScript 模块加载器动态加载资源时,不能重命名文件。这就是为什么其他策略也受支持并且可以组合的原因。 “固定”策略在 URL 中添加静态版本字符串,而不会更改文件名,如以下示例所示:

1
2
3
4
5
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
spring.resources.chain.strategy.fixed.enabled=true
spring.resources.chain.strategy.fixed.paths=/js/lib/
spring.resources.chain.strategy.fixed.version=v12

通过这种配置,位于"/js/lib/"下的 JavaScript 模块使用固定的版本控制策略("/v12/js/lib/mymodule.js"),而其他资源仍使用内容版本(<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>)。

有关更多受支持的选项,请参见ResourceProperties

Tip

此功能已在专用的blog post和 Spring Framework 的reference documentation中进行了详细描述。

欢迎页面

Spring Boot 支持静态和模板欢迎页面。它首先在配置的静态内容位置中查找index.html文件。如果未找到,则它将寻找index模板。如果找到任何一个,它将自动用作应用程序的欢迎页面。

自定义图标

Spring Boot 在配置的静态内容位置和 Classpath 的根目录(按此 Sequences)中查找favicon.ico。如果存在这样的文件,它将自动用作应用程序的收藏夹图标。

路径匹配和内容协商

Spring MVC 可以通过查看请求路径并将其匹配到应用程序中定义的Map(例如 Controller 方法上的@GetMapping注解),将传入的 HTTP 请求 Map 到处理程序。

Spring Boot 默认选择禁用后缀模式匹配,这意味着诸如"GET /projects/spring-boot.json"之类的请求将不会与@GetMapping("/projects/spring-boot")Map 相匹配。这被视为Spring MVC 应用程序的最佳实践。过去,此功能主要用于未发送正确的“ Accept”请求 Headers 的 HTTP Client 端。我们需要确保将正确的 Content Type 发送给 Client 端。如今,内容协商已变得更加可靠。

还有其他处理 HTTP Client 端的方法,这些方法不能始终发送正确的“ Accept”请求 Headers。除了使用后缀匹配,我们还可以使用查询参数来确保将"GET /projects/spring-boot?format=json"之类的请求 Map 到@GetMapping("/projects/spring-boot")

1
2
3
4
5
6
7
spring.mvc.contentnegotiation.favor-parameter=true

# We can change the parameter name, which is "format" by default:
# spring.mvc.contentnegotiation.parameter-name=myparam

# We can also register additional file extensions/media types with:
spring.mvc.contentnegotiation.media-types.markdown=text/markdown

如果您了解了注意事项,但仍希望您的应用程序使用后缀模式匹配,则需要以下配置:

1
2
spring.mvc.contentnegotiation.favor-path-extension=true
spring.mvc.pathmatch.use-suffix-pattern=true

另外,与其打开所有后缀模式,不如只支持注册的后缀模式,这是更安全的:

1
2
3
4
5
spring.mvc.contentnegotiation.favor-path-extension=true
spring.mvc.pathmatch.use-registered-suffix-pattern=true

# You can also register additional file extensions/media types with:
# spring.mvc.contentnegotiation.media-types.adoc=text/asciidoc

ConfigurableWebBindingInitializer

Spring MVC 使用WebBindingInitializer来为特定请求初始化WebDataBinder。如果创建自己的ConfigurableWebBindingInitializer @Bean,Spring Boot 会自动将 Spring MVC 配置为使用它。

模板引擎

除了 REST Web 服务之外,您还可以使用 Spring MVC 来提供动态 HTML 内容。 Spring MVC 支持各种模板技术,包括 Thymeleaf,FreeMarker 和 JSP。同样,许多其他模板引擎包括他们自己的 Spring MVC 集成。

Spring Boot 包括对以下模板引擎的自动配置支持:

Tip

如果可能,应避免使用 JSP。与嵌入式 servlet 容器一起使用时,有多个known limitations

当您使用默认配置的这些模板引擎之一时,将从src/main/resources/templates自动拾取模板。

Tip

根据您运行应用程序的方式,IntelliJ IDEA 对 Classpath 的排序方式不同。与使用 MavenGradle 或从打包的 jar 运行应用程序时,从 IDE 的 Main 方法运行应用程序的 Sequences 会有所不同。这可能会导致 Spring Boot 无法在 Classpath 上找到模板。如果遇到此问题,则可以在 IDE 中重新排序 Classpath,以首先放置模块的类和资源。另外,您可以配置模板前缀以搜索 Classpath 上的每个templates目录,如下所示:classpath*:/templates/

错误处理

默认情况下,Spring Boot 提供了一个/errorMap,可以明智地处理所有错误,并且已在 servlet 容器中注册为“全局”错误页面。对于机器 Client 端,它将生成 JSON 响应,其中包含错误,HTTP 状态和异常消息的详细信息。对于浏览器 Client 端,存在一个“ whitelabel”错误视图,该视图以 HTML 格式渲染相同的数据(要对其进行自定义,请添加解析为errorView)。要完全替换默认行为,可以实现ErrorController并注册该类型的 Bean 定义,或添加ErrorAttributes类型的 Bean 以使用现有机制但替换其内容。

Tip

BasicErrorController可用作自定义ErrorController的 Base Class。如果要为新的 Content Type 添加处理程序(默认是专门处理text/html并为其他所有内容提供后备功能),则此功能特别有用。为此,扩展BasicErrorController,添加具有produces属性的@RequestMapping的公共方法,并创建新类型的 bean。

您还可以定义带有@ControllerAdvice注解的类,以自定义 JSON 文档以针对特定的控制器和/或异常类型返回,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@ControllerAdvice(basePackageClasses = AcmeController.class)
public class AcmeControllerAdvice extends ResponseEntityExceptionHandler {

@ExceptionHandler(YourException.class)
@ResponseBody
ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {
HttpStatus status = getStatus(request);
return new ResponseEntity<>(new CustomErrorType(status.value(), ex.getMessage()), status);
}

private HttpStatus getStatus(HttpServletRequest request) {
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
if (statusCode == null) {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
return HttpStatus.valueOf(statusCode);
}

}

在前面的示例中,如果在与AcmeController相同的程序包中定义的控制器抛出YourException,则使用CustomErrorType POJO 的 JSON 表示代替ErrorAttributes表示。

自定义错误页面

如果要显示给定状态代码的自定义 HTML 错误页面,可以将文件添加到/error文件夹。错误页面可以是静态 HTML(即添加到任何静态资源文件夹下),也可以使用模板来构建。文件名应为确切的状态代码或系列掩码。

例如,要将404Map 到静态 HTML 文件,您的文件夹结构如下:

1
2
3
4
5
6
7
8
9
src/
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
+- <other public assets>

要使用 FreeMarker 模板 Map 所有5xx错误,您的文件夹结构如下:

1
2
3
4
5
6
7
8
9
src/
+- main/
+- java/
| + <source code>
+- resources/
+- templates/
+- error/
| +- 5xx.ftl
+- <other templates>

对于更复杂的 Map,还可以添加实现ErrorViewResolver接口的 bean,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
public class MyErrorViewResolver implements ErrorViewResolver {

@Override
public ModelAndView resolveErrorView(HttpServletRequest request,
HttpStatus status, Map<String, Object> model) {
// Use the request or status to optionally return a ModelAndView
return ...
}

}

您还可以使用常规的 Spring MVC 功能,例如@ExceptionHandler methods@ControllerAdviceErrorController然后接收任何未处理的异常。

MapSpringMVC之外的错误页面

对于不使用 Spring MVC 的应用程序,可以使用ErrorPageRegistrar接口直接注册ErrorPages。此抽象直接与基础嵌入式 servlet 容器一起使用,即使您没有 Spring MVC DispatcherServlet,也可以使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Bean
public ErrorPageRegistrar errorPageRegistrar(){
return new MyErrorPageRegistrar();
}

// ...

private static class MyErrorPageRegistrar implements ErrorPageRegistrar {

@Override
public void registerErrorPages(ErrorPageRegistry registry) {
registry.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400"));
}

}

Note

如果您注册的ErrorPage的路径最终由Filter处理(这在某些非 Spring Web 框架(如 Jersey 和 Wicket)中很常见),则必须将Filter明确注册为ERROR调度程序,如图所示。下面的例子:

1
2
3
4
5
6
7
8
@Bean
public FilterRegistrationBean myFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new MyFilter());
...
registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
return registration;
}

请注意,默认的FilterRegistrationBean不包括ERROR调度程序类型。

注意:Spring Boot 部署到 servlet 容器时,将使用其错误页面过滤器将具有错误状态的请求转发到相应的错误页面。如果尚未提交响应,则只能将请求转发到正确的错误页面。缺省情况下,WebSphere Application Server 8.0 和更高版本在成功完成 servlet 的服务方法后提交响应。您应该通过将com.ibm.ws.webcontainer.invokeFlushAfterService设置为false来禁用此行为。

Spring HATEOAS

如果您开发使用超媒体的 RESTful API,Spring Boot 将为 Spring HATEOAS 提供自动配置,该配置可与大多数应用程序很好地配合使用。自动配置取代了使用@EnableHypermediaSupport的需要,并注册了许多 Bean 以简化基于超媒体的应用程序的构建,包括LinkDiscoverers(用于 Client 端支持)和ObjectMapper,这些ObjectMapper被配置为将响应正确地编组为所需的表示形式。 ObjectMapper是通过设置各种spring.jackson.*属性来定制的,或者通过设置Jackson2ObjectMapperBuilder bean 来定制(如果存在)。

您可以使用@EnableHypermediaSupport来控制 Spring HATEOAS 的配置。请注意,这样做会禁用前面介绍的ObjectMapper自定义。

CORS支持

跨域资源共享(CORS)是由most browsers实现的W3C specification,可让您灵活地指定授权哪种类型的跨域请求,而不是使用一些安全性和功能不强的方法(例如 IFRAME 或 JSONP)。

从 4.2 版本开始,Spring MVC supports CORS。在 Spring Boot 应用程序中使用控制器方法 CORS 配置@CrossOrigin注解不需要任何特定的配置。可以通过使用自定义的addCorsMappings(CorsRegistry)方法注册WebMvcConfigurer bean 来定义全局 CORS 配置,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration
public class MyConfiguration {

@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**");
}
};
}
}

SpringWebFlux框架

Spring WebFlux 是 Spring Framework 5.0 中引入的新的响应式 Web 框架。与 Spring MVC 不同,它不需要 Servlet API,是完全异步和非阻塞的,并通过Reactor Project实现Reactive Streams规范。

Spring WebFlux 有两种形式:功能性的和基于注解的。基于注解的模型非常类似于 Spring MVC 模型,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@RestController
@RequestMapping("/users")
public class MyRestController {

@GetMapping("/{user}")
public Mono<User> getUser(@PathVariable Long user) {
// ...
}

@GetMapping("/{user}/customers")
public Flux<Customer> getUserCustomers(@PathVariable Long user) {
// ...
}

@DeleteMapping("/{user}")
public Mono<User> deleteUser(@PathVariable Long user) {
// ...
}

}

功能变量“ WebFlux.fn”将路由配置与请求的实际处理分开,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Configuration
public class RoutingConfiguration {

@Bean
public RouterFunction<ServerResponse> monoRouterFunction(UserHandler userHandler) {
return route(GET("/{user}").and(accept(APPLICATION_JSON)), userHandler::getUser)
.andRoute(GET("/{user}/customers").and(accept(APPLICATION_JSON)), userHandler::getUserCustomers)
.andRoute(DELETE("/{user}").and(accept(APPLICATION_JSON)), userHandler::deleteUser);
}

}

@Component
public class UserHandler {

public Mono<ServerResponse> getUser(ServerRequest request) {
// ...
}

public Mono<ServerResponse> getUserCustomers(ServerRequest request) {
// ...
}

public Mono<ServerResponse> deleteUser(ServerRequest request) {
// ...
}
}

WebFlux 是 Spring Framework 的一部分,其reference documentation中提供了详细信息。

Tip

您可以根据需要定义尽可能多的RouterFunction bean,以对 Router 的定义进行模块化。如果需要应用优先级,可以 Order Bean。

首先,将spring-boot-starter-webflux模块添加到您的应用程序中。

Note

在应用程序中同时添加spring-boot-starter-webspring-boot-starter-webflux模块会导致 Spring Boot 自动配置 Spring MVC,而不是 WebFlux。之所以选择这种行为,是因为许多 Spring 开发人员将spring-boot-starter-webflux添加到他们的 Spring MVC 应用程序中以使用 ReactiveWebClient。您仍然可以通过将选定的应用程序类型设置为SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE)来强制执行选择。

SpringWebFlux自动配置

Spring Boot 为 Spring WebFlux 提供了自动配置,可与大多数应用程序完美配合。

自动配置在 Spring 的默认值之上添加了以下功能:

  • HttpMessageReaderHttpMessageWriter实例配置编解码器(稍后将在本文档中描述)。
  • 支持服务静态资源,包括对 WebJars 的支持(描述为本文档后面)。

如果您想保留 Spring Boot WebFlux 功能,并且想要添加其他WebFlux configuration,则可以添加自己的@Configuration类,类型为WebFluxConfigurer,但 没有 @EnableWebFlux

如果要完全控制 Spring WebFlux,则可以添加带有@EnableWebFlux注解的自己的@Configuration

带有HttpMessageReaders和HttpMessageWriters的HTTP编解码器

Spring WebFlux 使用HttpMessageReaderHttpMessageWriter接口转换 HTTP 请求和响应。通过查看 Classpath 中可用的库,将它们配置为CodecConfigurer以具有合理的默认值。

Spring Boot 通过使用CodecCustomizer实例应用进一步的自定义。例如,将spring.jackson.*配置密钥应用于 Jackson 编解码器。

如果需要添加或自定义编解码器,则可以创建自定义CodecCustomizer组件,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
import org.springframework.boot.web.codec.CodecCustomizer;

@Configuration
public class MyConfiguration {

@Bean
public CodecCustomizer myCodecCustomizer() {
return codecConfigurer -> {
// ...
}
}

}

您还可以使用Boot 的自定义 JSON 序列化器和反序列化器

静态内容

默认情况下,Spring Boot 从 Classpath 中名为/static(或/public/resources/META-INF/resources)的目录中提供静态内容。它使用 Spring WebFlux 中的ResourceWebHandler,以便您可以通过添加自己的WebFluxConfigurer并覆盖addResourceHandlers方法来修改该行为。

默认情况下,资源 Map 在/**上,但是您可以通过设置spring.webflux.static-path-pattern属性对其进行调整。例如,将所有资源重定位到/resources/**可以实现如下:

1
spring.webflux.static-path-pattern=/resources/**

您还可以使用spring.resources.static-locations自定义静态资源位置。这样做会将默认值替换为目录位置列表。如果这样做,默认的欢迎页面检测将切换到您的自定义位置。因此,如果启动时您的任何位置都存在index.html,则它是应用程序的主页。

除了前面列出的“标准”静态资源位置之外,Webjars content也是一种特殊情况。如果 jar 文件以 Webjars 格式打包,则从 jar 文件提供带有/webjars/**路径的任何资源。

Tip

Spring WebFlux 应用程序不严格依赖 Servlet API,因此不能将它们部署为 war 文件,也不使用src/main/webapp目录。

模板引擎

除了 REST Web 服务之外,您还可以使用 Spring WebFlux 来提供动态 HTML 内容。 Spring WebFlux 支持多种模板技术,包括 Thymeleaf,FreeMarker 和 Mustache。

Spring Boot 包括对以下模板引擎的自动配置支持:

当您使用默认配置的这些模板引擎之一时,将从src/main/resources/templates自动拾取模板。

错误处理

Spring Boot 提供了一个WebExceptionHandler,可以明智地处理所有错误。它在处理 Sequences 中的位置紧靠 WebFlux 提供的处理程序之前,该处理程序被认为是最后一个。对于机器 Client 端,它将生成 JSON 响应,其中包含错误,HTTP 状态和异常消息的详细信息。对于浏览器 Client 端,有一个“ whitelabel”错误处理程序,以 HTML 格式渲染相同的数据。您还可以提供自己的 HTML 模板来显示错误(请参见next section

定制此功能的第一步通常涉及使用现有机制,但替换或增加错误内容。为此,您可以添加ErrorAttributes类型的 bean。

要更改错误处理行为,可以实现ErrorWebExceptionHandler并注册该类型的 bean 定义。由于WebExceptionHandler的级别很低,因此 Spring Boot 还提供了一个方便的AbstractErrorWebExceptionHandler,让您以 WebFlux 功能方式处理错误,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class CustomErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {

// Define constructor here

@Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {

return RouterFunctions
.route(aPredicate, aHandler)
.andRoute(anotherPredicate, anotherHandler);
}

}

要获得更完整的图片,您还可以直接继承DefaultErrorWebExceptionHandler并重写特定方法。

自定义错误页面

如果要显示给定状态代码的自定义 HTML 错误页面,可以将文件添加到/error文件夹。错误页面可以是静态 HTML(即添加到任何静态资源文件夹下),也可以使用模板构建。文件名应为确切的状态代码或系列掩码。

例如,要将404Map 到静态 HTML 文件,您的文件夹结构如下:

1
2
3
4
5
6
7
8
9
src/
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
+- <other public assets>

要使用 Mustache 模板 Map 所有5xx错误,您的文件夹结构如下:

1
2
3
4
5
6
7
8
9
src/
+- main/
+- java/
| + <source code>
+- resources/
+- templates/
+- error/
| +- 5xx.mustache
+- <other templates>

Web过滤器

Spring WebFlux提供了一个WebFilter接口,可以实现该接口来过滤HTTP请求-响应交换。 在应用程序上下文中找到的WebFilter bean将自动用于过滤每个交换。

如果过滤器的顺序很重要,则可以实现Ordered或使用@Order进行注解。 Spring Boot自动配置可能会为您配置Web过滤器。 这样做时,将使用下表中显示的顺序:

Web Filter Order
MetricsWebFilter Ordered.HIGHEST_PRECEDENCE + 1
WebFilterChainProxy(Spring Security 性) -100
HttpTraceWebFilter Ordered.LOWEST_PRECEDENCE - 10

JAX-RS和Jersey

如果您更喜欢 REST 端点的 JAX-RS 编程模型,则可以使用可用的实现之一来代替 Spring MVC。 JerseyApache CXF开箱即用。 CXF 要求您在应用程序上下文中将其ServletFilter注册为@Bean。Jersey(Jersey)有一些本机 Spring 支持,因此我们在 Spring Boot 中还与启动程序一起为其提供了自动配置支持。

要开始使用 Jersey,请将spring-boot-starter-jersey作为依赖项,然后需要一个ResourceConfig类型的@Bean,在其中注册所有端点,如以下示例所示:

1
2
3
4
5
6
7
8
@Component
public class JerseyConfig extends ResourceConfig {

public JerseyConfig() {
register(Endpoint.class);
}

}

Warning

Jersey 对扫描可执行归档文件的支持非常有限。例如,在运行可执行的 war 文件时,它无法扫描在完全可执行的 jar 文件WEB-INF/classes中找到的程序包中的端点。为避免此限制,不应使用packages方法,并且应使用register方法分别注册端点,如前面的示例所示。

对于更高级的定制,您还可以注册实现ResourceConfigCustomizer的任意数量的 bean。

所有注册的端点都应为@Components,并带有 HTTP 资源 Comments(@GET和其他 Comments),如以下示例所示:

1
2
3
4
5
6
7
8
9
10
@Component
@Path("/hello")
public class Endpoint {

@GET
public String message() {
return "Hello";
}

}

由于Endpoint是 Spring @Component,其生命周期由 Spring Management,因此您可以使用@Autowired注解注入依赖项,并使用@Value注解注入外部配置。默认情况下,Jersey servlet 已注册并 Map 到/*。您可以通过将@ApplicationPath添加到ResourceConfig来更改 Map。

默认情况下,Jersey 在名为jerseyServletRegistrationServletRegistrationBean类型的@Bean中设置为 Servlet。默认情况下,该 Servlet 延迟初始化,但是您可以通过设置spring.jersey.servlet.load-on-startup来自定义该行为。您可以通过使用相同的名称创建自己的一个来禁用或覆盖该 bean。您还可以通过设置spring.jersey.type=filter(在这种情况下,要替换或覆盖的@BeanjerseyFilterRegistration)来使用过滤器而不是 Servlet。过滤器具有@Order,您可以使用spring.jersey.filter.order进行设置。可以使用spring.jersey.init.*指定属性 Map,从而为 servlet 和过滤器注册都赋予 init 参数。

有一个Jersey sample,以便您可以了解如何进行设置。

嵌入式Servlet容器支持

Spring Boot 包含对嵌入式TomcatJettyUndertow服务器的支持。大多数开发人员使用适当的“启动器”来获取完全配置的实例。默认情况下,嵌入式服务器在端口8080上侦听 HTTP 请求。

Warning

如果选择在CentOS上使用 Tomcat,请注意,默认情况下,将使用一个临时目录来存储编译的 JSP,文件上载等等。您的应用程序运行时,此目录可能被tmpwatch删除,从而导致失败。为避免这种情况,您可能需要自定义tmpwatch配置,以使tomcat.*目录不会被删除,或配置server.tomcat.basedir,以使嵌入式 Tomcat 使用其他位置。

Servlet,过滤器和侦听器

使用嵌入式 Servlet 容器时,可以通过使用 Spring bean 或扫描 Servlet 组件来注册 Servlet 规范中的 Servlet,过滤器和所有侦听器(例如HttpSessionListener)。

将Servlet,过滤器和侦听器注册为SpringBean

任何作为 Spring bean 的ServletFilter或 servlet *Listener实例都向嵌入式容器注册。如果要在配置过程中引用application.properties中的值,这可能特别方便。

默认情况下,如果上下文仅包含单个 Servlet,则将其 Map 到/。对于多个 servlet bean,bean 名称用作路径前缀。过滤器 Map 到/*

如果基于约定的 Map 不够灵活,则可以使用ServletRegistrationBeanFilterRegistrationBeanServletListenerRegistrationBean类进行完全控制。

Spring Boot 附带了许多可能定义 Filter bean 的自动配置。以下是过滤器及其各自 Sequences 的一些示例(较低的 Sequences 值表示较高的优先级):

Servlet Filter Order
OrderedCharacterEncodingFilter Ordered.HIGHEST_PRECEDENCE
WebMvcMetricsFilter Ordered.HIGHEST_PRECEDENCE + 1
ErrorPageFilter Ordered.HIGHEST_PRECEDENCE + 1
HttpTraceFilter Ordered.LOWEST_PRECEDENCE - 10

通常可以使无序滤 bean 处于无序状态。

如果需要特定的 Sequences,则应避免配置一个在Ordered.HIGHEST_PRECEDENCE读取请求正文的过滤器,因为它可能与应用程序的字符编码配置不符。如果 Servlet 过滤器包装了请求,则应以小于或等于OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER的 Sequences 对其进行配置。

Servlet上下文初始化

嵌入式 Servlet 容器不会直接执行 Servlet 3.0 javax.servlet.ServletContainerInitializer接口或 Spring 的org.springframework.web.WebApplicationInitializer接口。这是一个有意设计的决定,目的是减少旨在在 War 中运行的第三方库可能破坏 Spring Boot 应用程序的风险。

如果需要在 Spring Boot 应用程序中执行 servlet 上下文初始化,则应该注册一个实现org.springframework.boot.web.servlet.ServletContextInitializer接口的 bean。单个onStartup方法提供对ServletContext的访问,并且在必要时可以轻松地用作现有WebApplicationInitializer的适配器。

扫描Servlet,过滤器和侦听器

使用嵌入式容器时,可以通过使用@ServletComponentScan来启用自动注册带有@WebServlet@WebFilter@WebListenerComments 的类。

Tip

@ServletComponentScan在独立容器中无效,而是使用该容器的内置发现机制。

ServletWebServerApplicationContext

在后台,Spring Boot 使用另一种类型的ApplicationContext来支持嵌入式 servlet 容器。 ServletWebServerApplicationContextWebApplicationContext的一种特殊类型,它通过搜索单个ServletWebServerFactory bean 来进行自我引导。通常TomcatServletWebServerFactoryJettyServletWebServerFactoryUndertowServletWebServerFactory已被自动配置。

Note

通常,您不需要了解这些实现类。大多数应用程序都是自动配置的,并且代表您创建了相应的ApplicationContextServletWebServerFactory

自定义嵌入式Servlet容器

可以使用 Spring Environment属性来配置常见的 servlet 容器设置。通常,您将在application.properties文件中定义属性。

常用服务器设置包括:

  • 网络设置:侦听传入 HTTP 请求的端口(server.port),绑定到server.address的接口地址,等等。
  • 会话设置:会话是否持久(server.servlet.session.persistence),会话超时(server.servlet.session.timeout),会话数据的位置(server.servlet.session.store-dir)和会话 cookie 配置(server.servlet.session.cookie.*)。
  • 错误 Management:错误页面的位置(server.error.path),依此类推。
  • SSL
  • HTTP compression

Spring Boot 尝试尽可能多地公开通用设置,但这并不总是可能的。在这种情况下,专用名称空间提供服务器特定的自定义项(请参见server.tomcatserver.undertow)。例如,access logs可以配置有嵌入式 Servlet 容器的特定功能。

Tip

有关完整列表,请参见ServerProperties类。

程序定制

如果需要以编程方式配置嵌入式 servlet 容器,则可以注册一个实现WebServerFactoryCustomizer接口的 Spring bean。 WebServerFactoryCustomizer提供对ConfigurableServletWebServerFactory的访问,其中包括许多自定义设置方法。以下示例显示以编程方式设置端口:

1
2
3
4
5
6
7
8
9
10
11
12
13
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.stereotype.Component;

@Component
public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {

@Override
public void customize(ConfigurableServletWebServerFactory server) {
server.setPort(9000);
}

}

Note

TomcatServletWebServerFactoryJettyServletWebServerFactoryUndertowServletWebServerFactoryConfigurableServletWebServerFactory的专用变体,分别具有针对 Tomcat,Jetty 和 Undertow 的其他自定义设置方法。

直接自定义ConfigurableServletWebServerFactory

如果上述定制技术太有限,则可以自己注册TomcatServletWebServerFactoryJettyServletWebServerFactoryUndertowServletWebServerFactory bean。

1
2
3
4
5
6
7
8
@Bean
public ConfigurableServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.setPort(9000);
factory.setSessionTimeout(10, TimeUnit.MINUTES);
factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notfound.html"));
return factory;
}

提供了许多配置选项的设置器。如果您需要做一些更奇特的操作,还提供了几种受保护的方法“钩子”。有关详情,请参见源代码文档

JSP限制

当运行使用嵌入式 servlet 容器(并打包为可执行归档文件)的 Spring Boot 应用程序时,JSP 支持存在一些限制。

  • 对于 Jetty 和 Tomcat,如果使用 War 包装,它应该可以工作。与java -jar一起启动时,可执行的 War 将起作用,并且也可部署到任何标准容器中。使用可执行 jar 时,不支持 JSP。
  • Undertow 不支持 JSP。
  • 创建自定义error.jsp页面不会覆盖error handling的默认视图。应该改用自定义错误页面

有一个JSP sample,以便您可以了解如何进行设置。

嵌入式反应式服务器支持

Spring Boot 包含对以下嵌入式反应式 Web 服务器的支持:Reactor Netty,Tomcat,Jetty 和 Undertow。大多数开发人员使用适当的“启动器”来获取完全配置的实例。默认情况下,嵌入式服务器在端口 8080 上侦听 HTTP 请求。

Reactive服务器资源配置

当自动配置 Reactor Netty 或 Jetty 服务器时,Spring Boot 将创建特定的 bean,这些 bean 将为服务器实例提供 HTTP 资源:ReactorResourceFactoryJettyResourceFactory

默认情况下,在以下情况下,这些资源还将与 Reactor Netty 和 Jetty Client 端共享,以实现最佳性能:

  • 服务器和 Client 端使用相同的技术
  • Client 端实例是使用 Spring Boot 自动配置的WebClient.Builder bean 构建的

通过提供自定义的ReactorResourceFactoryJettyResourceFactory bean,开发人员可以覆盖 Jetty 和 Reactor Netty 的资源配置-这将同时应用于 Client 端和服务器。

您可以在WebClient 运行时部分中了解有关 Client 端资源配置的更多信息。

正常关机

所有4个嵌入式web服务器(Jetty、Reactor Netty、Tomcat和Undertow)以及响应式和基于servlet的web应用程序都支持优雅的关机。它是关闭应用程序上下文的一部分,在停止SmartLifecycle bean的最初阶段执行。此停止处理使用了一个超时,该超时提供了一个宽限期,在此期间允许现有请求完成,但不允许新请求。不允许新请求的确切方式取决于所使用的web服务器。Jetty、Reactor Netty和Tomcat将停止在网络层接受请求。Undertow将接受请求,但立即响应一个服务不可用(503)响应。

使用Tomcat优雅地关机需要Tomcat 9.0.33或更高版本。

要启用优雅的关机,请配置服务器。关机属性,如下例所示:

1
server.shutdown=graceful

要配置超时时间,请配置spring.lifecycle。每关闭阶段超时属性,如下例所示:

1
spring.lifecycle.timeout-per-shutdown-phase=20s

Important

如果IDE无法发送正确的SIGTERM信号,则在其IDE中使用正常关机可能无法正常工作。 有关更多详细信息,请参阅IDE的文档。

RSocket

RSocket是用于字节流传输的二进制协议。 它通过通过单个连接传递的异步消息来启用对称交互模型。

Spring框架的spring-messaging模块在客户端和服务器端都支持RSocket请求者和响应者。 有关更多详细信息,请参见Spring Framework参考中的RSocket部分,其中包括RSocket协议的概述。

RSocket策略自动配置

Spring Boot自动配置一个RSocketStrategies bean,该bean提供用于编码和解码RSocket有效负载的所有必需的基础结构。默认情况下,自动配置将尝试按顺序配置以下内容:

  1. Jackson的CBOR编解码器
  1. Jackson的JSON编解码器

spring-boot-starter-rocket启动器提供了两种依赖关系。查阅Jackson支持部分,以了解有关定制可能性的更多信息。

开发人员可以通过创建实现RSocketStrategiesCustomizer接口的bean来自定义RSocketStrategies组件。请注意,它们的@Order很重要,因为它确定编解码器的顺序。

RSocket服务器自动配置

Spring Boot提供了RSocket服务器自动配置。所需的依赖关系由spring-boot-starter-rsocket提供。

Spring Boot允许通过WebFlux服务器通过WebSocket公开RSocket,或支持独立的RSocket服务器。这取决于应用程序的类型及其配置。

对于WebFlux应用程序(即类型为WebApplicationType.REACTIVE的应用程序),仅当以下属性匹配时,RSocket服务器才会插入Web服务器:

1
2
3
spring.rsocket.server.mapping-path=/rsocket # a mapping path is defined
spring.rsocket.server.transport=websocket # websocket is chosen as a transport
#spring.rsocket.server.port= # no port is defined

Note

由于RSocket本身是使用该库构建的,因此只有Reactor Netty支持将RSocket插入Web服务器。

另外,RSocket TCP或Websocket服务器也可以作为独立的嵌入式服务器启动。 除了依赖性要求之外,唯一需要的配置是为该服务器定义端口:

1
2
spring.rsocket.server.port=9898 # the only required configuration
spring.rsocket.server.transport=tcp # you're free to configure other properties

Spring Messaging RSocket支持

Spring Boot将为RSocket自动配置Spring Messaging基础结构。

这意味着Spring Boot将创建一个RSocketMessageHandler bean,该bean将处理对您的应用程序的RSocket请求。

使用RSocketRequester调用RSocket服务

在服务器和客户端之间建立RSocket通道后,任何一方都可以向另一方发送或接收请求。

作为服务器,您可以在RSocket @Controller的任何处理程序方法上注入RSocketRequester实例。作为客户端,您需要首先配置和建立RSocket连接。在这种情况下,Spring Boot会使用预期的编解码器自动配置RSocketRequester.Builder

RSocketRequester.Builder实例是一个原型bean,这意味着每个注入点将为您提供一个新实例。这样做是有目的的,因为此构建器是有状态的,因此您不应使用相同的实例创建具有不同设置的请求者。

以下代码显示了一个典型示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Service
public class MyService {

private final Mono<RSocketRequester> rsocketRequester;

public MyService(RSocketRequester.Builder rsocketRequesterBuilder) {
this.rsocketRequester = rsocketRequesterBuilder
.connectTcp("example.org", 9898).cache();
}

public Mono<User> someRSocketCall(String name) {
return this.rsocketRequester.flatMap(req ->
req.route("user").data(name).retrieveMono(User.class));
}

}

Security

如果Spring SecurityClasspath 上,则默认情况下将保护 Web 应用程序的安全。 Spring Boot 依靠 Spring Security 的内容协商策略来确定使用httpBasic还是formLogin。要将方法级安全性添加到 Web 应用程序,您还可以使用所需的设置添加@EnableGlobalMethodSecurity。其他信息可以在Spring Security 参考指南中找到。

默认的UserDetailsService有一个用户。用户名为user,密码为随机密码,并在应用程序启动时以 INFO 级别显示,如下例所示:

1
Using generated security password: 78fa095d-3f4c-48b1-ad50-e24c31d5cf35

Note

如果您微调日志记录配置,请确保将org.springframework.boot.autoconfigure.security类别设置为记录INFO级消息。否则,不会打印默认密码。

您可以通过提供spring.security.user.namespring.security.user.password来更改用户名和密码。

默认情况下,您在 Web 应用程序中获得的基本功能是:

  • 具有内存存储的UserDetailsService(或 WebFlux 应用程序为ReactiveUserDetailsService)bean 和具有生成的密码的单个用户(有关用户的属性,请参见SecurityProperties.User)。
  • 整个应用程序的基于表单的登录或 HTTP 基本安全性(取决于 Content-Type)(如果 Actuator 位于 Classpath 上,则包括 Actuator 端点)。
  • DefaultAuthenticationEventPublisher用于发布身份验证事件。

您可以通过添加一个 Bean 来提供另一个AuthenticationEventPublisher

MVC安全性

默认的安全配置在SecurityAutoConfigurationUserDetailsServiceAutoConfiguration中实现。 SecurityAutoConfiguration导入SpringBootWebSecurityConfiguration以获得 Web 安全性,并且UserDetailsServiceAutoConfiguration配置身份验证,这也与非 Web 应用程序相关。要完全关闭默认的 Web 应用程序安全性配置,可以添加类型为WebSecurityConfigurerAdapter的 bean(这样做不会禁用UserDetailsService配置或 Actuator 的安全性)。

要也关闭UserDetailsService配置,可以添加UserDetailsServiceAuthenticationProviderAuthenticationManager类型的 Bean。 Spring Bootsample中有几个安全的应用程序,可帮助您开始使用常见的用例。

通过添加自定义WebSecurityConfigurerAdapter可以覆盖访问规则。 Spring Boot 提供了便利的方法,可用于覆盖 Actuator 端点和静态资源的访问规则。 EndpointRequest可用于创建基于management.endpoints.web.base-path属性的RequestMatcherPathRequest可用于为常用位置的资源创建RequestMatcher

WebFlux安全性

与 Spring MVC 应用程序类似,您可以通过添加spring-boot-starter-security依赖项来保护 WebFlux 应用程序。默认的安全配置在ReactiveSecurityAutoConfigurationUserDetailsServiceAutoConfiguration中实现。 ReactiveSecurityAutoConfiguration导入WebFluxSecurityConfiguration以获得 Web 安全性,并且UserDetailsServiceAutoConfiguration配置身份验证,这也与非 Web 应用程序相关。要完全关闭默认的 Web 应用程序安全性配置,可以添加类型为WebFilterChainProxy的 bean(这样做不会禁用UserDetailsService配置或 Actuator 的安全性)。

要也关闭UserDetailsService配置,可以添加ReactiveUserDetailsServiceReactiveAuthenticationManager类型的 Bean。

可以通过添加自定义SecurityWebFilterChain来配置访问规则。 Spring Boot 提供了便利的方法,可用于覆盖 Actuator 端点和静态资源的访问规则。 EndpointRequest可用于创建基于management.endpoints.web.base-path属性的ServerWebExchangeMatcher

PathRequest可用于为常用位置的资源创建ServerWebExchangeMatcher

例如,您可以通过添加以下内容来自定义安全配置:

1
2
3
4
5
6
7
8
9
10
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
return http
.authorizeExchange()
.matchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.pathMatchers("/foo", "/bar")
.authenticated().and()
.formLogin().and()
.build();
}

OAuth2

OAuth2是 Spring 支持的广泛使用的授权框架。

Client

如果您的 Classpath 上有spring-security-oauth2-client,则可以利用一些自动配置功能来轻松设置 OAuth2/Open ID Connect Client 端。此配置使用OAuth2ClientProperties下的属性。相同的属性适用于 servlet 和反应式应用程序。

您可以使用spring.security.oauth2.client前缀注册多个 OAuth2 Client 端和提供者,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
spring.security.oauth2.client.registration.my-client-1.client-id=abcd
spring.security.oauth2.client.registration.my-client-1.client-secret=password
spring.security.oauth2.client.registration.my-client-1.client-name=Client for user scope
spring.security.oauth2.client.registration.my-client-1.provider=my-oauth-provider
spring.security.oauth2.client.registration.my-client-1.scope=user
spring.security.oauth2.client.registration.my-client-1.redirect-uri-template=http://my-redirect-uri.com
spring.security.oauth2.client.registration.my-client-1.client-authentication-method=basic
spring.security.oauth2.client.registration.my-client-1.authorization-grant-type=authorization_code

spring.security.oauth2.client.registration.my-client-2.client-id=abcd
spring.security.oauth2.client.registration.my-client-2.client-secret=password
spring.security.oauth2.client.registration.my-client-2.client-name=Client for email scope
spring.security.oauth2.client.registration.my-client-2.provider=my-oauth-provider
spring.security.oauth2.client.registration.my-client-2.scope=email
spring.security.oauth2.client.registration.my-client-2.redirect-uri-template=http://my-redirect-uri.com
spring.security.oauth2.client.registration.my-client-2.client-authentication-method=basic
spring.security.oauth2.client.registration.my-client-2.authorization-grant-type=authorization_code

spring.security.oauth2.client.provider.my-oauth-provider.authorization-uri=http://my-auth-server/oauth/authorize
spring.security.oauth2.client.provider.my-oauth-provider.token-uri=http://my-auth-server/oauth/token
spring.security.oauth2.client.provider.my-oauth-provider.user-info-uri=http://my-auth-server/userinfo
spring.security.oauth2.client.provider.my-oauth-provider.user-info-authentication-method=header
spring.security.oauth2.client.provider.my-oauth-provider.jwk-set-uri=http://my-auth-server/token_keys
spring.security.oauth2.client.provider.my-oauth-provider.user-name-attribute=name

对于支持OpenID Connect 发现的 OpenID Connect 提供程序,可以进一步简化配置。提供者需要配置一个issuer-uri,这是它声明为其发布者标识符的 URI。例如,如果提供的issuer-uri是“ https://example.com”,则将对“ https://example.com/.well-known/openid-configuration”设置`OpenID Provider Configuration Request。结果预期为OpenID Provider Configuration Response。以下示例显示了如何使用issuer-uri`配置 OpenID Connect 提供程序:

1
spring.security.oauth2.client.provider.oidc-provider.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/

默认情况下,Spring Security 的OAuth2LoginAuthenticationFilter只处理与/login/oauth2/code/*匹配的 URL。如果要定制redirect-uri以使用其他模式,则需要提供配置以处理该定制模式。例如,对于 servlet 应用程序,您可以添加自己的WebSecurityConfigurerAdapter,其类似于以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login()
.redirectionEndpoint()
.baseUri("/custom-callback");
}
}

通用提供商的OAuth2Client端注册

对于常见的 OAuth2 和 OpenID 提供程序,包括 Google,Github,Facebook 和 Okta,我们提供了一组提供程序默认值(分别为googlegithubfacebookokta)。

如果不需要自定义这些提供程序,则可以将provider属性设置为您需要为其推断默认值的属性。另外,如果用于 Client 端注册的密钥与默认支持的提供程序匹配,则 Spring Boot 也会进行推断。

换句话说,以下示例中的两种配置都使用 Google 提供程序:

1
2
3
4
5
6
spring.security.oauth2.client.registration.my-client.client-id=abcd
spring.security.oauth2.client.registration.my-client.client-secret=password
spring.security.oauth2.client.registration.my-client.provider=google

spring.security.oauth2.client.registration.google.client-id=abcd
spring.security.oauth2.client.registration.google.client-secret=password

资源服务器

如果您的 Classpath 上有spring-security-oauth2-resource-server,则只要指定了 JWK Set URI 或 OIDC Issuer URI,Spring Boot 就可以设置 OAuth2 资源服务器,如以下示例所示:

1
2
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://example.com/oauth2/default/v1/keys
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/

相同的属性适用于 servlet 和反应式应用程序。

另外,您可以为 Servlet 应用程序定义自己的JwtDecoder bean 或为 Reactive 应用程序定义ReactiveJwtDecoder

授权服务器

当前,Spring Security 不提供对实现 OAuth 2.0 授权服务器的支持。但是,此功能可从Spring Security OAuth项目获得,最终将被 Spring Security 完全取代。在此之前,您可以使用spring-security-oauth2-autoconfigure模块轻松设置 OAuth 2.0 授权服务器;有关说明,请参见其documentation

Actuator安全性

为了安全起见,默认禁用除/health/info以外的所有 Actuator。 management.endpoints.web.exposure.include属性可用于启用 Actuator。

如果 Spring Security 位于 Classpath 上,并且不存在其他 WebSecurityConfigurerAdapter,则通过 Spring Boot 自动配置来保护/health/info以外的所有 Actuator。如果您定义一个自定义WebSecurityConfigurerAdapter,Spring Boot 自动配置将退出,您将完全控制 Actuator 访问规则。

Note

在设置management.endpoints.web.exposure.include之前,请确保裸露的 Actuator 不包含敏感信息和/或通过将它们放置在防火墙后面或通过诸如 Spring Security 之类的东西进行保护。

跨站点请求伪造保护

由于 Spring Boot 依赖于 Spring Security 的默认值,因此默认情况下 CSRF 保护是打开的。这意味着在使用默认安全性配置时,需要POST的 Actuator 端点(关机和 Logger 端点),PUTDELETE将收到 403 禁止错误。

Note

我们建议仅在创建非浏览器 Client 端使用的服务时完全禁用 CSRF 保护。

有关 CSRF 保护的其他信息可以在Spring Security 参考指南中找到。

使用SQL数据库

Spring Framework为使用 SQL 数据库提供了广泛的支持,从使用JdbcTemplate的直接 JDBC 访问到完整的“对象关系 Map”技术(例如 Hibernate)。 Spring Data提供了更高级别的功能:直接从接口创建Repository实现,并使用约定从您的方法名称生成查询。

配置数据源

Java 的javax.sql.DataSource接口提供了使用数据库连接的标准方法。传统上,“数据源”使用URL以及一些凭据来构建数据库连接。

Tip

有关更高级的示例,请参见“操作方法”部分,通常可以完全控制 DataSource 的配置。

嵌入式数据库支持

通过使用内存嵌入式数据库来开发应用程序通常很方便。显然,内存数据库不提供持久存储。您需要在应用程序启动时填充数据库,并准备在应用程序结束时丢弃数据。

Tip

“操作方法”部分包括关于如何初始化数据库的部分

Spring Boot 可以自动配置嵌入式H2HSQLDerby数据库。您无需提供任何连接 URL。您只需要包含要使用的嵌入式数据库的构建依赖项即可。

Note

如果在测试中使用此功能,则可能会注意到,整个测试套件将重用同一数据库,而不管您使用的应用程序上下文的数量如何。如果要确保每个上下文都有一个单独的嵌入式数据库,则应将spring.datasource.generate-unique-name设置为true

例如,典型的 POM 依赖关系如下:

1
2
3
4
5
6
7
8
9
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>runtime</scope>
</dependency>

Note

您需要依赖spring-jdbc才能自动配置嵌入式数据库。在此示例中,它通过spring-boot-starter-data-jpa暂时拉入。

Tip

如果出于某种原因确实为嵌入式数据库配置了连接 URL,请确保确保禁用了数据库的自动关闭功能。如果使用 H2,则应使用DB_CLOSE_ON_EXIT=FALSE。如果使用 HSQLDB,则应确保不使用shutdown=true。通过禁用数据库的自动关闭功能,Spring Boot 可以控制何时关闭数据库,从而确保一旦不再需要访问数据库时就可以执行该操作。

连接到生产数据库

生产数据库连接也可以使用池DataSource进行自动配置。 Spring Boot 使用以下算法来选择特定的实现:

  • 我们更喜欢HikariCP的性能和并发性。如果 HikariCP 可用,我们总是选择它。
  • 否则,如果 Tomcat 池DataSource可用,我们将使用它。
  • 如果 HikariCP 和 Tomcat 池数据源都不可用,并且Commons DBCP2可用,我们将使用它。

如果使用spring-boot-starter-jdbcspring-boot-starter-data-jpa“启动器”,则会自动获得HikariCP的依赖项。

Note

您可以完全绕过该算法,并通过设置spring.datasource.type属性来指定要使用的连接池。如果您在 Tomcat 容器中运行应用程序,这一点尤其重要,因为默认情况下提供tomcat-jdbc

Tip

其他连接池始终可以手动配置。如果定义自己的DataSource bean,则不会进行自动配置。

数据源配置由spring.datasource.*中的外部配置属性控制。例如,您可以在application.properties中声明以下部分:

1
2
3
4
spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

Note

您至少应通过设置spring.datasource.url属性来指定 URL。否则,Spring Boot 会尝试自动配置嵌入式数据库。

Tip

您通常不需要指定driver-class-name,因为 Spring Boot 可以从url推导大多数数据库。

Note

对于要创建的池DataSource,我们需要能够验证一个有效的Driver类是否可用,因此我们在进行任何操作之前都要进行检查。换句话说,如果设置spring.datasource.driver-class-name=com.mysql.jdbc.Driver,则该类必须是可加载的。

有关更多受支持的选项,请参见DataSourceProperties。这些是与实际实现无关的标准选项。也可以使用它们各自的前缀(spring.datasource.hikari.*spring.datasource.tomcat.*spring.datasource.dbcp2.*)微调实现特定的设置。有关更多详细信息,请参考所用连接池实现的文档。

例如,如果您使用Tomcat 连接池,则可以自定义许多其他设置,如以下示例所示:

1
2
3
4
5
6
7
8
# Number of ms to wait before throwing an exception if no connection is available.
spring.datasource.tomcat.max-wait=10000

# Maximum number of active connections that can be allocated from this pool at the same time.
spring.datasource.tomcat.max-active=50

# Validate the connection before borrowing it from the pool.
spring.datasource.tomcat.test-on-borrow=true

连接到JNDI数据源

如果您将 Spring Boot 应用程序部署到 Application Server,则可能需要使用 Application Server 的内置功能来配置和 Management DataSource,并使用 JNDI 对其进行访问。

spring.datasource.jndi-name属性可以替代spring.datasource.urlspring.datasource.usernamespring.datasource.password属性,以从特定的 JNDI 位置访问DataSource。例如,application.properties中的以下部分显示了如何访问 JBoss AS 定义的DataSource

1
spring.datasource.jndi-name=java:jboss/datasources/customers

使用JdbcTemplate

Spring 的JdbcTemplateNamedParameterJdbcTemplate类是自动配置的,您可以@Autowire直接将它们@Autowire放入自己的 bean 中,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

private final JdbcTemplate jdbcTemplate;

@Autowired
public MyBean(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}

// ...

}

您可以使用spring.jdbc.template.*属性来自定义模板的某些属性,如以下示例所示:

1
spring.jdbc.template.max-rows=500

Note

NamedParameterJdbcTemplate在后台重复使用相同的JdbcTemplate实例。如果定义了多个JdbcTemplate并且不存在主要候选对象,则不会自动配置NamedParameterJdbcTemplate

JPA和SpringDataJPA

Java Persistence API 是一种标准技术,可让您将对象“Map”到关系数据库。 spring-boot-starter-data-jpa POM 提供了一种快速的 Starter 方法。它提供以下关键依赖性:

  • Hibernate:最流行的 JPA 实现之一。
  • Spring Data JPA:使基于 JPA 的存储库的实现变得容易。
  • Spring ORM:Spring Framework 提供的核心 ORM 支持。

Tip

在这里,我们不会过多讨论 JPA 或Spring Data的细节。您可以按照spring.io中的“使用 JPA 访问数据”指南进行操作,并阅读Spring Data JPAHibernate参考文档。

实体类

传统上,JPA“实体”类是在persistence.xml文件中指定的。对于 Spring Boot,此文件不是必需的,而是使用“实体扫描”。默认情况下,将搜索主配置类(用@EnableAutoConfiguration@SpringBootApplication注解的软件包)下的所有软件包。

任何带有@Entity@Embeddable@MappedSuperclass注解的类。典型的实体类类似于以下示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.example.myapp.domain;

import java.io.Serializable;
import javax.persistence.*;

@Entity
public class City implements Serializable {

@Id
@GeneratedValue
private Long id;

@Column(nullable = false)
private String name;

@Column(nullable = false)
private String state;

// ... additional members, often include @OneToMany mappings

protected City() {
// no-args constructor required by JPA spec
// this one is protected since it shouldn't be used directly
}

public City(String name, String state) {
this.name = name;
this.state = state;
}

public String getName() {
return this.name;
}

public String getState() {
return this.state;
}

// ... etc

}

Tip

您可以使用@EntityScan注解来自定义实体扫描位置。请参阅“ 第 84.4 节“将@Entity 定义与 Spring 配置分开””方法。

SpringDataJPA存储库

Spring Data JPA存储库是您可以定义以访问数据的接口。 JPA 查询是根据您的方法名称自动创建的。例如,一个CityRepository接口可能声明findAllByState(String state)方法来查找给定 State 的所有城市。

对于更复杂的查询,您可以使用 Spring Data 的Query注解对方法进行注解。

Spring Data 存储库通常从RepositoryCrudRepository接口扩展。如果使用自动配置,则会从包含主配置类(用@EnableAutoConfiguration@SpringBootApplication注解的主配置类)的包中搜索存储库。

以下示例显示了典型的 Spring Data 存储库接口定义:

1
2
3
4
5
6
7
8
9
10
11
12
package com.example.myapp.domain;

import org.springframework.data.domain.*;
import org.springframework.data.repository.*;

public interface CityRepository extends Repository<City, Long> {

Page<City> findAll(Pageable pageable);

City findByNameAndStateAllIgnoringCase(String name, String state);

}

Spring Data JPA存储库支持三种不同的引导模式:defaultdeferredlazy。 要启用deferredlazy,请将spring.data.jpa.repositories.bootstrap-mode属性分别设置为推迟或懒惰。 使用deferredlazy时,自动配置的EntityManagerFactoryBuilder将使用上下文的AsyncTaskExecutor(如果有)作为引导执行器。 如果存在多个,则将使用一个名为applicationTaskExecutor的应用程序。

Tip

我们几乎没有刮过 Spring Data JPA 的表面。有关完整的详细信息,请参见Spring Data JPA 参考文档

创建和删除JPA数据库

默认情况下,您不使用嵌入式数据库(H2,HSQL或Derby),JPA数据库自动创建。 您可以使用spring.jpa.*属性显式配置JPA设置。 例如,要创建和删除表,可以将以下行添加到application.properties

1
spring.jpa.hibernate.ddl-auto=create-drop

Note

Hibernate 自己的内部属性名称是hibernate.hbm2ddl.auto(如果您记得更好的话)。您可以使用spring.jpa.properties.*来设置它以及其他 Hibernate 本机属性(将前缀添加到实体 Management 器之前,前缀会被删除)。下面的行显示了为 Hibernate 设置 JPA 属性的示例:

1
spring.jpa.properties.hibernate.globally_quoted_identifiers=true

前面示例中的行将hibernate.globally_quoted_identifiers属性的值true传递给 Hibernate 实体 Management 器。

默认情况下,DDL 执行(或验证)被推迟到ApplicationContext开始。还有一个spring.jpa.generate-ddl标志,但是如果 Hibernate 自动配置处于 Active 状态,则不使用它,因为ddl-auto设置更细粒度。

在视图中打开EntityManager

如果您正在运行 Web 应用程序,则默认情况下,Spring Boot 注册OpenEntityManagerInViewInterceptor以应用“在视图中打开 EntityManager”模式,以允许在 Web 视图中进行延迟加载。如果您不希望出现这种情况,则应在application.properties中将spring.jpa.open-in-view设置为false

Spring Data JDBC

Spring Data 包括对 JDBC 的存储库支持,并将自动为CrudRepository上的方法生成 SQL。对于更高级的查询,提供了@QueryComments。

当必要的依赖项位于 Classpath 上时,Spring Boot 将自动配置 Spring Data 的 JDBC 存储库。只需依赖spring-boot-starter-data-jdbc即可将它们添加到您的项目中。如有必要,您可以通过向应用程序中添加@EnableJdbcRepositories注解或JdbcConfiguration子类来控制 Spring Data JDBC 的配置。

Tip

有关 Spring Data JDBC 的完整详细信息,请参阅reference documentation

使用H2的Web 控制台

H2 database提供了browser-based console,Spring Boot 可以为您自动配置browser-based console。满足以下条件时,将自动配置控制台:

Tip

如果您不使用 Spring Boot 的开发人员工具,但仍想使用 H2 的控制台,则可以将spring.h2.console.enabled属性配置为true

Note

H2 控制台仅在开发期间使用,因此您应确保在 Producing 不要将spring.h2.console.enabled设置为true

更改H2控制台的路径

默认情况下,控制台位于/h2-console。您可以使用spring.h2.console.path属性来自定义控制台的路径。

使用jOOQ

面向 Java 对象的查询(jOOQ)是Data Geekery的流行产品,它可以从数据库中生成 Java 代码,并允许您通过其流畅的 API 构建类型安全的 SQL 查询。商业版和开源版都可以与 Spring Boot 一起使用。

代码生成

为了使用 jOOQ 类型安全查询,您需要从数据库架构中生成 Java 类。您可以按照jOOQ 用户手册中的说明进行操作。如果您使用jooq-codegen-maven插件,并且还使用spring-boot-starter-parent“父 POM”,则可以安全地忽略该插件的<version>标签。您还可以使用 Spring Boot 定义的版本变量(例如h2.version)来声明插件的数据库依赖关系。以下 Lists 显示了一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<plugin>
<groupId>org.jooq</groupId>
<artifactId>jooq-codegen-maven</artifactId>
<executions>
...
</executions>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
</dependency>
</dependencies>
<configuration>
<jdbc>
<driver>org.h2.Driver</driver>
<url>jdbc:h2:~/yourdatabase</url>
</jdbc>
<generator>
...
</generator>
</configuration>
</plugin>

使用DSLContext

jOOQ 提供的流畅的 API 是通过org.jooq.DSLContext接口启动的。 Spring Boot 将DSLContext自动配置为 Spring Bean,并将其连接到应用程序DataSource。要使用DSLContext,您可以@Autowire,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
@Component
public class JooqExample implements CommandLineRunner {

private final DSLContext create;

@Autowired
public JooqExample(DSLContext dslContext) {
this.create = dslContext;
}

}

Tip

jOOQ 手册倾向于使用名为create的变量来保存DSLContext

然后,您可以使用DSLContext构造查询,如以下示例所示:

1
2
3
4
5
public List<GregorianCalendar> authorsBornAfter1980() {
return this.create.selectFrom(AUTHOR)
.where(AUTHOR.DATE_OF_BIRTH.greaterThan(new GregorianCalendar(1980, 0, 1)))
.fetch(AUTHOR.DATE_OF_BIRTH);
}

jOOQSQL方言

除非已配置spring.jooq.sql-dialect属性,否则 Spring Boot 会确定要用于数据源的 SQL 方言。如果 Spring Boot 无法检测到方言,则使用DEFAULT

Note

Spring Boot 只能自动配置开源版本的 jOOQ 支持的方言。

自定义jOOQ

通过定义自己的@Bean定义(可以在创建 jOOQ Configuration时使用)可以实现更高级的自定义。您可以为以下 jOOQ 类型定义 bean:

  • ConnectionProvider
  • ExecutorProvider
  • TransactionProvider
  • RecordMapperProvider
  • RecordUnmapperProvider
  • RecordListenerProvider
  • ExecuteListenerProvider
  • VisitListenerProvider
  • TransactionListenerProvider

如果要完全控制 jOOQ 配置,也可以创建自己的org.jooq.Configuration @Bean

使用NoSQL技术

Spring Data 提供了其他项目,可帮助您访问各种 NoSQL 技术,包括:MongoDBNeo4JElasticsearchSolrRedisGemfireCassandraCouchbaseLDAP。 Spring Boot 为 Redis,MongoDB,Neo4j,Elasticsearch,Solr Cassandra,Couchbase 和 LDAP 提供自动配置。您可以使用其他项目,但是必须自己配置它们。请参考projects.spring.io/spring-data的相应参考文档。

Redis

Redis是缓存,消息代理和功能丰富的键值存储。 Spring Boot 为LettuceJedisClient 端库提供了基本的自动配置,以及Spring Data Redis提供的对它们的抽象。

有一个spring-boot-starter-data-redis“启动程序”,以方便的方式收集依赖项。默认情况下,它使用Lettuce。该启动程序可以处理传统应用程序和响应式应用程序。

Tip

我们还提供spring-boot-starter-data-redis-reactive“Starter”,以与其他具有 Reactive 支持的 Store 保持一致。

连接到Redis

您可以像注入其他任何 Spring Bean 一样注入自动配置的RedisConnectionFactoryStringRedisTemplate或香草RedisTemplate实例。默认情况下,该实例尝试连接到localhost:6379的 Redis 服务器。下面的 Lists 显示了这种 Bean 的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Component
public class MyBean {

private StringRedisTemplate template;

@Autowired
public MyBean(StringRedisTemplate template) {
this.template = template;
}

// ...

}

Tip

您还可以注册任意数量的实现LettuceClientConfigurationBuilderCustomizer的 bean,以进行更高级的自定义。如果您使用 Jedis,则JedisClientConfigurationBuilderCustomizer也可用。

如果添加自己的任何自动配置类型的@Bean,它将替换默认值(除非RedisTemplate,但排除基于 Bean 名称redisTemplate而不是其类型,则除外)。默认情况下,如果commons-pool2在 Classpath 上,则将得到一个池化连接工厂。

MongoDB

MongoDB是一个开源 NoSQL 文档数据库,它使用类似 JSON 的架构而不是传统的基于表的关系数据。 Spring Boot 为使用 MongoDB 提供了许多便利,包括spring-boot-starter-data-mongodbspring-boot-starter-data-mongodb-reactive“启动器”。

连接到MongoDB数据库

要访问 Mongo 数据库,您可以注入自动配置的org.springframework.data.mongodb.MongoDbFactory。默认情况下,该实例尝试连接到mongodb://localhost/test的 MongoDB 服务器。以下示例显示如何连接到 MongoDB 数据库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import org.springframework.data.mongodb.MongoDbFactory;
import com.mongodb.DB;

@Component
public class MyBean {

private final MongoDbFactory mongo;

@Autowired
public MyBean(MongoDbFactory mongo) {
this.mongo = mongo;
}

// ...

public void example() {
DB db = mongo.getDb();
// ...
}

}

您可以设置spring.data.mongodb.uri属性来更改 URL 并配置其他设置,例如 replica set ,如以下示例所示:

1
spring.data.mongodb.uri=mongodb://user:[emailprotected]:12345,mongo2.example.com:23456/test

另外,只要您使用 Mongo 2.x,就可以指定host/port。例如,您可以在application.properties中声明以下设置:

1
2
spring.data.mongodb.host=mongoserver
spring.data.mongodb.port=27017

如果您定义了自己的MongoClient,它将用于自动配置合适的MongoDbFactorycom.mongodb.MongoClientcom.mongodb.client.MongoClient均受支持。

Note

如果使用 Mongo 3.0 Java 驱动程序,则不支持spring.data.mongodb.hostspring.data.mongodb.port。在这种情况下,应使用spring.data.mongodb.uri提供所有配置。

Tip

如果未指定spring.data.mongodb.port,则使用默认值27017。您可以从前面显示的示例中删除此行。

Tip

如果您不使用 Spring Data Mongo,则可以注入com.mongodb.MongoClient bean 而不是MongoDbFactory。如果要完全控制构建 MongoDB 连接的方式,则还可以声明自己的MongoDbFactoryMongoClient bean。

Note

如果使用 Reactive 驱动程序,则 SSL 需要 Netty。如果 Netty 可用并且尚未自定义要使用的工厂,则自动配置会自动配置该工厂。

MongoTemplate

Spring Data MongoDB提供的MongoTemplate类的设计与 Spring 的JdbcTemplate非常相似。与JdbcTemplate一样,Spring Boot 为您自动配置一个 Bean 来注入模板,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

private final MongoTemplate mongoTemplate;

@Autowired
public MyBean(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}

// ...

}

有关完整的详细信息,请参见MongoOperations Javadoc

SpringDataMongoDB存储库

Spring Data 包括对 MongoDB 的存储库支持。与前面讨论的 JPA 存储库一样,基本原理是根据方法名称自动构造查询。

实际上,Spring Data JPA 和 Spring Data MongoDB 共享相同的通用基础架构。您可以从前面的 JPA 示例开始,并假设City现在是 Mongo 数据类而不是 JPA @Entity,它的工作方式相同,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
package com.example.myapp.domain;

import org.springframework.data.domain.*;
import org.springframework.data.repository.*;

public interface CityRepository extends Repository<City, Long> {

Page<City> findAll(Pageable pageable);

City findByNameAndStateAllIgnoringCase(String name, String state);

}

Tip

您可以使用@EntityScanComments 来自定义文档扫描位置。

Tip

有关 Spring Data MongoDB 的完整详细信息,包括其丰富的对象 Map 技术,请参阅其reference documentation

嵌入式Mongo

Spring Boot 为Embedded Mongo提供自动配置。要在您的 Spring Boot 应用程序中使用它,请在de.flapdoodle.embed:de.flapdoodle.embed.mongo上添加一个依赖项。

可以通过设置spring.data.mongodb.port属性来配置 Mongo 侦听的端口。要使用随机分配的空闲端口,请使用 0 值。由MongoAutoConfiguration创建的MongoClient自动配置为使用随机分配的端口。

Note

如果未配置自定义端口,则默认情况下,嵌入式支持使用随机端口(而不是 27017)。

如果 Classpath 上有 SLF4J,则 Mongo 产生的输出将自动路由到名为org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongo的 Logger。

您可以声明自己的IMongodConfigIRuntimeConfig bean 来控制 Mongo 实例的配置和日志记录路由。

Neo4j

Neo4j是一个开源 NoSQL 图形数据库,它使用通过一级关系连接的节点的丰富数据模型,比传统的 RDBMS 方法更适合于连接的大数据。 Spring Boot 为 Neo4j 的使用提供了许多便利,包括spring-boot-starter-data-neo4j“ Starter”。

连接到Neo4j数据库

要访问 Neo4j 服务器,您可以注入自动配置的org.neo4j.ogm.session.Session。默认情况下,该实例尝试使用 Bolt 协议连接到localhost:7687处的 Neo4j 服务器。以下示例显示如何注入 Neo4j Session

1
2
3
4
5
6
7
8
9
10
11
12
13
@Component
public class MyBean {

private final Session session;

@Autowired
public MyBean(Session session) {
this.session = session;
}

// ...

}

您可以通过设置spring.data.neo4j.*属性来配置要使用的 uri 和凭据,如以下示例所示:

1
2
3
spring.data.neo4j.uri=bolt://my-server:7687
spring.data.neo4j.username=neo4j
spring.data.neo4j.password=secret

您可以通过添加org.neo4j.ogm.config.Configuration @Bean来完全控制会话的创建。另外,添加类型为SessionFactory@Bean会禁用自动配置,并提供完全控制权。

使用嵌入式模式

如果您将org.neo4j:neo4j-ogm-embedded-driver添加到应用程序的依赖项中,则 Spring Boot 将自动配置 Neo4j 的进程内嵌入式实例,该实例在应用程序关闭时不会保留任何数据。

Note

由于嵌入式 Neo4j OGM 驱动程序本身不提供 Neo4j 内核,因此您必须自己声明org.neo4j:neo4j作为依赖项。有关兼容版本的列表,请参考Neo4j OGM 文档

当 Classpath 上有多个驱动程序时,嵌入式驱动程序优先于其他驱动程序。您可以通过设置spring.data.neo4j.embedded.enabled=false显式禁用嵌入式模式。

如上所述,如果嵌入式驱动程序和 Neo4j 内核位于 Classpath 中,则数据 Neo4j 测试自动使用嵌入式 Neo4j 实例。

Note

您可以通过在配置中提供数据库文件的路径来启用嵌入式模式的持久性。 spring.data.neo4j.uri=file://var/tmp/graph.db

Neo4jSession

默认情况下,如果您正在运行 Web 应用程序,则会话将绑定到线程以进行请求的整个处理(即,它使用“在视图中打开会话”模式)。如果您不希望出现这种情况,请将以下行添加到您的application.properties文件中:

1
spring.data.neo4j.open-in-view=false

SpringDataNeo4j存储库

Spring Data 包括对 Neo4j 的存储库支持。

Spring Data Neo4j 与许多其他 Spring Data 模块一样,与 Spring Data JPA 共享公共基础结构。您可以使用前面的 JPA 示例,并将City定义为 Neo4j OGM @NodeEntity而不是 JPA @Entity,并且存储库抽象以相同的方式工作,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
package com.example.myapp.domain;

import java.util.Optional;

import org.springframework.data.neo4j.repository.*;

public interface CityRepository extends Neo4jRepository<City, Long> {

Optional<City> findOneByNameAndState(String name, String state);

}

spring-boot-starter-data-neo4j“启动器”启用存储库支持以及事务 Management。您可以通过分别在@Configuration -bean 上使用@EnableNeo4jRepositories@EntityScan来定制位置以查找存储库和实体。

Tip

有关 Spring Data Neo4j 的完整详细信息,包括其对象 Map 技术,请参阅reference documentation

Gemfire

Spring Data Gemfire提供了方便使用 Spring 的便捷工具,用于访问Pivotal Gemfire数据 Management 平台。有一个spring-boot-starter-data-gemfire“启动器”,用于以方便的方式收集依赖项。 Gemfire 当前没有自动配置支持,但是您可以使用单个 Comments:@EnableGemfireRepositories启用 Spring Data Repositories。

Solr

Apache Solr是搜索引擎。 Spring Boot 为 Solr 5 Client 端库提供了基本的自动配置,并由Spring Data Solr提供了对它的抽象。有一个spring-boot-starter-data-solr“启动程序”,用于以方便的方式收集依赖项。

连接到Solr

您可以像注入其他任何 Spring bean 一样注入自动配置的SolrClient实例。默认情况下,该实例尝试连接到localhost:8983/solr处的服务器。下面的示例显示如何注入 Solr bean:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Component
public class MyBean {

private SolrClient solr;

@Autowired
public MyBean(SolrClient solr) {
this.solr = solr;
}

// ...

}

如果添加自己的SolrClient类型的@Bean,它将替换默认值。

SpringDataSolr存储库

Spring Data 包括对 Apache Solr 的存储库支持。与前面讨论的 JPA 存储库一样,基本原理是根据方法名称自动为\构造查询。

实际上,Spring Data JPA 和 Spring Data Solr 共享相同的通用基础结构。您可以从以前的 JPA 示例开始,并假设City现在是@SolrDocument类而不是 JPA @Entity,它的工作方式相同。

Tip

有关 Spring Data Solr 的完整详细信息,请参阅reference documentation

Elasticsearch

Elasticsearch是开源,分布式,RESTful 搜索和分析引擎。 Spring Boot 为 Elasticsearch 提供了基本的自动配置。

Spring Boot 支持多个 HTTP Client 端:

  • 官方 Java“低级”和“高级” REST Client 端
  • Jest

Spring Data Elasticsearch仍在使用传输 Client 端,您可以从spring-boot-starter-data-elasticsearch“ Starter”开始使用。

通过 RESTClient端连接到Elasticsearch

Elasticsearch 附带了两个不同的 REST Client 端,可用于查询集群:“低级”Client 端和“高级”Client 端。

如果您对 Classpath 具有org.elasticsearch.client:elasticsearch-rest-client依赖关系,Spring Boot 将自动配置并注册一个RestClient bean,默认情况下它针对localhost:9200。您可以进一步调整RestClient的配置方式,如以下示例所示:

1
2
3
spring.elasticsearch.rest.uris=http://search.example.com:9200
spring.elasticsearch.rest.username=user
spring.elasticsearch.rest.password=secret

您还可以注册任意数量的实现RestClientBuilderCustomizer的 bean,以进行更高级的自定义。要完全控制注册,请定义一个RestClient bean。

如果您对 Classpath 具有org.elasticsearch.client:elasticsearch-rest-high-level-client依赖性,则 Spring Boot 将自动配置RestHighLevelClient,该_包装任何现有的RestClient bean,并重新使用其 HTTP 配置。

使用Jest连接到Elasticsearch

如果您在 Classpath 上有Jest,则可以注入自动配置的JestClient,默认情况下以localhost:9200为目标。您可以进一步调整 Client 端的配置方式,如以下示例所示:

1
2
3
4
spring.elasticsearch.jest.uris=http://search.example.com:9200
spring.elasticsearch.jest.read-timeout=10000
spring.elasticsearch.jest.username=user
spring.elasticsearch.jest.password=secret

您还可以注册任意数量的实现HttpClientConfigBuilderCustomizer的 bean,以进行更高级的自定义。以下示例调整其他 HTTP 设置:

1
2
3
4
5
6
7
8
static class HttpSettingsCustomizer implements HttpClientConfigBuilderCustomizer {

@Override
public void customize(HttpClientConfig.Builder builder) {
builder.maxTotalConnection(100).defaultMaxTotalConnectionPerRoute(5);
}

}

要完全控制注册,请定义一个JestClient bean。

使用Spring数据连接到Elasticsearch

要连接到 Elasticsearch,您必须提供一个或多个集群节点的地址。可以通过将spring.data.elasticsearch.cluster-nodes属性设置为逗号分隔的host:port列表来指定地址。有了此配置后,就可以像其他任何 Spring bean 一样注入ElasticsearchTemplateTransportClient,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
spring.data.elasticsearch.cluster-nodes=localhost:9300
@Component
public class MyBean {

private final ElasticsearchTemplate template;

public MyBean(ElasticsearchTemplate template) {
this.template = template;
}

// ...

}

如果添加自己的ElasticsearchTemplateTransportClient @Bean,它将替换默认值。

SpringDataElasticsearch存储库

Spring Data 包括对 Elasticsearch 的存储库支持。与前面讨论的 JPA 存储库一样,基本原理是根据方法名称自动为您构造查询。

实际上,Spring Data JPA 和 Spring Data Elasticsearch 共享相同的通用基础架构。您可以从前面的 JPA 示例开始,并假设City现在是 Elasticsearch @Document类而不是 JPA @Entity,它的工作方式相同。

Tip

有关 Spring Data Elasticsearch 的完整详细信息,请参阅reference documentation

Cassandra

Cassandra是一个开放源代码的分布式数据库 Management 系统,旨在处理许多商品服务器上的大量数据。 Spring Boot 为 Cassandra 提供自动配置,并由Spring Data Cassandra提供最高级的抽象。有一个spring-boot-starter-data-cassandra“启动程序”,用于以方便的方式收集依赖项。

连接到Cassandra

您可以像使用其他任何 Spring Bean 一样注入自动配置的CassandraTemplate或 Cassandra Session实例。 spring.data.cassandra.*属性可用于自定义连接。通常,您提供keyspace-namecontact-points属性,如以下示例所示:

1
2
spring.data.cassandra.keyspace-name=mykeyspace
spring.data.cassandra.contact-points=cassandrahost1,cassandrahost2

您还可以注册任意数量的实现ClusterBuilderCustomizer的 bean,以进行更高级的自定义。

以下代码 Lists 显示了如何注入 Cassandra bean:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Component
public class MyBean {

private CassandraTemplate template;

@Autowired
public MyBean(CassandraTemplate template) {
this.template = template;
}

// ...

}

如果添加自己的CassandraTemplate类型的@Bean,它将替换默认值。

SpringDataCassandra存储库

Spring Data 包括对 Cassandra 的基本存储库支持。当前,这比前面讨论的 JPA 存储库受到更多限制,并且需要使用@QueryComments finder 方法。

Tip

有关 Spring Data Cassandra 的完整详细信息,请参阅reference documentation

Couchbase

Couchbase是开放源代码,分布式,多模型的 NoSQL 面向文档的数据库,已针对交互式应用程序进行了优化。 Spring Boot 为 Couchbase 提供自动配置,并由Spring Data Couchbase提供最高级的抽象。有spring-boot-starter-data-couchbasespring-boot-starter-data-couchbase-reactive个“启动程序”,以方便的方式收集依赖项。

连接到Couchbase

您可以通过添加 Couchbase SDK 和一些配置来获得BucketClusterspring.couchbase.*属性可用于自定义连接。通常,您提供引导主机,存储桶名称和密码,如以下示例所示:

1
2
3
spring.couchbase.bootstrap-hosts=my-host-1,192.168.1.123
spring.couchbase.bucket.name=my-bucket
spring.couchbase.bucket.password=secret

Tip

您至少需要提供*引导主机,在这种情况下,存储区名称为default,密码为空字符串。另外,您可以定义自己的org.springframework.data.couchbase.config.CouchbaseConfigurer @Bean来控制整个配置。

还可以自定义某些CouchbaseEnvironment设置。例如,以下配置更改了用于打开新的Bucket的超时并启用了 SSL 支持:

1
2
3
spring.couchbase.env.timeouts.connect=3000
spring.couchbase.env.ssl.key-store=/location/of/keystore.jks
spring.couchbase.env.ssl.key-store-password=secret

查看spring.couchbase.env.*属性以获取更多详细信息。

SpringDataCouchbase存储库

Spring Data 包括对 Couchbase 的存储库支持。有关 Spring Data Couchbase 的完整详细信息,请参阅reference documentation

您可以像使用任何其他 Spring Bean 一样注入自动配置的CouchbaseTemplate实例,前提是 default CouchbaseConfigurer可用(如前所述,启用 Couchbase 支持时会发生这种情况)。

以下示例显示了如何注入 Couchbase bean:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Component
public class MyBean {

private final CouchbaseTemplate template;

@Autowired
public MyBean(CouchbaseTemplate template) {
this.template = template;
}

// ...

}

您可以在自己的配置中定义一些 Bean,以覆盖自动配置提供的那些:

  • 名称为couchbaseTemplateCouchbaseTemplate @Bean
  • 名为couchbaseIndexManagerIndexManager @Bean
  • 名称为couchbaseCustomConversionsCustomConversions @Bean

为了避免在您自己的配置中对这些名称进行硬编码,您可以重复使用 Spring Data Couchbase 提供的BeanNames。例如,您可以自定义要使用的转换器,如下所示:

1
2
3
4
5
6
7
8
9
10
11
@Configuration
public class SomeConfiguration {

@Bean(BeanNames.COUCHBASE_CUSTOM_CONVERSIONS)
public CustomConversions myCustomConversions() {
return new CustomConversions(...);
}

// ...

}

Tip

如果您想完全绕过 Spring Data Couchbase 的自动配置,请提供自己的org.springframework.data.couchbase.config.AbstractCouchbaseDataConfiguration实现。

LDAP

LDAP(轻型目录访问协议)是一种开放的,与供应商无关的行业标准应用程序协议,用于通过 IP 网络访问和维护分布式目录信息服务。 Spring Boot 为任何兼容的 LDAP 服务器提供自动配置,并从UnboundID支持嵌入式内存 LDAP 服务器。

Spring Data LDAP提供 LDAP 抽象。有一个spring-boot-starter-data-ldap“启动程序”,以方便的方式收集依赖项。

连接到LDAP服务器

要连接到 LDAP 服务器,请确保声明对spring-boot-starter-data-ldap“ Starter”或spring-ldap-core的依赖关系,然后在 application.properties 中声明服务器的 URL,如以下示例所示:

1
2
3
spring.ldap.urls=ldap://myserver:1235
spring.ldap.username=admin
spring.ldap.password=secret

如果需要自定义连接设置,则可以使用spring.ldap.basespring.ldap.base-environment属性。

LdapContextSource是根据这些设置自动配置的。如果您需要对其进行自定义(例如使用PooledContextSource),则仍可以注入自动配置的LdapContextSource。确保将自定义的ContextSource标记为@Primary,以便自动配置的LdapTemplate使用它。

SpringDataLDAP存储库

Spring Data 包括对 LDAP 的存储库支持。有关 Spring Data LDAP 的完整详细信息,请参阅reference documentation

您还可以像使用其他任何 Spring Bean 一样注入自动配置的LdapTemplate实例,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Component
public class MyBean {

private final LdapTemplate template;

@Autowired
public MyBean(LdapTemplate template) {
this.template = template;
}

// ...

}

嵌入式内存LDAP服务器

出于测试目的,Spring Boot 支持从UnboundID自动配置内存中的 LDAP 服务器。要配置服务器,请将依赖项添加到com.unboundid:unboundid-ldapsdk并声明base-dn属性,如下所示:

1
spring.ldap.embedded.base-dn=dc=spring,dc=io

Note

可以定义多个 base-dn 值,但是,由于可分辨的名称通常包含逗号,因此必须使用正确的符号来定义它们。

在 yaml 文件中,您可以使用 yaml 列表符号:

1
2
3
spring.ldap.embedded.base-dn:
- dc=spring,dc=io
- dc=pivotal,dc=io

在属性文件中,必须将索引包括在属性名称中:

1
2
spring.ldap.embedded.base-dn[0]=dc=spring,dc=io
spring.ldap.embedded.base-dn[1]=dc=pivotal,dc=io

默认情况下,服务器在随机端口上启动并触发常规 LDAP 支持。无需指定spring.ldap.urls属性。

如果您的 Classpath 上有一个schema.ldif文件,它将用于初始化服务器。如果要从其他资源加载初始化脚本,则也可以使用spring.ldap.embedded.ldif属性。

默认情况下,使用标准架构来验证LDIF个文件。您可以通过设置spring.ldap.embedded.validation.enabled属性完全关闭验证。如果您具有自定义属性,则可以使用spring.ldap.embedded.validation.schema定义您的自定义属性类型或对象类。

InfluxDB

InfluxDB是开放源代码的时间序列数据库,已优化用于在操作监视,应用程序度量,物联网传感器数据和实时分析等领域中快速,高可用性地存储和检索时间序列数据。

连接到nfluxDB

只要influxdb-javaClient 端位于 Classpath 上并且设置了数据库的 URL,Spring Boot 就会自动配置InfluxDB实例,如以下示例所示:

1
spring.influx.url=http://172.0.0.1:8086

如果与 InfluxDB 的连接需要用户和密码,则可以相应地设置spring.influx.userspring.influx.password属性。

InfluxDB 依赖 OkHttp。如果需要在后台调整 http Client 端InfluxDB的使用,则可以注册InfluxDbOkHttpClientBuilderProvider bean。

Caching

Spring 框架提供了对向应用程序透明添加缓存的支持。从本质上讲,抽象将缓存应用于方法,从而根据缓存中可用的信息减少执行次数。缓存逻辑是透明应用的,不会对调用者造成任何干扰。只要通过@EnableCachingComments 启用了缓存支持,Spring Boot 就会自动配置缓存基础结构。

Note

查看 Spring 框架参考的relevant section以获得更多详细信息。

简而言之,将缓存添加到服务的操作就像将相关 Comments 添加到其方法一样容易,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;

@Component
public class MathService {

@Cacheable("piDecimals")
public int computePiDecimal(int i) {
// ...
}

}

本示例说明了在可能耗资巨大的操作上使用缓存的方法。在调用computePiDecimal之前,抽象将在piDecimals缓存中查找与i参数匹配的条目。如果找到条目,则高速缓存中的内容会立即返回给调用方,并且不会调用该方法。否则,将调用该方法,并在返回值之前更新缓存。

Warning

您还可以透明地使用标准 JSR-107(JCache)注解(例如@CacheResult)。但是,我们强烈建议您不要混合使用 Spring Cache 和 JCache 注解。

如果您不添加任何特定的缓存库,Spring Boot 会自动配置一个使用内存中并发 Map 的simple provider。需要缓存时(例如上例中的piDecimals),此提供程序将为您创建它。实际上,不建议将简单提供程序用于生产用途,但是它对于 Starter 并确保您了解功能非常有用。确定要使用的缓存提供程序后,请确保阅读其文档,以了解如何配置应用程序使用的缓存。几乎所有提供程序都要求您显式配置在应用程序中使用的每个缓存。有些提供了一种自定义spring.cache.cache-names属性定义的默认缓存的方法。

Tip

也可以透明地从缓存中updateevict数据。

支持的缓存提供程序

缓存抽象不提供实际的存储,而是依赖于org.springframework.cache.Cacheorg.springframework.cache.CacheManager接口实现的抽象。

如果尚未定义类型CacheManager或名为cacheResolverCacheResolver(请参见CachingConfigurer),则 Spring Boot 尝试检测以下提供程序(按指示的 Sequences):

Tip

也可以通过设置spring.cache.type属性来“强制”特定的缓存提供程序。如果需要在某些环境(例如测试)中完全禁用缓存,请使用此属性。

Tip

使用spring-boot-starter-cache“Starter”快速添加基本的缓存依赖项。启动器带来spring-context-support。如果手动添加依赖项,则必须包含spring-context-support才能使用 JCache,EhCache 2.x 或 Guava 支持。

如果CacheManager是由 Spring Boot 自动配置的,则可以通过公开实现CacheManagerCustomizer接口的 bean,在完全初始化之前进一步调整其配置。下面的示例设置一个标志,指示应该将空值向下传递到基础 Map:

1
2
3
4
5
6
7
8
9
@Bean
public CacheManagerCustomizer<ConcurrentMapCacheManager> cacheManagerCustomizer() {
return new CacheManagerCustomizer<ConcurrentMapCacheManager>() {
@Override
public void customize(ConcurrentMapCacheManager cacheManager) {
cacheManager.setAllowNullValues(false);
}
};
}

Note

在前面的示例中,应使用自动配置的ConcurrentMapCacheManager。如果不是这种情况(您提供了自己的配置,或者自动配置了其他缓存提供程序),则根本不会调用定制程序。您可以根据需要拥有任意数量的定制程序,也可以使用@OrderOrdered对其进行排序。

Generic

如果上下文至少定义了一个org.springframework.cache.Cache bean,则使用通用缓存。创建一个CacheManager包装该类型的所有 bean。

JCache(JSR-107)

JCache通过 Classpath 上存在javax.cache.spi.CachingProvider进行引导(即,Classpath 上存在符合 JSR-107 的缓存库),并且JCacheCacheManagerspring-boot-starter-cache“启动程序”提供。提供了各种兼容的库,Spring Boot 为 Ehcache 3,Hazelcast 和 Infinispan 提供了依赖 Management。也可以添加任何其他兼容的库。

可能会出现多个提供者,在这种情况下,必须明确指定提供者。即使 JSR-107 标准没有强制采用标准化的方式来定义配置文件的位置,Spring Boot 也会尽其所能以设置具有实现细节的缓存,如以下示例所示:

1
2
3
# Only necessary if more than one provider is present
spring.cache.jcache.provider=com.acme.MyCachingProvider
spring.cache.jcache.config=classpath:acme.xml

Note

当缓存库同时提供本机实现和 JSR-107 支持时,Spring Boot 会首选 JSR-107 支持,因此,如果您切换到其他 JSR-107 实现,则可以使用相同的功能。

Tip

Spring Boot 具有对 Hazelcast 的常规支持。如果有一个HazelcastInstance可用,则除非指定spring.cache.jcache.config属性,否则它也会自动为CacheManager重用。

自定义基础javax.cache.cacheManager的方法有两种:

  • 可以在启动时通过设置spring.cache.cache-names属性来创建缓存。如果定义了自定义javax.cache.configuration.Configuration bean,则将其用于自定义它们。
  • org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer bean 与CacheManager的引用一起调用以进行完全自定义。

Tip

如果定义了一个标准的javax.cache.CacheManager bean,它将自动包装在抽象期望的org.springframework.cache.CacheManager实现中。不再对其应用定制。

EhCache2.x

如果可以在 Classpath 的根目录下找到名为ehcache.xml的文件,则使用EhCache2.x。如果找到 EhCache 2.x,则使用spring-boot-starter-cache“启动程序”提供的EhCacheCacheManager来引导缓存 Management 器。也可以提供备用配置文件,如以下示例所示:

1
spring.cache.ehcache.config=classpath:config/another-config.xml

Hazelcast缓存

Spring Boot 具有对 Hazelcast 的常规支持。如果已自动配置HazelcastInstance,则会自动将其包装在CacheManager中。

Infinispan

Infinispan没有默认配置文件位置,因此必须明确指定。否则,将使用默认的引导程序。

1
spring.cache.infinispan.config=infinispan.xml

可以在启动时通过设置spring.cache.cache-names属性来创建缓存。如果定义了自定义ConfigurationBuilder bean,则用于自定义缓存。

Note

Spring Boot 对 Infinispan 的支持仅限于嵌入式模式,并且非常基础。如果您需要更多选择,则应该使用官方的 Infinispan Spring Boot 启动程序。有关更多详细信息,请参见Infinispan’s documentation

Couchbase

如果Couchbase Java Client 端和couchbase-spring-cache实现可用且 Couchbase 为configured,则将自动配置CouchbaseCacheManager。也可以通过设置spring.cache.cache-names属性在启动时创建其他缓存。这些缓存在自动配置的Bucket上运行。您还可以*使用定制程序在另一个Bucket上创建其他缓存。假设您在“主” Bucket上需要两个缓存(cache1cache2),在(另一个)Bucket上需要一个缓存(cache3)的自定义时间为 2 秒。您可以通过配置创建前两个缓存,如下所示:

1
spring.cache.cache-names=cache1,cache2

然后,您可以定义一个@Configuration类来配置额外的Bucketcache3缓存,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Configuration
public class CouchbaseCacheConfiguration {

private final Cluster cluster;

public CouchbaseCacheConfiguration(Cluster cluster) {
this.cluster = cluster;
}

@Bean
public Bucket anotherBucket() {
return this.cluster.openBucket("another", "secret");
}

@Bean
public CacheManagerCustomizer<CouchbaseCacheManager> cacheManagerCustomizer() {
return c -> {
c.prepareCache("cache3", CacheBuilder.newInstance(anotherBucket())
.withExpiration(2));
};
}

}

此示例配置重复使用通过自动配置创建的Cluster

Redis

如果Redis可用并已配置,则将自动配置RedisCacheManager。可以通过设置spring.cache.cache-names属性在启动时创建其他缓存,并且可以使用spring.cache.redis.*属性配置缓存默认值。例如,以下配置创建了“生存时间”为 10 分钟的cache1cache2缓存:

1
2
spring.cache.cache-names=cache1,cache2
spring.cache.redis.time-to-live=600000

Note

默认情况下,添加密钥前缀,以便如果两个单独的缓存使用相同的密钥,则 Redis 不会有重叠的密钥,并且不能返回无效值。如果您创建自己的RedisCacheManager,强烈建议您启用此设置。

Tip

您可以添加自己的RedisCacheConfiguration @Bean,从而完全控制配置。如果您要自定义序列化策略,这将很有用。

Caffeine

Caffeine是对 Guava 缓存的 Java 8 重写,取代了对 Guava 的支持。如果存在 Caffeine,则会自动配置CaffeineCacheManager(由spring-boot-starter-cache“Starter”提供)。缓存可以在启动时通过设置spring.cache.cache-names属性来创建,并且可以通过以下方式之一自定义(按指示的 Sequences):

  • spring.cache.caffeine.spec定义的缓存规范
  • 定义了一个com.github.benmanes.caffeine.cache.CaffeineSpec bean
  • 定义了一个com.github.benmanes.caffeine.cache.Caffeine bean

例如,以下配置创建cache1cache2缓存,最大大小为 500,并且生存时间为 10 分钟

1
2
spring.cache.cache-names=cache1,cache2
spring.cache.caffeine.spec=maximumSize=500,expireAfterAccess=600s

如果定义了com.github.benmanes.caffeine.cache.CacheLoader bean,它将自动与CaffeineCacheManager关联。由于CacheLoader将与由缓存 Management 器 Management 的 all 缓存相关联,因此必须将其定义为CacheLoader<Object, Object>。自动配置将忽略任何其他通用类型。

Simple

如果找不到其他提供者,则配置使用ConcurrentHashMap作为缓存存储区的简单实现。如果您的应用程序中不存在任何缓存库,则这是默认设置。默认情况下,将根据需要创建缓存,但是您可以通过设置cache-names属性来限制可用缓存的列表。例如,如果只需要cache1cache2缓存,则按如下所示设置cache-names属性:

1
spring.cache.cache-names=cache1,cache2

如果这样做,并且您的应用程序使用了未列出的缓存,那么当需要该缓存时,它将在运行时失败,但不会在启动时失败。这类似于使用未声明的缓存时“实际”缓存提供程序的行为。

None

当您的配置中包含@EnableCaching时,也需要合适的缓存配置。如果需要在某些环境中完全禁用缓存,请强制将缓存类型设置为none以使用无操作实现,如以下示例所示:

1
spring.cache.type=none

消息

Spring 框架为与消息传递系统集成提供了广泛的支持,从简化使用JmsTemplate的 JMS API 的使用到完整的异步接收消息的基础结构。 Spring AMQP 为高级消息队列协议提供了类似的功能集。 Spring Boot 还为RabbitTemplate和 RabbitMQ 提供了自动配置选项。 Spring WebSocket 本身就包含对 STOMP 消息的支持,而 Spring Boot 通过启动程序和少量的自动配置对此提供了支持。 Spring Boot 还支持 Apache Kafka。

JMS

javax.jms.ConnectionFactory接口提供了创建javax.jms.Connection与 JMS 代理进行交互的标准方法。尽管 Spring 需要ConnectionFactory才能与 JMS 一起使用,但是您通常不需要自己直接使用它,而是可以依靠更高级别的消息抽象。 (有关详细信息,请参见 Spring Framework 参考文档的relevant section。)Spring Boot 还自动配置必要的基础结构来发送和接收消息。

ActiveMQ支持

ActiveMQ在 Classpath 上可用时,Spring Boot 也可以配置ConnectionFactory。如果存在代理,则将自动启动和配置嵌入式代理(前提是未通过配置指定代理 URL)。

Note

如果使用spring-boot-starter-activemq,则将提供连接或嵌入 ActiveMQ 实例所需的依赖关系,以及与 JMS 集成的 Spring 基础结构。

ActiveMQ 配置由spring.activemq.*中的外部配置属性控制。例如,您可以在application.properties中声明以下部分:

1
2
3
spring.activemq.broker-url=tcp://192.168.1.210:9876
spring.activemq.user=admin
spring.activemq.password=secret

默认情况下,CachingConnectionFactory使用可以由spring.jms.*中的外部配置属性控制的明智设置来包装本机ConnectionFactory

1
spring.jms.cache.session-cache-size=5

如果您想使用本机池,则可以通过向org.messaginghub:pooled-jms添加依赖项并相应地配置JmsPoolConnectionFactory来实现,如下例所示:

1
2
spring.activemq.pool.enabled=true
spring.activemq.pool.max-connections=50

Tip

有关更多受支持的选项,请参见ActiveMQProperties。您还可以注册任意数量的实现ActiveMQConnectionFactoryCustomizer的 bean,以进行更高级的自定义。

默认情况下,ActiveMQ 将创建一个目的地(如果目的地尚不存在),以便根据其提供的名称来解析目的地。

Artemis支持

当 Spring Boot 检测到Artemis在 Classpath 中可用时,它可以自动配置ConnectionFactory。如果存在代理,则将自动启动和配置嵌入式代理(除非已明确设置 mode 属性)。支持的模式为embedded(以明确要求使用嵌入式代理,并且如果代理在 Classpath 上不可用,则会发生错误)和native(使用netty传输协议连接到代理)。配置后者后,Spring Boot 将使用默认设置配置一个ConnectionFactory,该ConnectionFactory连接到在本地计算机上运行的代理。

Note

如果使用spring-boot-starter-artemis,则将提供连接到现有 Artemis 实例所需的依赖关系,以及与 JMS 集成的 Spring 基础结构。将org.apache.activemq:artemis-jms-server添加到您的应用程序可让您使用嵌入式模式。

Artemis 配置由spring.artemis.*中的外部配置属性控制。例如,您可以在application.properties中声明以下部分:

1
2
3
4
5
spring.artemis.mode=native
spring.artemis.host=192.168.1.210
spring.artemis.port=9876
spring.artemis.user=admin
spring.artemis.password=secret

嵌入代理时,可以选择是否要启用持久性并列出应使其可用的目的地。可以将它们指定为以逗号分隔的列表,以使用默认选项创建它们,也可以为高级队列和主题配置分别定义类型org.apache.activemq.artemis.jms.server.config.JMSQueueConfigurationorg.apache.activemq.artemis.jms.server.config.TopicConfiguration的 bean。

默认情况下,CachingConnectionFactory使用可以由spring.jms.*中的外部配置属性控制的明智设置来包装本机ConnectionFactory

1
spring.jms.cache.session-cache-size=5

如果您想使用本机池,则可以通过向org.messaginghub:pooled-jms添加依赖项并相应地配置JmsPoolConnectionFactory来实现,如下例所示:

1
2
spring.artemis.pool.enabled=true
spring.artemis.pool.max-connections=50

有关更多受支持的选项,请参见ArtemisProperties

不涉及 JNDI 查找,并且使用 Artemis 配置中的name属性或通过配置提供的名称来根据目的地名称解析目的地。

使用JNDI连接工厂

如果您正在应用程序服务器中运行应用程序,则 Spring Boot 会尝试使用 JNDI 查找 JMS ConnectionFactory。默认情况下,选中java:/JmsXAjava:/XAConnectionFactory位置。如果需要指定替代位置,则可以使用spring.jms.jndi-name属性,如以下示例所示:

1
spring.jms.jndi-name=java:/MyConnectionFactory

发送消息

Spring 的JmsTemplate是自动配置的,您可以将其直接自动连接到自己的 bean 中,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

private final JmsTemplate jmsTemplate;

@Autowired
public MyBean(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}

// ...

}

Note

JmsMessagingTemplate可以类似的方式注入。如果定义了DestinationResolverMessageConverter bean,则将其自动关联到自动配置的JmsTemplate

接收消息

存在 JMS 基础结构时,可以使用@JmsListenerComments 任何 bean 以创建侦听器端点。如果未定义JmsListenerContainerFactory,则会自动配置一个默认值。如果定义了DestinationResolverMessageConverter bean,它将自动关联到默认工厂。

默认情况下,默认工厂是事务性的。如果您在存在JtaTransactionManager的基础结构中运行,则默认情况下会将其与侦听器容器关联。如果不是,则启用sessionTransacted标志。在后一种情况下,可以通过在侦听器方法(或其委托)上添加@Transactional来将本地数据存储事务与传入消息的处理相关联。这样可以确保本地事务完成后,传入消息得到确认。这还包括发送已在同一 JMS 会话上执行的响应消息。

以下组件在someQueue目标上创建侦听器端点:

1
2
3
4
5
6
7
8
9
@Component
public class MyBean {

@JmsListener(destination = "someQueue")
public void processMessage(String content) {
// ...
}

}

Tip

有关更多详细信息,请参见@EnableJms 的 Javadoc

如果您需要创建更多的JmsListenerContainerFactory实例,或者想覆盖默认实例,Spring Boot 提供了一个DefaultJmsListenerContainerFactoryConfigurer,您可以使用与自动配置的设置相同的设置来初始化DefaultJmsListenerContainerFactory

例如,以下示例公开了另一个使用特定MessageConverter的工厂:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration
static class JmsConfiguration {

@Bean
public DefaultJmsListenerContainerFactory myFactory(
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory =
new DefaultJmsListenerContainerFactory();
configurer.configure(factory, connectionFactory());
factory.setMessageConverter(myMessageConverter());
return factory;
}

}

然后,您可以在任何带有@JmsListenerComments 的方法中使用工厂,如下所示:

1
2
3
4
5
6
7
8
9
@Component
public class MyBean {

@JmsListener(destination = "someQueue", containerFactory="myFactory")
public void processMessage(String content) {
// ...
}

}

AMQP

高级消息队列协议(AMQP)是面向消息中间件的与平台无关的有线级别协议。 Spring AMQP 项目将 Spring 的核心概念应用于基于 AMQP 的消息传递解决方案的开发。 Spring Boot 为通过 RabbitMQ 使用 AMQP 提供了许多便利,包括spring-boot-starter-amqp“ Starter”。

RabbitMQ 支持

RabbitMQ是基于 AMQP 协议的轻型,可靠,可伸缩和便携式消息代理。 Spring 使用RabbitMQ通过 AMQP 协议进行通信。

RabbitMQ 配置由spring.rabbitmq.*中的外部配置属性控制。例如,您可以在application.properties中声明以下部分:

1
2
3
4
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=secret

如果上下文中存在ConnectionNameStrategy bean,它将自动用于命名由自动配置的ConnectionFactory创建的连接。有关更多受支持的选项,请参见RabbitProperties

Tip

有关更多详细信息,请参见了解 AMQP,RabbitMQ 使用的协议

发送信息

Spring 的AmqpTemplateAmqpAdmin是自动配置的,您可以将它们直接自动连接到自己的 bean 中,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

private final AmqpAdmin amqpAdmin;
private final AmqpTemplate amqpTemplate;

@Autowired
public MyBean(AmqpAdmin amqpAdmin, AmqpTemplate amqpTemplate) {
this.amqpAdmin = amqpAdmin;
this.amqpTemplate = amqpTemplate;
}

// ...

}

Note

RabbitMessagingTemplate可以类似的方式注入。如果定义了MessageConverter bean,它将自动关联到自动配置的AmqpTemplate

如有必要,任何定义为 bean 的org.springframework.amqp.core.Queue都会自动用于在 RabbitMQ 实例上声明相应的队列。

要重试操作,可以在AmqpTemplate上启用重试(例如,在代理连接丢失的情况下):

1
2
spring.rabbitmq.template.retry.enabled=true
spring.rabbitmq.template.retry.initial-interval=2s

默认情况下,重试是禁用的。您还可以pass 语句RabbitRetryTemplateCustomizer bean 来以编程方式自定义RetryTemplate

接收消息

存在 Rabbit 基础结构时,可以使用@RabbitListenerComments 任何 bean 以创建侦听器端点。如果未定义RabbitListenerContainerFactory,则会自动配置默认的SimpleRabbitListenerContainerFactory,并且可以使用spring.rabbitmq.listener.type属性切换到直接容器。如果定义了MessageConverterMessageRecoverer bean,它将自动与默认工厂关联。

以下示例组件在someQueue队列上创建一个侦听器端点:

1
2
3
4
5
6
7
8
9
@Component
public class MyBean {

@RabbitListener(queues = "someQueue")
public void processMessage(String content) {
// ...
}

}

Tip

有关更多详细信息,请参见@EnableRabbit 的 Javadoc

如果您需要创建更多的RabbitListenerContainerFactory实例,或者想覆盖默认实例,Spring Boot 提供了SimpleRabbitListenerContainerFactoryConfigurerDirectRabbitListenerContainerFactoryConfigurer,您可以使用它们设置与自动配置使用的工厂相同的设置来初始化SimpleRabbitListenerContainerFactoryDirectRabbitListenerContainerFactory

Tip

选择哪种容器都没有关系。这两个 bean 通过自动配置公开。

例如,以下配置类公开了另一个使用特定MessageConverter的工厂:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration
static class RabbitConfiguration {

@Bean
public SimpleRabbitListenerContainerFactory myFactory(
SimpleRabbitListenerContainerFactoryConfigurer configurer) {
SimpleRabbitListenerContainerFactory factory =
new SimpleRabbitListenerContainerFactory();
configurer.configure(factory, connectionFactory);
factory.setMessageConverter(myMessageConverter());
return factory;
}

}

然后,您可以使用任何带有@RabbitListenerComments 的方法来使用工厂,如下所示:

1
2
3
4
5
6
7
8
9
@Component
public class MyBean {

@RabbitListener(queues = "someQueue", containerFactory="myFactory")
public void processMessage(String content) {
// ...
}

}

您可以启用重试来处理侦听器引发异常的情况。默认情况下,使用RejectAndDontRequeueRecoverer,但是您可以定义自己的MessageRecoverer。重试用尽后,如果将代理配置为这样做,则消息将被拒绝并被丢弃或路由到死信交换。默认情况下,重试是禁用的。您也可以pass 语句RabbitRetryTemplateCustomizer bean 来以编程方式自定义RetryTemplate

Tip

默认情况下,如果禁用了重试,并且侦听器引发了异常,则会无限期地重试传递。您可以通过两种方式修改此行为:将defaultRequeueRejected属性设置为false,以便尝试进行零次重新传递或抛出AmqpRejectAndDontRequeueException来指示应拒绝该消息。后者是启用重试并达到最大传递尝试次数时使用的机制。

ApacheKafka支持

通过提供spring-kafka项目的自动配置来支持Apache Kafka

Kafka 配置由spring.kafka.*中的外部配置属性控制。例如,您可以在application.properties中声明以下部分:

1
2
spring.kafka.bootstrap-servers=localhost:9092
spring.kafka.consumer.group-id=myGroup

Tip

要在启动时创建主题,请添加NewTopic类型的 Bean。如果该主题已经存在,则将忽略 Bean。

有关更多受支持的选项,请参见KafkaProperties

发送消息

Spring 的KafkaTemplate是自动配置的,您可以直接在自己的 bean 中自动对其进行布线,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Component
public class MyBean {

private final KafkaTemplate kafkaTemplate;

@Autowired
public MyBean(KafkaTemplate kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate;
}

// ...

}

Note

如果定义了属性spring.kafka.producer.transaction-id-prefix,则会自动配置KafkaTransactionManager。同样,如果定义了RecordMessageConverter bean,它将自动与自动配置的KafkaTemplate关联。

接收消息

存在 Apache Kafka 基础结构时,可以使用@KafkaListenerComments 任何 bean 以创建侦听器端点。如果未定义KafkaListenerContainerFactory,则会使用spring.kafka.listener.*中定义的键自动配置一个默认值。

以下组件在someTopic主题上创建侦听器终结点:

1
2
3
4
5
6
7
8
9
@Component
public class MyBean {

@KafkaListener(topics = "someTopic")
public void processMessage(String content) {
// ...
}

}

如果定义了KafkaTransactionManager bean,它将自动与容器工厂关联。同样,如果定义了RecordMessageConverterErrorHandlerAfterRollbackProcessor bean,它将自动与默认工厂关联。

Tip

自定义ChainedKafkaTransactionManager必须标记为@Primary,因为它通常引用自动配置的KafkaTransactionManager bean。

Kafka流

用于 Apache Kafka 的 Spring 提供了一个工厂 bean 来创建StreamsBuilder对象并 Management 其流的生命周期。只要kafka-streams在 Classpath 上并且通过@EnableKafkaStreamsComments 启用 Kafka Streams,Spring Boot 就会自动配置所需的KafkaStreamsConfiguration bean。

启用 Kafka Streams 意味着必须设置应用程序 ID 和引导服务器。可以使用spring.kafka.streams.application-id配置前者,如果未设置,则默认为spring.application.name。后者可以全局设置,也可以仅针对流进行覆盖。

使用专用属性可以使用几个附加属性。可以使用spring.kafka.streams.properties名称空间设置其他任意 Kafka 属性。另请参见“其他 Kafka 属性”

要使用工厂 bean,只需将StreamsBuilder连接到您的@Bean中,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration
@EnableKafkaStreams
static class KafkaStreamsExampleConfiguration {

@Bean
public KStream<Integer, String> kStream(StreamsBuilder streamsBuilder) {
KStream<Integer, String> stream = streamsBuilder.stream("ks1In");
stream.map((k, v) -> new KeyValue<>(k, v.toUpperCase())).to("ks1Out",
Produced.with(Serdes.Integer(), new JsonSerde<>()));
return stream;
}

}

默认情况下,由它创建的StreamBuilder对象 Management 的流将自动启动。您可以使用spring.kafka.streams.auto-startup属性来自定义此行为。

Kafka的其他属性

自动配置支持的属性显示在附录 A,通用应用程序属性中。请注意,在大多数情况下,这些属性(连字符或 camelCase)直接 Map 到 Apache Kafka 点缀属性。有关详细信息,请参阅 Apache Kafka 文档。

这些属性的前几个属性适用于所有组件(生产者,使用者,Management 员和流),但如果您希望使用不同的值,则可以在组件级别上指定。 Apache Kafka 会指定重要性为 HIGH,MEDIUM 或 LOW 的属性。 Spring Boot 自动配置支持所有 HIGH 重要性属性,一些选定的 MEDIUM 和 LOW 属性以及任何没有默认值的属性。

Kafka 支持的属性的子集仅可通过KafkaProperties类直接使用。如果希望使用不直接支持的其他属性来配置生产者或使用者,请使用以下属性:

1
2
3
4
5
spring.kafka.properties.prop.one=first
spring.kafka.admin.properties.prop.two=second
spring.kafka.consumer.properties.prop.three=third
spring.kafka.producer.properties.prop.four=fourth
spring.kafka.streams.properties.prop.five=fifth

这将公共prop.one Kafka 属性设置为first(适用于生产者,Consumer 和 Management 员),将prop.two admin 属性设置为second,将prop.threeConsumer 属性设置为third,将prop.four生产者属性设置为fourth,并将prop.five streams 属性设置为fifth

您还可以如下配置 Spring Kafka JsonDeserializer

1
2
3
spring.kafka.consumer.value-deserializer=org.springframework.kafka.support.serializer.JsonDeserializer
spring.kafka.consumer.properties.spring.json.value.default.type=com.example.Invoice
spring.kafka.consumer.properties.spring.json.trusted.packages=com.example,org.acme

同样,您可以禁用在 Headers 中发送类型信息的JsonSerializer默认行为:

1
2
spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer
spring.kafka.producer.properties.spring.json.add.type.headers=false

Tip

以这种方式设置的属性将覆盖 Spring Boot 显式支持的任何配置项。

使用RestTemplate调用REST服务

如果您需要从应用程序中调用远程 REST 服务,则可以使用 Spring Framework 的RestTemplate类。由于RestTemplate实例在使用前通常需要自定义,因此 Spring Boot 不提供任何单个自动配置的RestTemplate bean。但是,它会自动配置RestTemplateBuilder,可以在需要时创建RestTemplate实例。自动配置的RestTemplateBuilder确保将明智的HttpMessageConverters应用于RestTemplate实例。

以下代码显示了一个典型示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Service
public class MyService {

private final RestTemplate restTemplate;

public MyService(RestTemplateBuilder restTemplateBuilder) {
this.restTemplate = restTemplateBuilder.build();
}

public Details someRestCall(String name) {
return this.restTemplate.getForObject("/{name}/details", Details.class, name);
}

}

Tip

RestTemplateBuilder包含许多可用于快速配置RestTemplate的有用方法。例如,要添加 BASIC 身份验证支持,可以使用builder.basicAuthentication("user", "password").build()

RestTemplate自定义

RestTemplate自定义有三种 Main 方法,具体取决于您希望自定义应用的范围。

要使所有自定义项的范围尽可能缩小,请注入自动配置的RestTemplateBuilder,然后根据需要调用其方法。每个方法调用都返回一个新的RestTemplateBuilder实例,因此自定义仅影响构建器的使用。

要进行应用程序范围的附加自定义,请使用RestTemplateCustomizer bean。所有此类 bean 都会自动注册到自动配置的RestTemplateBuilder中,并应用于使用它构建的任何模板。

以下示例显示了一个定制程序,该定制程序为除192.168.0.5之外的所有主机配置代理的使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static class ProxyCustomizer implements RestTemplateCustomizer {

@Override
public void customize(RestTemplate restTemplate) {
HttpHost proxy = new HttpHost("proxy.example.com");
HttpClient httpClient = HttpClientBuilder.create()
.setRoutePlanner(new DefaultProxyRoutePlanner(proxy) {

@Override
public HttpHost determineProxy(HttpHost target,
HttpRequest request, HttpContext context)
throws HttpException {
if (target.getHostName().equals("192.168.0.5")) {
return null;
}
return super.determineProxy(target, request, context);
}

}).build();
restTemplate.setRequestFactory(
new HttpComponentsClientHttpRequestFactory(httpClient));
}

}

最后,最极端(也是很少使用)的选项是创建自己的RestTemplateBuilder bean。这样做会关闭RestTemplateBuilder的自动配置,并防止使用任何RestTemplateCustomizer bean。

使用WebClient调用REST服务

如果您的 Classpath 中包含 Spring WebFlux,则还可以选择使用WebClient来调用远程 REST 服务。与RestTemplate相比,此 Client 端具有更多的功能感,并且具有完全的 Reactive。您可以在专用的Spring Framework 文档中的部分中了解有关WebClient的更多信息。

Spring Boot 为您创建并预配置了WebClient.Builder;强烈建议将其注入您的组件中并使用它来创建WebClient实例。 Spring Boot 正在配置该构建器以共享 HTTP 资源,以与服务器相同的方式反映编解码器的设置(请参阅WebFlux HTTP 编解码器自动配置,以及更多。

以下代码显示了一个典型示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Service
public class MyService {

private final WebClient webClient;

public MyService(WebClient.Builder webClientBuilder) {
this.webClient = webClientBuilder.baseUrl("http://example.org").build();
}

public Mono<Details> someRestCall(String name) {
return this.webClient.get().uri("/{name}/details", name)
.retrieve().bodyToMono(Details.class);
}

}

WebClient运行时

Spring Boot 将根据应用程序 Classpath 上可用的库自动检测要使用哪个ClientHttpConnector来驱动WebClient。目前,还支持 Reactor Netty 和 Jetty RS Client 端。

默认情况下,spring-boot-starter-webflux启动程序取决于io.projectreactor.netty:reactor-netty,这同时带来了服务器和 Client 端实现。如果选择使用 Jetty 作为反应式服务器,则应在 Jetty 反应式 HTTP Client 端库org.eclipse.jetty:jetty-reactive-httpclient上添加依赖项。对服务器和 Client 端使用相同的技术具有其优势,因为它将自动在 Client 端和服务器之间共享 HTTP 资源。

通过提供自定义的ReactorResourceFactoryJettyResourceFactory bean,开发人员可以覆盖 Jetty 和 Reactor Netty 的资源配置-这将同时应用于 Client 端和服务器。

如果您希望为 Client 端覆盖该选择,则可以定义自己的ClientHttpConnector bean 并完全控制 Client 端配置。

您可以了解有关Spring Framework 参考文档中的 WebClient 配置选项的更多信息。

WebClient自定义

WebClient自定义有三种 Main 方法,具体取决于您希望自定义应用的范围。

要使所有自定义项的范围尽可能缩小,请注入自动配置的WebClient.Builder,然后根据需要调用其方法。 WebClient.Builder实例是有状态的:构建器上的任何更改都会反映在随后使用它创建的所有 Client 端中。如果要使用同一构建器创建多个 Client 端,则也可以考虑使用WebClient.Builder other = builder.clone();克隆该构建器。

要对所有WebClient.Builder实例进行应用程序级的附加自定义,您可以声明WebClientCustomizer bean 并在注入点更改WebClient.Builder

最后,您可以使用原始 API 并使用WebClient.create()。在这种情况下,不会应用任何自动配置或WebClientCustomizer

Validation

只要 JSR-303 实现(例如 Hibernate 验证器)位于 Classpath 上,就会自动启用 Bean 验证 1.1 支持的方法验证功能。这样就可以在 Bean 方法的参数和/或返回值上使用javax.validation约束 Comments。具有此类 Comments 方法的目标类需要在类型级别使用@ValidatedComments 进行 Comments,以便在其方法中搜索内联约束 Comments。

例如,以下服务触发第一个参数的验证,确保其大小在 8 到 10 之间:

1
2
3
4
5
6
7
8
9
10
@Service
@Validated
public class MyBean {

public Archive findByCodeAndAuthor(@Size(min = 8, max = 10) String code,
Author author) {
...
}

}

发送电子邮件

Spring 框架提供了一种使用JavaMailSender接口发送电子邮件的简单抽象方法,而 Spring Boot 为它提供了自动配置以及启动程序模块。

Tip

有关如何使用JavaMailSender的详细说明,请参见reference documentation

如果spring.mail.host和相关库(由spring-boot-starter-mail定义)可用,则如果不存在默认库JavaMailSender,则将创建该库。可以通过spring.mail名称空间中的配置项进一步自定义发送方。有关更多详细信息,请参见MailProperties

特别是,某些默认超时值是无限的,您可能需要更改该值,以避免线程被无响应的邮件服务器阻塞,如以下示例所示:

1
2
3
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=3000
spring.mail.properties.mail.smtp.writetimeout=5000

也可以使用 JNDI 中的现有Session配置JavaMailSender

1
spring.mail.jndi-name=mail/Session

设置jndi-name时,它优先于所有其他与会话相关的其他设置。

JTA 的分布式事务

Spring Boot 通过使用AtomikosBitronix嵌入式事务 Management 器,支持跨多个 XA 资源的分布式 JTA 事务。部署到合适的 Java EE 应用程序服务器时,还支持 JTA 事务。

当检测到 JTA 环境时,使用 Spring 的JtaTransactionManager来 Management 事务。自动配置的 JMS,DataSource 和 JPA Bean 已升级为支持 XA 事务。您可以使用标准的 Spring 习惯用法(例如@Transactional)来参与分布式事务。如果您在 JTA 环境中,并且仍要使用本地事务,则可以将spring.jta.enabled属性设置为false以禁用 JTA 自动配置。

使用Atomikos事物管理器

Atomikos是流行的开源事务 Management 器,可以嵌入到您的 Spring Boot 应用程序中。您可以使用spring-boot-starter-jta-atomikos Starter 引入适当的 Atomikos 库。 Spring Boot 自动配置 Atomikos 并确保将适当的depends-on设置应用于您的 Spring Bean,以正确启动和关闭 Sequences。

默认情况下,Atomikos 事务日志将写入应用程序主目录(应用程序 jar 文件所在的目录)中的transaction-logs目录。您可以通过在application.properties文件中设置spring.jta.log-dir属性来自定义此目录的位置。以spring.jta.atomikos.properties开头的属性也可以用于自定义 Atomikos UserTransactionServiceImp。有关完整的详细信息,请参见AtomikosProperties Javadoc

Note

为了确保多个事务 Management 器可以安全地协调同一资源 Management 器,必须为每个 Atomikos 实例配置一个唯一的 ID。默认情况下,此 ID 是运行 Atomikos 的计算机的 IP 地址。为了确保 Producing 的唯一性,应为应用程序的每个实例将spring.jta.transaction-manager-id属性配置为不同的值。

使用Bitronix事物管理器

Bitronix是流行的开源 JTA 事务 Management 器实现。您可以使用spring-boot-starter-jta-bitronixStarter 程序将适当的 Bitronix 依赖项添加到您的项目中。与 Atomikos 一样,Spring Boot 自动配置 Bitronix 并对您的 bean 进行后处理,以确保启动和关闭 Sequences 正确。

默认情况下,Bitronix 事务日志文件(part1.btmpart2.btm)被写入应用程序主目录中的transaction-logs目录。您可以通过设置spring.jta.log-dir属性来自定义此目录的位置。以spring.jta.bitronix.properties开头的属性也绑定到bitronix.tm.Configuration bean,从而可以进行完全自定义。有关详情,请参见Bitronix documentation

Note

为了确保多个事务 Management 器可以安全地协调同一资源 Management 器,必须为每个 Bitronix 实例配置唯一的 ID。默认情况下,此 ID 是运行 Bitronix 的计算机的 IP 地址。为了确保 Producing 的唯一性,应为应用程序的每个实例将spring.jta.transaction-manager-id属性配置为不同的值。

使用JavaEE托管事务管理器

如果将 Spring Boot 应用程序打包为warear文件并将其部署到 Java EE 应用程序服务器,则可以使用应用程序服务器的内置事务 Management 器。 Spring Boot 尝试通过查看常见的 JNDI 位置(java:comp/UserTransactionjava:comp/TransactionManager等)来自动配置事务 Management 器。如果使用应用程序服务器提供的事务服务,通常还需要确保所有资源都由服务器 Management 并通过 JNDI 公开。 Spring Boot 通过在 JNDI 路径(java:/JmsXAjava:/XAConnectionFactory)中查找ConnectionFactory来尝试自动配置 JMS,您可以使用spring.datasource.jndi-name property来配置DataSource

混合XA和非XAJMS连接

使用 JTA 时,主要的 JMS ConnectionFactory bean 支持 XA,并参与分布式事务。在某些情况下,您可能希望通过使用非 XA ConnectionFactory处理某些 JMS 消息。例如,您的 JMS 处理逻辑可能需要比 XA 超时更长的时间。

如果要使用非 XA ConnectionFactory,则可以注入nonXaJmsConnectionFactory bean 而不是@Primary jmsConnectionFactory bean。为了保持一致性,还使用 Bean 别名xaJmsConnectionFactory提供了jmsConnectionFactory bean。

以下示例显示了如何注入ConnectionFactory个实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
// Inject the primary (XA aware) ConnectionFactory
@Autowired
private ConnectionFactory defaultConnectionFactory;

// Inject the XA aware ConnectionFactory (uses the alias and injects the same as above)
@Autowired
@Qualifier("xaJmsConnectionFactory")
private ConnectionFactory xaConnectionFactory;

// Inject the non-XA aware ConnectionFactory
@Autowired
@Qualifier("nonXaJmsConnectionFactory")
private ConnectionFactory nonXaConnectionFactory;

支持备用嵌入式事务Management器

XAConnectionFactoryWrapperXADataSourceWrapper接口可用于支持其他嵌入式事务 Management 器。这些接口负责包装XAConnectionFactoryXADataSource bean 并将它们作为常规ConnectionFactoryDataSource bean 公开,它们透明地注册了分布式事务。数据源和 JMS 自动配置使用 JTA 变体,前提是您拥有JtaTransactionManager bean 和在ApplicationContext中注册了适当的 XA 包装 bean。

BitronixXAConnectionFactoryWrapperBitronixXADataSourceWrapper提供了有关如何编写 XA 包装程序的良好示例。

Hazelcast

如果Hazelcast位于 Classpath 上,并且找到了合适的配置,则 Spring Boot 会自动配置一个HazelcastInstance,您可以将其插入到应用程序中。

如果定义一个com.hazelcast.config.Config bean,Spring Boot 将使用它。如果您的配置定义了一个实例名称,Spring Boot 会尝试查找一个现有实例,而不是创建一个新实例。

您还可以指定hazelcast.xml配置文件以通过配置使用,如以下示例所示:

1
spring.hazelcast.config=classpath:config/my-hazelcast.xml

否则,Spring Boot 会尝试从默认位置:工作目录中或 Classpath 根目录中的hazelcast.xml查找 Hazelcast 配置。我们还检查hazelcast.config系统属性是否设置。有关更多详细信息,请参见Hazelcast documentation

如果hazelcast-client存在于 Classpath 中,则 Spring Boot 首先尝试通过检查以下配置选项来创建 Client 端:

  • com.hazelcast.client.config.ClientConfig bean 的存在。
  • spring.hazelcast.config属性定义的配置文件。
  • hazelcast.client.config系统属性的存在。
  • 工作目录中或 Classpath 根目录中的hazelcast-client.xml

Note

Spring Boot 也具有对 Hazelcast 的显式缓存支持。如果启用了缓存,则HazelcastInstance将自动包装在CacheManager实现中。

QuartzScheduler

Spring Boot 为使用Quartz scheduler提供了许多便利,其中包括spring-boot-starter-quartz“ Starter”。如果 Quartz 可用,则会自动配置Scheduler(通过SchedulerFactoryBean抽象)。

以下类型的 Bean 被自动拾取并与Scheduler关联:

  • JobDetail:定义特定的作业。可以使用JobBuilder API 构建JobDetail实例。
  • Calendar .
  • Trigger:定义何时触发特定作业。

默认情况下,使用内存中的JobStore。但是,如果您的应用程序中有DataSource bean 可用,并且相应地配置了spring.quartz.job-store-type属性,则可以配置基于 JDBC 的存储,如以下示例所示:

1
spring.quartz.job-store-type=jdbc

使用 JDBC 存储时,可以在启动时初始化模式,如以下示例所示:

1
spring.quartz.jdbc.initialize-schema=always

Warning

默认情况下,使用 Quartz 库随附的标准脚本检测并初始化数据库。这些脚本删除现有表,并在每次重新启动时删除所有触发器。也可以通过设置spring.quartz.jdbc.schema属性来提供自定义脚本。

要让 Quartz 使用除应用程序主DataSource之外的DataSource,请声明DataSource bean,并用@QuartzDataSourceComments 其@Bean方法。这样做可确保SchedulerFactoryBean使用 Quartz 专用的DataSource并用于模式初始化。

默认情况下,通过配置创建的作业将不会覆盖从持久性作业存储中读取的已注册作业。要启用覆盖现有作业定义的功能,请设置spring.quartz.overwrite-existing-jobs属性。

可以使用spring.quartz属性和SchedulerFactoryBeanCustomizer bean 自定义 Quartz Scheduler 配置,从而可以通过编程方式自定义SchedulerFactoryBean。可以使用spring.quartz.properties.*定制高级 Quartz 配置属性。

Note

特别是,Executor bean 没有与调度程序相关联,因为 Quartz 提供了一种通过spring.quartz.properties配置调度程序的方法。如果您需要自定义任务 Actuator,请考虑实现SchedulerFactoryBeanCustomizer

作业可以定义设置器以注入数据 Map 属性。常规 bean 也可以类似的方式注入,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class SampleJob extends QuartzJobBean {

private MyService myService;

private String name;

// Inject "MyService" bean
public void setMyService(MyService myService) { ... }

// Inject the "name" job data property
public void setName(String name) { ... }

@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
...
}

}

任务执行和计划

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

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

1
2
3
spring.task.execution.pool.max-threads=16
spring.task.execution.pool.queue-capacity=100
spring.task.execution.pool.keep-alive=10s

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

如果需要将ThreadPoolTaskScheduler与计划的任务执行(@EnableScheduling)关联,也可以对其进行自动配置。默认情况下,线程池使用一个线程,可以使用spring.task.scheduling名称空间对这些设置进行微调。

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

Spring整合

Spring Boot 为使用Spring Integration提供了许多便利,其中包括spring-boot-starter-integration“ Starter”。 Spring Integration 在消息传递以及其他传输(例如 HTTP,TCP 等)上提供了抽象。如果您的 Classpath 上有 Spring Integration,则可以通过@EnableIntegrationComments 对其进行初始化。

Spring Boot 还配置了一些功能,这些功能由其他 Spring Integration 模块的存在触发。如果spring-integration-jmx也在 Classpath 上,则消息处理统计信息将通过 JMX 发布。如果spring-integration-jdbc可用,则可以在启动时创建默认数据库架构,如以下行所示:

1
spring.integration.jdbc.initialize-schema=always

有关更多详细信息,请参见IntegrationAutoConfigurationIntegrationProperties类。

默认情况下,如果存在 Micrometer meterRegistry bean,那么 Spring Integration Metrics 将由 Micrometer Management。如果您希望使用旧版 Spring Integration Metrics,请将DefaultMetricsFactory bean 添加到应用程序上下文中。

SpringSession

Spring Boot 为广泛的数据存储提供Spring Session自动配置。构建 Servlet Web 应用程序时,可以自动配置以下存储:

  • JDBC
  • Redis
  • Hazelcast
  • MongoDB

构建反应式 Web 应用程序时,可以自动配置以下存储:

  • Redis
  • MongoDB

如果 Classpath 上只有一个 Spring Session 模块,Spring Boot 会自动使用该存储实现。如果您有多个实现,则必须选择要用于存储会话的StoreType。例如,要将 JDBC 用作后端存储,可以按以下方式配置应用程序:

1
spring.session.store-type=jdbc

Tip

您可以通过将store-type设置为none来禁用 Spring Session。

每个 Store 都有特定的其他设置。例如,可以为 JDBC 存储定制表的名称,如以下示例所示:

1
spring.session.jdbc.table-name=SESSIONS

要设置会话超时,您可以使用spring.session.timeout属性。如果未设置该属性,则自动配置将回退到server.servlet.session.timeout的值。

通过JMX进行监视和管理

Java Management 扩展(JMX)提供了监视和 Management 应用程序的标准机制。默认情况下,Spring Boot 创建一个 ID 为mbeanServerMBeanServer bean,并公开任何带有 Spring JMX Comments(@ManagedResource@ManagedAttribute@ManagedOperation)的 bean。

有关更多详细信息,请参见JmxAutoConfiguration类。

Testing

Spring Boot 提供了许多Util和注解,可以在测试应用程序时提供帮助。测试支持由两个模块提供:spring-boot-test包含核心项目,而spring-boot-test-autoconfigure支持自动配置测试。

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

启动程序还带来了老式引擎,因此您可以运行JUnit 4和JUnit 5测试。 如果已将测试迁移到JUnit 5,则应排除对JUnit 4的支持,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>

测试范围依赖性

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

  • JUnit:用于对 Java 应用程序进行单元测试的实际标准。
  • Spring Test和 Spring Boot 测试:对 Spring Boot 应用程序的 Util 和集成测试支持。
  • AssertJ:流畅的 assert 库。
  • Hamcrest:匹配器对象库(也称为约束或谓词)。
  • Mockito:Java 模拟框架。
  • JSONassert:JSON 的 assert 库。
  • JsonPath:JSON 的 XPath。

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

测试Spring应用程序

依赖注入的主要优点之一是,它应该使您的代码更易于进行单元测试。您可以使用new运算符实例化对象,而无需使用 Spring。您也可以使用 mock objects 代替真实的依赖。

通常,您需要超越单元测试并开始集成测试(使用 Spring ApplicationContext)。能够进行集成测试而无需部署应用程序或连接到其他基础结构,这很有用。

Spring 框架包括用于此类集成测试的专用测试模块。您可以直接向org.springframework:spring-test声明依赖项,也可以使用spring-boot-starter-test“启动器”将其引入。

如果以前没有使用过spring-test模块,则应先阅读 Spring Framework 参考文档的relevant section

测试SpringBoot应用程序

Spring Boot 应用程序是 Spring ApplicationContext,因此除了用普通的 Spring 上下文进行测试之外,无需执行任何其他特殊操作即可对其进行测试。

Note

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

Spring Boot 提供了@SpringBootTest注解,可以在需要 Spring Boot 功能时用作标准spring-test @ContextConfiguration注解的替代方法。Comments 由通过 SpringApplication 创建在测试中使用的 ApplicationContext起作用。除了@SpringBootTest之外,还为应用程序测试更具体的切片提供了许多其他 Comments。

Tip

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

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

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

Note

如果您的测试是@Transactional,则默认情况下它将在每个测试方法的末尾回滚事务。但是,由于将这种安排与RANDOM_PORTDEFINED_PORT一起使用隐式提供了 true 的 servlet 环境,因此 HTTP Client 端和服务器在单独的线程中运行,因此在单独的事务中运行。在这种情况下,服务器上启动的任何事务都不会回滚。

Note

如果您的应用程序对 Management 服务器使用其他端口,则@SpringBootTestwebEnvironment = WebEnvironment.RANDOM_PORT还将在单独的随机端口上启动 Management 服务器。

检测Web应用程序类型

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

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

1
2
3
@RunWith(SpringRunner.class)
@SpringBootTest(properties = "spring.main.web-application-type=reactive")
public class MyWebFluxTests { ... }

检测测试配置

如果您熟悉 Spring Test Framework,则可能会习惯使用@ContextConfiguration(classes=…)来指定要加载哪个 Spring @Configuration。另外,您可能经常在测试中使用嵌套的@Configuration类。

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

搜索算法从包含测试的程序包开始工作,直到找到带有@SpringBootApplication@SpringBootConfigurationComments 的类。只要您以一种明智的方式结构化代码,通常就可以找到您的主要配置。

Note

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

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

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

Note

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

排除测试配置

如果您的应用程序使用组件扫描(例如,如果使用@SpringBootApplication@ComponentScan),则可能会偶然发现到处都是为特定测试创建的顶级配置类。

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

1
2
3
4
5
6
7
8
9
10
11
@RunWith(SpringRunner.class)
@SpringBootTest
@Import(MyTestsConfiguration.class)
public class MyTests {

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

}

Note

如果您直接使用@ComponentScan(即不是通过@SpringBootApplication),则需要向其注册TypeExcludeFilter。有关详情,请参见the Javadoc

在模拟环境中进行测试

默认情况下,@SpringBootTest不会启动服务器。如果您有要在此模拟环境下进行测试的 Web 终结点,则可以另外配置MockMvc,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import org.junit.Test;
import org.junit.runner.RunWith;

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.context.junit4.SpringRunner;
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;

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class MockMvcExampleTests {

@Autowired
private MockMvc mvc;

@Test
public void exampleTest() throws Exception {
this.mvc.perform(get("/")).andExpect(status().isOk())
.andExpect(content().string("Hello World"));
}

}

Tip

如果您只想关注 Web 层而不想开始完整的ApplicationContext,请考虑使用@WebMvcTest 代替

或者,您可以配置WebTestClient,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import org.junit.Test;
import org.junit.runner.RunWith;

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.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureWebTestClient
public class MockWebTestClientExampleTests {

@Autowired
private WebTestClient webClient;

@Test
public void exampleTest() {
this.webClient.get().uri("/").exchange().expectStatus().isOk()
.expectBody(String.class).isEqualTo("Hello World");
}

}

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import org.junit.Test;
import org.junit.runner.RunWith;

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.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class RandomPortWebTestClientExampleTests {

@Autowired
private WebTestClient webClient;

@Test
public void exampleTest() {
this.webClient.get().uri("/").exchange().expectStatus().isOk()
.expectBody(String.class).isEqualTo("Hello World");
}

}

此设置在 Classpath 上需要spring-webflux。如果您不能或不会添加 webflux,Spring Boot 还将提供TestRestTemplate功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import org.junit.Test;
import org.junit.runner.RunWith;

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 org.springframework.test.context.junit4.SpringRunner;

import static org.assertj.core.api.Assertions.assertThat;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class RandomPortTestRestTemplateExampleTests {

@Autowired
private TestRestTemplate restTemplate;

@Test
public void exampleTest() {
String body = this.restTemplate.getForObject("/", String.class);
assertThat(body).isEqualTo("Hello World");
}

}

使用JMX

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RunWith(SpringRunner.class)
@SpringBootTest(properties = "spring.jmx.enabled=true")
@DirtiesContext
public class SampleJmxTests {

@Autowired
private MBeanServer mBeanServer;

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

}

模拟bean和Spybean

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

Spring Boot 包含@MockBean注解,可用于为ApplicationContext中的 bean 定义 Mockito 模拟。您可以使用 Comments 添加新的 bean 或替换单个现有的 bean 定义。注解可以直接用于测试类,测试中的字段或@Configuration类和字段。在字段上使用时,还将注入创建的模拟的实例。每种测试方法后,模拟 bean 都会自动重置。

Note

如果您的测试使用 Spring Boot 的测试 Comments 之一(例如@SpringBootTest),那么此功能将自动启用。要以其他方式使用此功能,必须显式添加侦听器,如以下示例所示:

1
@TestExecutionListeners(MockitoTestExecutionListener.class)

下面的示例使用模拟实现替换现有的RemoteService bean:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import org.junit.*;
import org.junit.runner.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.boot.test.context.*;
import org.springframework.boot.test.mock.mockito.*;
import org.springframework.test.context.junit4.*;

import static org.assertj.core.api.Assertions.*;
import static org.mockito.BDDMockito.*;

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {

@MockBean
private RemoteService remoteService;

@Autowired
private Reverser reverser;

@Test
public void exampleTest() {
// RemoteService has been injected into the reverser bean
given(this.remoteService.someCall()).willReturn("mock");
String reverse = reverser.reverseSomeCall();
assertThat(reverse).isEqualTo("kcom");
}

}

另外,您可以使用@SpyBean将任何现有的 bean 与 Mockito spy包装在一起。有关详细信息,请参见Javadoc

Note

Spring 的测试框架在测试之间缓存应用程序上下文,并为共享相同配置的测试重用上下文,而@MockBean@SpyBean的使用会影响缓存键,这很可能会增加上下文的数量。

Tip

如果您使用@SpyBean监视具有通过名称引用参数的@Cacheable方法的 bean,则您的应用程序必须使用-parameters进行编译。这样可以确保一旦侦察到 bean,就可以将参数名称用于缓存基础结构。

自动配置的测试

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

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

Note

每个切片将组件扫描限制为适当的组件,并加载一组非常受限制的自动配置类。如果您需要排除其中之一,则大多数@…TestComments 都提供excludeAutoConfiguration属性。或者,您可以使用@ImportAutoConfiguration#exclude

Note

不支持在一个测试中使用多个@…TestComments 来包含多个“切片”。如果您需要多个“切片”,请选择@…TestComments 之一,并手动添加其他“切片”的@AutoConfigure…Comments。

Tip

也可以将@AutoConfigure…Comments 与标准@SpringBootTestComments 一起使用。如果您对“切片”应用程序不感兴趣,但需要一些自动配置的测试 bean,则可以使用此组合。

自动配置的JSON测试

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

  • JacksonObjectMapper,任何@JsonComponentbeans 和任何 JacksonModule s
  • Gson
  • Jsonb

Tip

@JsonTest启用的自动配置的列表可以为见附录

如果需要配置自动配置的元素,则可以使用@AutoConfigureJsonTestersComments。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import org.junit.*;
import org.junit.runner.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.boot.test.autoconfigure.json.*;
import org.springframework.boot.test.context.*;
import org.springframework.boot.test.json.*;
import org.springframework.test.context.junit4.*;

import static org.assertj.core.api.Assertions.*;

@RunWith(SpringRunner.class)
@JsonTest
public class MyJsonTests {

@Autowired
private JacksonTester<VehicleDetails> json;

@Test
public void testSerialize() 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
public void testDeserialize() 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");
}

}

Note

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

自动配置的SpringMVC测试

要测试 Spring MVC 控制器是否按预期工作,请使用@WebMvcTest注解。 @WebMvcTest自动配置 Spring MVC 基础结构,并将扫描的 Bean 限制为@Controller@ControllerAdvice@JsonComponentConverterGenericConverterFilterWebMvcConfigurerHandlerMethodArgumentResolver。使用此 Comments 时,不扫描常规的@Component bean。

Tip

@WebMvcTest启用的自动配置设置的列表可以为见附录

Tip

如果您需要注册其他组件,例如 Jackson Module,则可以在测试中使用@Import导入其他配置类。

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

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

Tip

您还可以通过用@AutoConfigureMockMvcComments 非@WebMvcTest(例如@SpringBootTest)来自动配置MockMvc。以下示例使用MockMvc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import org.junit.*;
import org.junit.runner.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.boot.test.autoconfigure.web.servlet.*;
import org.springframework.boot.test.mock.mockito.*;

import static org.assertj.core.api.Assertions.*;
import static org.mockito.BDDMockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@RunWith(SpringRunner.class)
@WebMvcTest(UserVehicleController.class)
public class MyControllerTests {

@Autowired
private MockMvc mvc;

@MockBean
private UserVehicleService userVehicleService;

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

}

Tip

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

如果使用 HtmlUnit 或 Selenium,则自动配置还会提供 HTMLUnit WebClient bean 和/或WebDriver bean。以下示例使用 HtmlUnit:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import com.gargoylesoftware.htmlunit.*;
import org.junit.*;
import org.junit.runner.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.boot.test.autoconfigure.web.servlet.*;
import org.springframework.boot.test.mock.mockito.*;

import static org.assertj.core.api.Assertions.*;
import static org.mockito.BDDMockito.*;

@RunWith(SpringRunner.class)
@WebMvcTest(UserVehicleController.class)
public class MyHtmlUnitTests {

@Autowired
private WebClient webClient;

@MockBean
private UserVehicleService userVehicleService;

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

}

Note

默认情况下,Spring Boot 将WebDriver bean 放在特殊的“作用域”中,以确保驱动程序在每次测试后退出并注入新实例。如果您不希望出现这种情况,可以将@Scope("singleton")添加到WebDriver @Bean定义中。

Warning

Spring Boot 创建的webDriver作用域将替换任何用户定义的同名作用域。如果定义自己的webDriver范围,则使用@WebMvcTest时可能会停止工作。

如果您在 Classpath 上具有 Spring Security,则@WebMvcTest还将扫描WebSecurityConfigurer bean。您可以使用 Spring Security 的测试支持,而不是完全禁用此类测试的安全性。有关如何使用 Spring Security 的MockMvc支持的更多详细信息,可以在此 第 80 章,使用 Spring Security 进行测试 操作方法部分中找到。

Tip

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

自动配置的SpringWebFlux测试

要测试Spring WebFlux控制器是否按预期工作,可以使用@WebFluxTest注解。 @WebFluxTest自动配置 Spring WebFlux 基础结构,并将扫描的 bean 限制为@Controller@ControllerAdvice@JsonComponentConverterGenericConverterWebFluxConfigurer。使用@WebFluxTest注解时,不扫描常规@Component bean。

Tip

@WebFluxTest启用的自动配置的列表可以为见附录

Tip

如果您需要注册其他组件,例如 Jackson Module,则可以在测试中使用@Import导入其他配置类。

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

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

Tip

您还可以通过用@AutoConfigureWebTestClientComments 非@WebFluxTest(例如@SpringBootTest)来自动配置WebTestClient。以下示例显示了同时使用@WebFluxTestWebTestClient的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import org.junit.Test;
import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;

@RunWith(SpringRunner.class)
@WebFluxTest(UserVehicleController.class)
public class MyControllerTests {

@Autowired
private WebTestClient webClient;

@MockBean
private UserVehicleService userVehicleService;

@Test
public void testExample() throws Exception {
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");
}

}

Tip

WebFlux 应用程序仅支持此设置,因为在模拟的 Web 应用程序中使用WebTestClient目前仅适用于 WebFlux。

Note

@WebFluxTest无法检测通过功能 Web 框架注册的路由。要在上下文中测试RouterFunction bean,请考虑自己通过@Import或使用@SpringBootTest导入RouterFunction

Tip

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

自动配置的数据JPA测试

您可以使用@DataJpaTest注解来测试 JPA 应用程序。默认情况下,它配置一个内存嵌入式数据库,扫描@Entity类,并配置 Spring Data JPA 存储库。常规@Component bean 未加载到ApplicationContext中。

Tip

@DataJpaTest启用的自动配置设置的列表可以为见附录

默认情况下,数据 JPA 测试是事务性的,并在每次测试结束时回滚。有关更多详细信息,请参见《 Spring Framework 参考文档》中的relevant section。如果这不是您想要的,则可以按以下方式禁用测试或整个类的事务 Management:

1
2
3
4
5
6
7
8
9
10
11
12
13
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@RunWith(SpringRunner.class)
@DataJpaTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public class ExampleNonTransactionalTests {

}

数据 JPA 测试还可以注入TestEntityManager bean,它提供了专门为测试设计的标准 JPA EntityManager的替代方案。如果要在@DataJpaTest实例之外使用TestEntityManager,则也可以使用@AutoConfigureTestEntityManagerComments。如果需要,也可以提供JdbcTemplate。以下示例显示了正在使用的@DataJpaTest注解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import org.junit.*;
import org.junit.runner.*;
import org.springframework.boot.test.autoconfigure.orm.jpa.*;

import static org.assertj.core.api.Assertions.*;

@RunWith(SpringRunner.class)
@DataJpaTest
public class ExampleRepositoryTests {

@Autowired
private TestEntityManager entityManager;

@Autowired
private UserRepository repository;

@Test
public void testExample() throws Exception {
this.entityManager.persist(new User("sboot", "1234"));
User user = this.repository.findByUsername("sboot");
assertThat(user.getUsername()).isEqualTo("sboot");
assertThat(user.getVin()).isEqualTo("1234");
}

}

内存嵌入式数据库通常运行良好,不需要任何安装,因此通常可以很好地进行测试。但是,如果您希望对真实数据库运行测试,则可以使用@AutoConfigureTestDatabase注解,如以下示例所示:

1
2
3
4
5
6
7
8
@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace=Replace.NONE)
public class ExampleRepositoryTests {

// ...

}

自动配置的JDBC测试

@JdbcTest@DataJpaTest类似,但适用于只需要DataSource并且不使用 Spring Data JDBC 的测试。默认情况下,它配置内存嵌入式数据库和JdbcTemplate。常规@Component bean 没有加载到ApplicationContext中。

Tip

@JdbcTest启用的自动配置的列表可以为[见附录](https://route-nice.github.io/2020/08/31/SpringBoot官方文档翻译-附录/#测试自动配置注解。

缺省情况下,JDBC 测试是事务性的,并在每次测试结束时回滚。有关更多详细信息,请参见《 Spring Framework 参考文档》中的relevant section。如果这不是您想要的,则可以为测试或整个类禁用事务 Management,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@RunWith(SpringRunner.class)
@JdbcTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public class ExampleNonTransactionalTests {

}

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

自动配置的数据JDBC测试

@DataJdbcTest@JdbcTest类似,但适用于使用 Spring Data JDBC 存储库的测试。默认情况下,它配置一个内存嵌入式数据库JdbcTemplate和 Spring Data JDBC 存储库。常规@Component bean 没有加载到ApplicationContext中。

Tip

@DataJdbcTest启用的自动配置的列表可以为见附录

默认情况下,Data JDBC 测试是事务性的,并在每个测试结束时回滚。有关更多详细信息,请参见《 Spring Framework 参考文档》中的relevant section。如果这不是您想要的,则可以禁用测试或整个测试类的事务 Management,即在 JDBC 示例中显示

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

自动配置的jOOQ测试

您可以以与@JdbcTest类似的方式使用@JooqTest,但可以用于与 jOOQ 相关的测试。由于 jOOQ 严重依赖与数据库模式相对应的基于 Java 的模式,因此使用现有的DataSource。如果要将其替换为内存数据库,则可以使用@AutoConfigureTestDatabase覆盖这些设置。 (有关将 jOOQ 与 Spring Boot 结合使用的更多信息,请参阅本章前面的“ 第 30.6 节“使用 jOOQ””。)常规@Component bean 没有加载到ApplicationContext中。

Tip

@JooqTest启用的自动配置的列表可以为见附录

@JooqTest配置DSLContext。常规@Component bean 未加载到ApplicationContext中。以下示例显示了正在使用的@JooqTestComments:

1
2
3
4
5
6
7
8
9
10
11
12
13
import org.jooq.DSLContext;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.autoconfigure.jooq.JooqTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@JooqTest
public class ExampleJooqTests {

@Autowired
private DSLContext dslContext;
}

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

自动配置的DataMongoDB测试

您可以使用@DataMongoTest测试 MongoDB 应用程序。默认情况下,它配置内存嵌入式 MongoDB(如果可用),配置MongoTemplate,扫描@Document类,并配置 Spring Data MongoDB 存储库。常规@Component bean 没有加载到ApplicationContext中。 (有关将 MongoDB 与 Spring Boot 结合使用的更多信息,请参阅本章前面的“ 第 31.2 节“ MongoDB””。)

Tip

@DataMongoTest启用的自动配置设置的列表可以为见附录

此类显示正在使用的@DataMongoTest注解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@DataMongoTest
public class ExampleDataMongoTests {

@Autowired
private MongoTemplate mongoTemplate;

//
}

内存嵌入式 MongoDB 通常运行良好,不需要任何开发人员安装,因此通常可以很好地用于测试。但是,如果您希望对真实的 MongoDB 服务器运行测试,则应排除嵌入式 MongoDB 自动配置,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
import org.junit.runner.RunWith;
import org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class)
public class ExampleDataMongoNonEmbeddedTests {

}

自动配置的数据Neo4j测试

您可以使用@DataNeo4jTest测试 Neo4j 应用程序。默认情况下,它使用内存中嵌入式 Neo4j(如果有嵌入式驱动程序可用),扫描@NodeEntity类,并配置 Spring Data Neo4j 存储库。常规@Component bean 没有加载到ApplicationContext中。 (有关将 Neo4J 与 Spring Boot 结合使用的更多信息,请参阅本章前面的“ 第 31.3 节“ Neo4j””。)

Tip

@DataNeo4jTest启用的自动配置设置的列表可以为见附录

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@DataNeo4jTest
public class ExampleDataNeo4jTests {

@Autowired
private YourRepository repository;

//
}

默认情况下,Data Neo4j 测试是事务性的,并在每个测试结束时回滚。有关更多详细信息,请参见《 Spring Framework 参考文档》中的relevant section。如果这不是您想要的,则可以为测试或整个类禁用事务 Management,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@RunWith(SpringRunner.class)
@DataNeo4jTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public class ExampleNonTransactionalTests {

}

自动配置的数据Redis测试

您可以使用@DataRedisTest测试 Redis 应用程序。默认情况下,它将扫描@RedisHash类并配置 Spring Data Redis 存储库。常规@Component bean 没有加载到ApplicationContext中。 (有关在 Spring Boot 中使用 Redis 的更多信息,请参阅本章前面的“ 第 31.1 节“ Redis””。)

Tip

@DataRedisTest启用的自动配置设置的列表可以为见附录

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@DataRedisTest
public class ExampleDataRedisTests {
javajavajava
@Autowired
private YourRepository repository;

//
}

自动配置的数据LDAP测试

您可以使用@DataLdapTest测试 LDAP 应用程序。默认情况下,它配置内存嵌入式 LDAP(如果可用),配置LdapTemplate,扫描@Entry类,并配置 Spring Data LDAP 存储库。常规@Component bean 没有加载到ApplicationContext中。 (有关将 LDAP 与 Spring Boot 结合使用的更多信息,请参阅本章前面的“ 第 31.9 节“ LDAP””。)

Tip

@DataLdapTest启用的自动配置设置的列表可以为见附录

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@DataLdapTest
public class ExampleDataLdapTests {

@Autowired
private LdapTemplate ldapTemplate;

//
}

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

1
2
3
4
5
6
7
8
9
10
import org.junit.runner.RunWith;
import org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration;
import org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@DataLdapTest(excludeAutoConfiguration = EmbeddedLdapAutoConfiguration.class)
public class ExampleDataLdapNonEmbeddedTests {

}

自动配置的RESTClient端

您可以使用@RestClientTest注解来测试 REST Client 端。默认情况下,它会自动配置 Jackson,GSON 和 Jsonb 支持,配置RestTemplateBuilder,并添加对MockRestServiceServer的支持。常规@Component bean 没有加载到ApplicationContext中。

Tip

@RestClientTest启用的自动配置设置的列表可以为见附录

应该使用@RestClientTestvaluecomponents属性指定要测试的特定 bean,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@RunWith(SpringRunner.class)
@RestClientTest(RemoteVehicleDetailsService.class)
public class ExampleRestClientTest {

@Autowired
private RemoteVehicleDetailsService service;

@Autowired
private MockRestServiceServer server;

@Test
public void getVehicleDetailsWhenResultIsSuccessShouldReturnDetails()
throws Exception {
this.server.expect(requestTo("/greet/details"))
.andRespond(withSuccess("hello", MediaType.TEXT_PLAIN));
String greeting = this.service.callRestService();
assertThat(greeting).isEqualTo("hello");
}

}

自动配置的SpringREST文档测试

您可以在 Mock MVC,REST 保证或 WebTestClient 的测试中使用@AutoConfigureRestDocs注解来使用Spring REST 文件。它消除了 Spring REST Docs 中对 JUnit 规则的需求。

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

使用MockMVC自动配置的SpringRESTDocs测试

@AutoConfigureRestDocs自定义MockMvc bean 以使用 Spring REST Docs。您可以使用@Autowired注入它,并像通常使用 Mock MVC 和 Spring REST Docs 一样在测试中使用它,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import org.junit.Test;
import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
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.*;

@RunWith(SpringRunner.class)
@WebMvcTest(UserController.class)
@AutoConfigureRestDocs
public class UserDocumentationTests {

@Autowired
private MockMvc mvc;

@Test
public void listUsers() throws Exception {
this.mvc.perform(get("/users").accept(MediaType.TEXT_PLAIN))
.andExpect(status().isOk())
.andDo(document("list-users"));
}

}

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

1
2
3
4
5
6
7
8
9
10
@TestConfiguration
static class CustomizationConfiguration
implements RestDocsMockMvcConfigurationCustomizer {

@Override
public void customize(MockMvcRestDocumentationConfigurer configurer) {
configurer.snippets().withTemplateFormat(TemplateFormats.markdown());
}

}

如果要使用 Spring REST Docs 对参数化输出目录的支持,则可以创建RestDocumentationResultHandler bean。自动配置使用此结果处理程序调用alwaysDo,从而使每个MockMvc调用自动生成默认片段。以下示例显示正在定义的RestDocumentationResultHandler

1
2
3
4
5
6
7
8
9
@TestConfiguration
static class ResultHandlerConfiguration {

@Bean
public RestDocumentationResultHandler restDocumentation() {
return MockMvcRestDocumentation.document("{method-name}");
}

}

具有 REST 保证的自动配置的 Spring REST 文档测试

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import io.restassured.specification.RequestSpecification;
import org.junit.Test;
import org.junit.runner.RunWith;

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.web.server.LocalServerPort;
import org.springframework.test.context.junit4.SpringRunner;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
import static org.springframework.restdocs.restassured3.RestAssuredRestDocumentation.document;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureRestDocs
public class UserDocumentationTests {

@LocalServerPort
private int port;

@Autowired
private RequestSpecification documentationSpec;

@Test
public void listUsers() {
given(this.documentationSpec).filter(document("list-users")).when()
.port(this.port).get("/").then().assertThat().statusCode(is(200));
}

}

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

1
2
3
4
5
6
7
8
9
10
@TestConfiguration
public static class CustomizationConfiguration
implements RestDocsRestAssuredConfigurationCustomizer {

@Override
public void customize(RestAssuredRestDocumentationConfigurer configurer) {
configurer.snippets().withTemplateFormat(TemplateFormats.markdown());
}

}

其他自动配置和切片

每个切片提供一个或多个@AutoConfigure…注解,即定义应包含在切片中的自动配置。可以通过创建自定义@AutoConfigure…Comments 或仅通过向测试中添加@ImportAutoConfiguration来添加其他自动配置,如以下示例所示:

1
2
3
4
5
6
@RunWith(SpringRunner.class)
@JdbcTest
@ImportAutoConfiguration(IntegrationAutoConfiguration.class)
public class ExampleJdbcTests {

}

Note

确保不要使用常规的@Import注解 来导入自动配置,因为它们是由 Spring Boot 以特定方式处理的。

用户配置和切片

如果您以明智的方式结构化代码,则您的@SpringBootApplication类为默认使用作为测试的配置。

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

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

1
2
3
@SpringBootApplication
@EnableBatchProcessing
public class SampleApplication { ... }

因为此类是测试的源配置,所以任何切片测试实际上都尝试启动 Spring Batch,这绝对不是您想要执行的操作。建议的方法是将特定于区域的配置移到与您的应用程序相同级别的单独的@Configuration类,如以下示例所示:

1
2
3
@Configuration
@EnableBatchProcessing
public class BatchConfiguration { ... }

Note

根据您应用程序的复杂性,您可以为自己的自定义设置一个@Configuration类,或者每个域区域一个类。后一种方法可让您在必要的测试中使用@Import注解启用它。

混乱的另一个来源是 Classpath 扫描。假设在以合理的方式组织代码的同时,您需要扫描其他程序包。您的应用程序可能类似于以下代码:

1
2
3
@SpringBootApplication
@ComponentScan({ "com.example.app", "org.acme.another" })
public class SampleApplication { ... }

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

Tip

如果这不是您的选择,则可以在测试层次结构中的某个位置创建@SpringBootConfiguration,以便代替它使用。另外,您可以为测试指定一个源,从而禁用查找默认源的行为。

使用Spock测试SpringBoot应用程序

如果希望使用 Spock 测试 Spring Boot 应用程序,则应在应用程序的构建中添加对 Spock 的spock-spring模块的依赖。 spock-spring将 Spring 的测试框架集成到 Spock 中。建议您使用 Spock 1.2 或更高版本,以受益于 Spock 的 Spring Framework 和 Spring Boot 集成的许多改进。有关更多详细信息,请参见Spock 的 Spring 模块的文档

测试Util

一些测试 Util 类通常在测试您的应用程序时有用,它们被打包为spring-boot的一部分。

ConfigFileApplicationContextInitializer

ConfigFileApplicationContextInitializerApplicationContextInitializer,您可以将其应用于测试以加载 Spring Boot application.properties文件。如不需要以下示例所示,可以在不需要@SpringBootTest提供的全部功能时使用它:

1
2
@ContextConfiguration(classes = Config.class,
initializers = ConfigFileApplicationContextInitializer.class)

Note

单独使用ConfigFileApplicationContextInitializer不支持@Value("${…}")注入。它唯一的工作就是确保将application.properties文件加载到 Spring 的Environment中。为了获得@Value支持,您需要另外配置PropertySourcesPlaceholderConfigurer或使用@SpringBootTest,后者会为您自动配置一个。

TestPropertyValues

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

1
TestPropertyValues.of("org=Spring", "name=Boot").applyTo(env);

OutputCapture

OutputCapture是一个 JUnit Rule,可用于捕获System.outSystem.err输出。您可以将捕获声明为@Rule,然后将toString()用于 assert,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import org.junit.Rule;
import org.junit.Test;
import org.springframework.boot.test.rule.OutputCapture;

import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;

public class MyTest {

@Rule
public OutputCapture capture = new OutputCapture();

@Test
public void testName() throws Exception {
System.out.println("Hello World!");
assertThat(capture.toString(), containsString("World"));
}

}

TestRestTemplate

Tip

Spring Framework 5.0 提供了一个新的WebTestClient,它适用于WebFlux 集成测试WebFlux 和 MVC 端到端测试。与TestRestTemplate不同,它为声明提供了流畅的 API。

TestRestTemplate是 Spring RestTemplate的便捷替代方法,在集成测试中非常有用。您可以使用普通模板或发送基本 HTTP 身份验证(带有用户名和密码)的模板。在这两种情况下,模板都不会通过在服务器端错误上引发异常来以易于测试的方式运行。建议(但不是强制性的)使用 Apache HTTP Client(版本 4.3.2 或更高版本)。如果您在 Classpath 中具有该名称,则TestRestTemplate会通过适当配置 Client 端进行响应。如果确实使用 Apache 的 HTTP Client 端,则会启用一些其他易于测试的功能:

  • 不遵循重定向(因此您可以声明响应位置)。
  • Cookies 被忽略(因此模板是 Stateless 的)。

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

1
2
3
4
5
6
7
8
9
10
11
12
public class MyTest {

private TestRestTemplate template = new TestRestTemplate();

@Test
public void testRequest() throws Exception {
HttpHeaders headers = this.template.getForEntity(
"http://myhost.example.com/example", String.class).getHeaders();
assertThat(headers.getLocation()).hasHost("other.example.com");
}

}

另外,如果您将@SpringBootTestComments 与WebEnvironment.RANDOM_PORTWebEnvironment.DEFINED_PORT一起使用,则可以注入已完全配置的TestRestTemplate并开始使用它。如有必要,可以通过RestTemplateBuilder bean 应用其他定制。未指定主机和端口的所有 URL 都会自动连接到嵌入式服务器,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class SampleWebClientTests {

@Autowired
private TestRestTemplate template;

@Test
public void testRequest() {
HttpHeaders headers = this.template.getForEntity("/example", String.class)
.getHeaders();
assertThat(headers.getLocation()).hasHost("other.example.com");
}

@TestConfiguration
static class Config {

@Bean
public RestTemplateBuilder restTemplateBuilder() {
return new RestTemplateBuilder().setConnectTimeout(Duration.ofSeconds(1))
.setReadTimeout(Duration.ofSeconds(1));
}

}

}

WebSockets

Spring Boot 为嵌入式 Tomcat,Jetty 和 Undertow 提供了 WebSockets 自动配置。如果将 war 文件部署到独立容器,Spring Boot 会假定该容器负责其 WebSocket 支持的配置。

Spring Framework 为 MVC Web 应用程序提供了丰富的 WebSocket 支持,可以通过spring-boot-starter-websocket模块轻松访问。

WebSocket 支持也可用于响应式 Web 应用程序,并且需要在spring-boot-starter-webflux旁边包括 WebSocket API:

1
2
3
4
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
</dependency>

WebService

Spring Boot 提供了 Web 服务自动配置,因此您所要做的就是定义Endpoints

Spring Web Services 功能可以通过spring-boot-starter-webservices模块轻松访问。

可以分别为您的 WSDL 和 XSD 自动创建SimpleWsdl11DefinitionSimpleXsdSchema bean。为此,请配置其位置,如以下示例所示:

1
spring.webservices.wsdl-locations=classpath:/wsdl

使用WebServiceTemplate调用Web服务

如果需要从应用程序调用远程 Web 服务,则可以使用WebServiceTemplate类。由于WebServiceTemplate实例在使用前通常需要自定义,因此 Spring Boot 不提供任何单个自动配置的WebServiceTemplate bean。但是,它会自动配置WebServiceTemplateBuilder,可以在需要时创建WebServiceTemplate实例。

以下代码显示了一个典型示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Service
public class MyService {

private final WebServiceTemplate webServiceTemplate;

public MyService(WebServiceTemplateBuilder webServiceTemplateBuilder) {
this.webServiceTemplate = webServiceTemplateBuilder.build();
}

public DetailsResp someWsCall(DetailsReq detailsReq) {
return (DetailsResp) this.webServiceTemplate.marshalSendAndReceive(detailsReq, new SoapActionCallback(ACTION));

}

}

默认情况下,WebServiceTemplateBuilder使用 Classpath 上可用的 HTTP Client 端库检测合适的基于 HTTP 的WebServiceMessageSender。您还可以如下自定义读取和连接超时:

1
2
3
4
5
@Bean
public WebServiceTemplate webServiceTemplate(WebServiceTemplateBuilder builder) {
return builder.messageSenders(new HttpWebServiceMessageSenderBuilder()
.setConnectTimeout(5000).setReadTimeout(2000).build()).build();
}

创建自己的自动配置

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

自动配置可以与“启动器”相关联,该“启动器”提供自动配置代码以及您将使用的典型库。我们首先介绍构建自己的自动配置所需的知识,然后 continue 进行创建自定义启动器所需的典型步骤

Tip

demo project可用来展示如何逐步创建 Starter 者。

了解自动配置的Bean

在后台,自动配置是通过标准的@Configuration类实现的。其他@ConditionalComments 用于约束何时应应用自动配置。通常,自动配置类使用@ConditionalOnClass@ConditionalOnMissingBeanComments。这样可以确保仅当找到相关的类并且没有声明自己的@Configuration时,自动配置才适用。

您可以浏览spring-boot-autoconfigure的源代码以查看 Spring 提供的@Configuration类(请参见META-INF/spring.factories文件)。

查找自动配置的候选人

Spring Boot 检查发布的 jar 中是否存在META-INF/spring.factories文件。该文件应在EnableAutoConfiguration键下列出您的配置类,如以下示例所示:

1
2
3
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.mycorp.libx.autoconfigure.LibXAutoConfiguration,\
com.mycorp.libx.autoconfigure.LibXWebAutoConfiguration

如果需要按特定 Sequences 应用配置,则可以使用@AutoConfigureAfter@AutoConfigureBefore注解。例如,如果您提供特定于 Web 的配置,则可能需要在WebMvcAutoConfiguration之后应用您的类。

如果要 Order 某些彼此之间没有直接知识的自动配置,则也可以使用@AutoConfigureOrder。该 Comments 与常规@OrderComments 具有相同的语义,但为自动配置类提供了专用 Sequences。

Note

自动配置必须以 only 的方式加载。确保在特定的软件包空间中定义了它们,尤其是它们绝不是组件扫描的目标。

Condition注解

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

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

Class条件

@ConditionalOnClass@ConditionalOnMissingClass注解允许根据是否存在特定类来包含配置。由于 Comments 元数据是通过使用ASM进行解析的,因此即使该类实际上可能未出现在正在运行的应用程序 Classpath 上,您也可以使用value属性来引用真实的类。如果您希望通过使用String值来指定类名,则也可以使用name属性。

Tip

如果您使用@ConditionalOnClass@ConditionalOnMissingClass作为元 Comments 的一部分来组成自己的组合 Comments,则必须使用name,因为在这种情况下无法引用该类。

Bean条件

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

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

1
2
3
4
5
6
7
8
@Configuration
public class MyAutoConfiguration {

@Bean
@ConditionalOnMissingBean
public MyService myService() { ... }

}

在前面的示例中,如果ApplicationContext中没有包含MyService类型的 bean,则将创建myService bean。

Tip

您需要非常注意添加 bean 定义的 Sequences,因为这些条件是根据到目前为止已处理的内容来评估的。因此,我们建议在自动配置类上仅使用@ConditionalOnBean@ConditionalOnMissingBeanComments(因为保证在添加任何用户定义的 Bean 定义后即可加载这些 Comments)。

Note

@ConditionalOnBean@ConditionalOnMissingBean不会阻止@Configuration类的创建。在类级别使用这些条件与使用 Comments 标记每个包含的@Bean方法之间的唯一区别是,如果条件不匹配,则前者会阻止@Configuration类注册为 bean。

Property条件

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

Resource条件

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

WebApplication条件

根据应用程序是否为“ Web 应用程序”,可以使用@ConditionalOnWebApplication@ConditionalOnNotWebApplication注解包含配置。 Web 应用程序是使用 Spring WebApplicationContext,定义session范围或具有StandardServletEnvironment的任何应用程序。

SpEL表达条件

@ConditionalOnExpression注解允许基于SpEL expression的结果包括配置。

测试您的自动配置

自动配置可能受许多因素影响:用户配置(@Bean定义和Environment定制),条件评估(特定库的存在)和其他因素。具体而言,每个测试都应创建定义良好的ApplicationContext,以表示这些自定义项的组合。 ApplicationContextRunner提供了一种实现此目标的好方法。

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

1
2
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(UserServiceAutoConfiguration.class));

Tip

如果必须定义多个自动配置,则无需按与运行应用程序时完全相同的 Sequences 调用它们的声明。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Test
public void defaultServiceBacksOff() {
this.contextRunner.withUserConfiguration(UserConfiguration.class)
.run((context) -> {
assertThat(context).hasSingleBean(UserService.class);
assertThat(context.getBean(UserService.class)).isSameAs(
context.getBean(UserConfiguration.class).myUserService());
});
}

@Configuration
static class UserConfiguration {

@Bean
public UserService myUserService() {
return new UserService("mine");
}

}

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

1
2
3
4
5
6
7
@Test
public void serviceNameCanBeConfigured() {
this.contextRunner.withPropertyValues("user.name=test123").run((context) -> {
assertThat(context).hasSingleBean(UserService.class);
assertThat(context.getBean(UserService.class).getName()).isEqualTo("test123");
});
}

Running 者也可以用来显示ConditionEvaluationReport。该报告可以INFODEBUG级别打印。以下示例显示如何在自动配置测试中使用ConditionEvaluationReportLoggingListener打印报告。

1
2
3
4
5
6
7
8
9
@Test
public void autoConfigTest {
ConditionEvaluationReportLoggingListener initializer = new ConditionEvaluationReportLoggingListener(
LogLevel.INFO);
ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withInitializer(initializer).run((context) -> {
// Do something...
});
}

模拟网络环境

如果您需要测试仅在 Servlet 或 Reactive Web 应用程序上下文中运行的自动配置,请分别使用WebApplicationContextRunnerReactiveWebApplicationContextRunner

覆盖Classpath

还可以测试在运行时不存在特定的类和/或程序包时发生的情况。 Spring Boot 附带FilteredClassLoader,Running 者可以轻松使用。在以下示例中,我们 assert 如果不存在UserService,则会自动禁用自动配置:

1
2
3
4
5
@Test
public void serviceIsIgnoredIfLibraryIsNotPresent() {
this.contextRunner.withClassLoader(new FilteredClassLoader(UserService.class))
.run((context) -> assertThat(context).doesNotHaveBean("userService"));
}

创建自己的启动器

库的完整 Spring BootStarter 程序可能包含以下组件:

  • 包含自动配置代码的autoconfigure模块。
  • starter模块提供对autoconfigure模块以及库的依赖关系,以及通常有用的任何其他依赖关系。简而言之,添加启动程序应提供开始使用该库所需的一切。

Tip

如果不需要将这两个问题分开,则可以将自动配置代码和依赖性 Management 结合在一起。

Naming

您应该确保为启动器提供适当的名称空间。即使您使用其他 Maven groupId,也不要以spring-boot开头模块名称。将来,我们可能会为您自动配置的内容提供官方支持。

根据经验,您应该在启动器后命名一个组合模块。例如,假设您要为“ acme”创建启动程序,并且将自动配置模块命名为acme-spring-boot-autoconfigure,而启动程序则命名为acme-spring-boot-starter。如果只有一个将两者结合的模块,请将其命名为acme-spring-boot-starter

另外,如果您的 Starter 者提供了配置密钥,请为其使用唯一的名称空间。特别是,不要在 Spring Boot 使用的名称空间中包含您的密钥(例如servermanagementspring等)。如果使用相同的名称空间,将来我们可能会以破坏模块的方式修改这些名称空间。

确保触发元数据生成,以便您的按键也可以使用 IDE 协助。您可能需要查看生成的元数据(META-INF/spring-configuration-metadata.json),以确保正确记录了您的密钥。

自动配置模块

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

Tip

您应该将对库的依赖关系标记为可选,以便可以更轻松地在项目中包含autoconfigure模块。如果这样做,则不提供该库,并且默认情况下,Spring Boot 会后退。

Spring Boot 使用 Comments 处理器来收集元数据文件(META-INF/spring-autoconfigure-metadata.properties)中自动配置的条件。如果存在该文件,它将用于急切过滤不匹配的自动配置,这将缩短启动时间。建议在包含自动配置的模块中添加以下依赖项:

1
2
3
4
5
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure-processor</artifactId>
<optional>true</optional>
</dependency>

对于 Gradle 4.5 及更早版本,依赖关系应在compileOnly配置中声明,如以下示例所示:

1
2
3
dependencies {
compileOnly "org.springframework.boot:spring-boot-autoconfigure-processor"
}

在 Gradle 4.6 及更高版本中,依赖性应在annotationProcessor配置中声明,如以下示例所示:

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

Starter模块

起动器确实是一个空Jar子。其唯一目的是提供必要的依赖关系以使用库。您可以将其视为对 Starter 所需的看法。

不要对添加了启动器的项目做任何假设。如果您要自动配置的库通常需要其他启动器,请同时提及它们。如果可选依赖项的数量很高,则提供一组适当的 default 依赖项可能会很困难,因为您应避免包括对于库的典型用法而言不必要的依赖项。换句话说,您不应包括可选的依赖项。

Note

无论哪种方式,您的启动程序都必须直接或间接引用核心 Spring Boot 启动程序(spring-boot-starter)(即,如果您的启动程序依赖于另一个启动程序,则无需添加它)。如果仅使用您的自定义启动器创建项目,则通过使用该核心启动器来兑现 Spring Boot 的核心功能。

Kotlin支持

Kotlin是针对 JVM(和其他平台)的静态类型的语言,它允许编写简洁明了的代码,同时为interoperability提供以 Java 编写的现有库。

Spring Boot 通过利用其他 Spring 项目(例如 Spring Framework,Spring Data 和 Reactor)中的支持来提供 Kotlin 支持。有关更多信息,请参见Spring Framework Kotlin 支持文档

从 Spring Boot 和 Kotlin 开始的最简单方法是遵循本综合教程。您可以通过start.spring.io创建新的 Kotlin 项目。如果需要支持,可以随时加入Kotlin Slack的#spring Channels,或在Stack Overflow上使用springkotlin标签询问问题。

Requirements

Spring Boot 支持 Kotlin1.2.x。要使用 Kotlin,Classpath 上必须存在org.jetbrains.kotlin:kotlin-stdliborg.jetbrains.kotlin:kotlin-reflect。也可以使用kotlin-stdlib变体kotlin-stdlib-jdk7kotlin-stdlib-jdk8

Kotlin 类默认为 final开始,您可能需要配置kotlin-spring插件,以便自动打开带有 Spring Comments 的类,以便对其进行代理。

在 Kotlin 中序列化/反序列化 JSON 数据需要Jackson 的 Kotlin 模块。在 Classpath 上找到它会自动注册。如果存在 Jackson 和 Kotlin 但不存在 Jackson Kotlin 模块,则会记录一条警告消息。

Tip

如果一个人在start.spring.io上引导 Kotlin 项目,则默认情况下会提供这些依赖项和插件。

Null-safety

Kotlin 的主要功能之一是null-safety。它在编译时处理null值,而不是将问题推迟到运行时并遇到NullPointerException。这有助于消除常见的错误源,而无需支付Optional之类的包装器的费用。 Kotlin 还允许使用具有可空值的函数构造,如Kotlin 空安全综合指南中所述。

尽管 Java 不允许人在其类型系统中表示空安全性,但 Spring Framework,Spring Data 和 Reactor 现在通过易于使用工具的注解为 API 提供了空安全性。默认情况下,Kotlin 中使用的 Java API 中的类型被识别为platform types,对此类型的空检查得到了放宽。 Kotlin 对 JSR 305 注解的支持与可空性 Comments 结合使用,为 Kotlin 中的相关 Spring API 提供了空安全性。

可以通过添加带有以下选项的-Xjsr305编译器标志来配置 JSR 305 检查:-Xjsr305={strict|warn|ignore}。默认行为与-Xjsr305=warn相同。必须使用strict值来考虑从 Spring API 推断出的 Kotlin 类型的空安全性,但应使用该知识,即使 Spring API 的空性声明即使在次要发行版之间也可能会演变,并且将来可能会添加更多检查,这一点应得到使用。

Warning

尚不支持泛型类型参数,varargs 和数组元素的可空性。有关最新信息,请参见SPR-15942。另外请注意,Spring Boot 自己的 API 是尚未 注解

KotlinAPI

runApplication

Spring Boot 提供了一种惯用的方式来使用runApplication<MyApplication>(*args)运行应用程序,如以下示例所示:

1
2
3
4
5
6
7
8
9
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)的直接替代。它还允许自定义应用程序,如以下示例所示:

1
2
3
runApplication<MyApplication>(*args) {
setBannerMode(OFF)
}

Extensions

Kotlin extensions提供了使用其他功能扩展现有类的功能。 Spring Boot Kotlin API 利用这些扩展为现有 API 添加了新的 Kotlin 专用便利。

提供了TestRestTemplateextensions,类似于 Spring Framework 为RestOperations在 Spring Framework 中提供的 extensions。除其他事项外,这些扩展使利用 Kotlin 修饰类型参数成为可能。

依赖性管理

为了避免在 Classpath 上混合使用不同版本的 Kotlin 依赖项,提供了以下 Kotlin 依赖项的依赖项 Management:

  • kotlin-reflect
  • kotlin-runtime
  • kotlin-stdlib
  • kotlin-stdlib-jdk7
  • kotlin-stdlib-jdk8
  • kotlin-stdlib-jre7
  • kotlin-stdlib-jre8

使用 Maven,可以通过kotlin.version属性自定义 Kotlin 版本,并为kotlin-maven-plugin提供插件 Management。使用 Gradle,Spring Boot 插件会自动将kotlin.version与 Kotlin 插件的版本对齐。

@ConfigurationProperties

@ConstructorBinding结合使用时,@ConfigurationProperties支持具有不变val属性的类,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
@ConstructorBinding
@ConfigurationProperties("example.kotlin")
data class KotlinExampleProperties(
val name: String,
val description: String,
val myService: MyService) {

data class MyService(
val apiToken: String,
val uri: URI
)
}

Tip

要使用注解处理器生成您自己的元数据,具有spring-boot-configuration-processor依赖性的kapt 应该配置

Testing

虽然可以使用 JUnit 4(由spring-boot-starter-test提供的默认值)来测试 Kotlin 代码,但建议使用 JUnit 5. JUnit 5 使一个测试类可以实例化一次,并可以重新用于该类的所有测试。这样就可以在非静态方法上使用@BeforeAll@AfterAll注解,这非常适合 Kotlin。

要使用 JUnit 5,请从spring-boot-starter-test中排除junit:junit依赖性,添加 JUnit 5 依赖性,并相应地配置 Maven 或 Gradle 插件。有关更多详细信息,请参见JUnit 5 文档。您还需要将测试实例生命周期切换为“每个类”

Resources

进一步阅读

Examples

接下来要读什么

如果您想了解有关本节讨论的任何类的更多信息,可以签出Spring Boot API 文档或浏览直接源代码。如果您有特定问题,请查看how-to部分。

如果您熟悉 Spring Boot 的核心功能,则可以 continue 阅读production-ready features