3. 简介
Spring Profiles 提供了一种分离应用程序配置部分并使其仅在某些环境中可用的方法。任何@Component
,@Configuration
或@ConfigurationProperties
可以在@Profile
加载时标记为限制,如下例所示:
@Configuration(proxyBeanMethods = false)
@Profile("production")
public class ProductionConfiguration {
// ...
}
您可以使用spring.profiles.active
Environment
属性来指定哪些配置文件处于活动状态。您可以通过本章前面描述的任何方式指定属性。例如,您可以将它包含在您的application.properties
中,如以下示例所示:
特性
spring.profiles.active=dev,hsqldb
您还可以使用以下开关在命令行上指定它:--spring.profiles.active=dev,hsqldb
.
如果没有配置文件处于活动状态,则启用默认配置文件。默认配置文件的名称是default
,并且可以使用该spring.profiles.default
Environment
属性进行调整,如以下示例所示:
特性
spring.profiles.default=none
spring.profiles.active
并且spring.profiles.default
只能在非配置文件特定文档中使用。这意味着它们不能包含在配置文件特定文件或由.spring.config.activate.on-profile
例如第二个文档配置无效:
特性
# this document is valid
spring.profiles.active=prod
#---
# this document is invalid
spring.config.activate.on-profile=prod
spring.profiles.active=metrics
3.1添加活动配置文件
该spring.profiles.active
属性遵循与其他属性相同的排序规则:最高者PropertySource
获胜。这意味着您可以在其中指定活动配置文件,application.properties
然后使用命令行开关替换它们。
有时,将属性添加到活动配置文件而不是替换它们很有用。该属性可用于在由该属性spring.profiles.include
激活的配置文件之上添加活动配置文件。入口点还有一个用于设置附加配置文件的 Java API spring.profiles.active
。SpringApplication
请参阅SpringApplicationsetAdditionalProfiles()
中的方法。
例如,当运行具有以下属性的应用程序时,即使使用 --spring.profiles.active 开关运行,也会激活公共和本地配置文件:
特性
spring.profiles.include[0]=common
spring.profiles.include[1]=local
如果给定的配置文件处于活动状态,则在下一节中描述的配置文件组也可用于添加活动配置文件。
3.2. 配置文件组
有时,您在应用程序中定义和使用的配置文件过于细化,使用起来很麻烦。例如,您可能拥有用于独立启用数据库和消息传递功能的配置文件proddb
。prodmq
为了帮助解决这个问题,Spring Boot 允许您定义配置文件组。配置文件组允许您为相关的配置文件组定义逻辑名称。
例如,我们可以创建一个production
由我们的proddb
和prodmq
配置文件组成的组。
特性
spring.profiles.group.production[0]=proddb
spring.profiles.group.production[1]=prodmq
我们的应用程序现在可以启动,一--spring.profiles.active=production
键激活production
,proddb
和prodmq
配置文件。
3.3. 以编程方式设置配置文件
SpringApplication.setAdditionalProfiles(…)
您可以通过在应用程序运行之前调用来以编程方式设置活动配置文件。也可以使用 Spring 的ConfigurableEnvironment
界面激活配置文件。
3.4. 配置文件特定的配置文件
application.properties
(或application.yml
)和通过引用的文件的特定配置文件变体@ConfigurationProperties
被视为文件并加载。有关详细信息,请参阅“配置文件特定文件”。
4. 记录
Spring Boot 使用Commons Logging进行所有内部日志记录,但保持底层日志实现打开。为Java Util Logging、Log4J2和Logback提供了默认配置。在每种情况下,记录器都预先配置为使用控制台输出,并且还提供可选的文件输出。
默认情况下,如果您使用“Starters”,则使用 Logback 进行日志记录。还包括适当的 Logback 路由,以确保使用 Java Util Logging、Commons Logging、Log4J 或 SLF4J 的依赖库都能正常工作。
4.1日志格式
Spring Boot 的默认日志输出类似于以下示例:
2022-10-20 12:40:11.311 INFO 16138 --- [main] osbdfsMyApplication:在 PID 16138 的 myhost 上使用 Java 1.8.0_345 启动 MyApplication(/opt/apps/myapp.jar 由 myuser 在 /opt/apps/ 中启动)
2022-10-20 12:40:11.330 INFO 16138 --- [main] osbdfsMyApplication:未设置活动配置文件,回退到 1 个默认配置文件:“默认”
2022-10-20 12:40:13.056 INFO 16138 -- - [主] osbwembedded.tomcat.TomcatWebServer:Tomcat 使用端口初始化:8080 (http)
2022-10-20 12:40:13.070 INFO 16138 --- [主] o.apache.catalina.core.StandardService:启动服务 [Tomcat]
2022-10-20 12:40:13.070 INFO 16138 --- [main] org.apache.catalina.core.StandardEngine:启动 Servlet 引擎:[Apache Tomcat/9.0.68]
2022-10-20 12:40:13.178 INFO 16138 --- [main] oaccC[Tomcat].[localhost].[/]:初始化 Spring 嵌入式 WebApplicationContext
2022-10-20 12:40:13.178 INFO 16138 --- [main] wscServletWebServerApplicationContext:Root WebApplicationContext:初始化完成在 1762 毫秒
2022-10-20 12:40:13.840 INFO 16138 --- [main] osbwembedded.tomcat.TomcatWebServer:Tomcat 在端口:8080 (http) 上启动,上下文路径为 ''
2022-10-20 12 :40:13.850 INFO 16138 --- [main] osbdfsMyApplication:MyApplication 在 4.062 秒内启动(JVM 运行 5.452)
输出以下项目:
- 日期和时间:毫秒精度,易于排序。
- 日志级别:
ERROR
、WARN
、INFO
、DEBUG
或TRACE
。 - 进程标识。
-
---
用于区分实际日志消息开始的分隔符。 - 线程名称:括在方括号中(可能会被截断以用于控制台输出)。
- 记录器名称:这通常是源类名称(通常缩写)。
- 日志消息。
4.2. 控制台输出
默认日志配置在写入时将消息回显到控制台。默认情况下,会记录ERROR
-level、WARN
-level 和INFO
-level 消息。--debug
您还可以通过使用标志启动应用程序来启用“调试”模式。
$ java -jar myapp.jar --debug
启用调试模式后,会配置一系列核心记录器(嵌入式容器、Hibernate 和 Spring Boot)以输出更多信息。启用调试模式不会将您的应用程序配置为记录所有DEBUG
级别的消息。
或者,您可以通过使用--trace
标志(或trace=true
在您的application.properties
. 这样做可以为选择的核心记录器(嵌入式容器、Hibernate 模式生成和整个 Spring 产品组合)启用跟踪日志记录。
4.2.1颜色编码输出
如果您的终端支持 ANSI,则使用颜色输出来提高可读性。您可以设置spring.output.ansi.enabled
为支持的值以覆盖自动检测。
使用%clr
转换字配置颜色编码。在最简单的形式中,转换器根据日志级别为输出着色,如以下示例所示:
%clr(%5p)
下表描述了日志级别到颜色的映射:
等级 | 颜色 |
| 红色的 |
| 红色的 |
| 黄色 |
| 绿色的 |
| 绿色的 |
| 绿色的 |
或者,您可以通过将其作为转换选项提供来指定应使用的颜色或样式。例如,要将文本变为黄色,请使用以下设置:
%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){yellow}
支持以下颜色和样式:
-
blue
-
cyan
-
faint
-
green
-
magenta
-
red
-
yellow
4.3. 文件输出
默认情况下,Spring Boot 仅记录到控制台,不写入日志文件。如果您想在控制台输出之外写入日志文件,您需要设置一个logging.file.name
orlogging.file.path
属性(例如,在您的application.properties
.
下表显示了如何logging.*
一起使用这些属性:
表 5. 日志记录属性
| | 例子 | 描述 |
(没有任何) | (没有任何) | 仅控制台日志记录。 | |
具体文件 | (没有任何) | | 写入指定的日志文件。名称可以是确切的位置,也可以是相对于当前目录的位置。 |
(没有任何) | 具体目录 | | 写入 |
日志文件在达到 10 MB 时会旋转,并且与控制台输出一样,默认情况下会记录ERROR
-level、WARN
-level 和INFO
-level 消息。
4.4. 文件轮换
application.properties
如果您使用的是 Logback,则可以使用您的orapplication.yaml
文件微调日志轮换设置。对于所有其他日志记录系统,您需要自己直接配置轮换设置(例如,如果您使用 Log4J2,那么您可以添加一个log4j2.xml
或log4j2-spring.xml
文件)。
支持以下轮换策略属性:
姓名 | 描述 |
| 用于创建日志存档的文件名模式。 |
| 如果应在应用程序启动时进行日志归档清理。 |
| 归档前日志文件的最大大小。 |
| 在被删除之前可以占用的最大大小的日志档案。 |
| 要保留的存档日志文件的最大数量(默认为 7)。 |
4.5. 日志级别
所有受支持的日志记录系统都可以通过使用 TRACE、DEBUG、INFO、WARN、ERROR、FATAL 或 OFF 之一在 Spring 中设置记录器级别(例如Environment
in application.properties
) 。记录器可以使用.logging.level.<logger-name>=<level>
level
root
logging.level.root
以下示例显示了潜在的日志记录设置application.properties
:
特性
logging.level.root=warn
logging.level.org.springframework.web=debug
logging.level.org.hibernate=error
也可以使用环境变量设置日志记录级别。例如,LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_WEB=DEBUG
将设置org.springframework.web
为DEBUG
。
4.6. 日志组
能够将相关的记录器组合在一起通常很有用,以便可以同时配置它们。例如,您可能通常会更改所有与 Tomcat 相关的记录器的日志记录级别,但您不容易记住顶级包。
为了解决这个问题,Spring Boot 允许您在 Spring 中定义日志记录组Environment
。例如,您可以通过以下方式定义“tomcat”组,方法是将其添加到您的application.properties
:
特性
logging.group.tomcat=org.apache.catalina,org.apache.coyote,org.apache.tomcat
定义后,您可以使用一行更改组中所有记录器的级别:
特性
logging.level.tomcat=trace
Spring Boot 包括以下可开箱即用的预定义日志记录组:
姓名 | 记录器 |
网络 | |
sql | |
4.7. 使用日志关闭挂钩
为了在您的应用程序终止时释放日志记录资源,提供了一个关闭挂钩,该挂钩将在 JVM 退出时触发日志系统清理。除非您的应用程序部署为 war 文件,否则此关闭挂钩会自动注册。如果您的应用程序具有复杂的上下文层次结构,则关闭挂钩可能无法满足您的需求。如果没有,请禁用关闭挂钩并调查底层日志系统直接提供的选项。例如,Logback 提供上下文选择器,允许每个 Logger 在其自己的上下文中创建。您可以使用该logging.register-shutdown-hook
属性来禁用关闭挂钩。将其设置为false
将禁用注册。您可以在application.properties
orapplication.yaml
文件中设置属性:
特性
logging.register-shutdown-hook=false
4.8. 自定义日志配置
各种日志系统可以通过在类路径中包含适当的库来激活,并且可以通过在类路径的根目录或由以下 SpringEnvironment
属性指定的位置提供合适的配置文件来进一步定制logging.config
:
org.springframework.boot.logging.LoggingSystem
您可以使用system 属性强制 Spring Boot 使用特定的日志记录系统。该值应该是实现的完全限定类名LoggingSystem
。您还可以使用none
.
根据您的日志记录系统,将加载以下文件:
测井系统 | 定制 |
回溯 | |
日志4j2 | |
JDK(Java 实用程序日志记录) | |
为了帮助进行自定义,一些其他属性从 Spring 转移Environment
到 System 属性,如下表所述:
春天环境 | 系统属性 | 注释 |
| | 记录异常时使用的转换字。 |
| | 如果已定义,它将在默认日志配置中使用。 |
| | 如果已定义,它将在默认日志配置中使用。 |
| | 在控制台上使用的日志模式 (stdout)。 |
| | 日志日期格式的附加模式。 |
| | 用于控制台日志记录的字符集。 |
| | 在文件中使用的日志模式(如果 |
| | 用于文件日志记录的字符集(如果 |
| | 呈现日志级别时使用的格式(默认 |
| | 当前进程 ID(如果可能且尚未定义为 OS 环境变量时发现)。 |
如果使用 Logback,还会传输以下属性:
春天环境 | 系统属性 | 注释 |
| | 翻转日志文件名的模式(默认 |
| | 是否在启动时清理归档日志文件。 |
| | 最大日志文件大小。 |
| | 要保留的日志备份的总大小。 |
| | 要保留的存档日志文件的最大数量。 |
所有受支持的日志记录系统在解析其配置文件时都可以查阅系统属性。spring-boot.jar
有关示例,请参见中的默认配置:
- 回溯
- 日志4j 2
- Java 实用程序日志记录
4.9. Logback 扩展
Spring Boot 包含许多对 Logback 的扩展,可以帮助进行高级配置。您可以在logback-spring.xml
配置文件中使用这些扩展。
ch.qos.logback.core.joran.spi.Interpreter@4 :71中的错误- [springProperty] 没有适用的操作,当前 ElementPath 是 [[configuration][springProperty]] ch.qos.logback.core.joran
中的错误.spi.Interpreter@4 :71 - [springProfile] 没有适用的操作,当前 ElementPath 是 [[configuration][springProfile]]
4.9.1配置文件特定的配置
该<springProfile>
标签允许您根据活动的 Spring 配置文件选择性地包含或排除配置部分。元素内的任何位置都支持配置文件部分<configuration>
。使用该name
属性来指定哪个配置文件接受配置。标签可以包含配置<springProfile>
文件名称(例如staging
)或配置文件表达式。配置文件表达式允许表达更复杂的配置文件逻辑,例如production & (eu-central | eu-west)
. 查看参考指南以获取更多详细信息。以下清单显示了三个示例配置文件:
<springProfile name="staging">
<!-- configuration to be enabled when the "staging" profile is active -->
</springProfile>
<springProfile name="dev | staging">
<!-- configuration to be enabled when the "dev" or "staging" profiles are active -->
</springProfile>
<springProfile name="!production">
<!-- configuration to be enabled when the "production" profile is not active -->
</springProfile>
4.9.2. 环境属性
该<springProperty>
标签允许您公开 Spring 中的属性Environment
以在 Logback 中使用。application.properties
如果您想在 Logback 配置中访问文件中的值,这样做会很有用。该标签的工作方式与 Logback 的标准<property>
标签类似。value
但是,您可以指定source
属性的 (来自) ,而不是直接指定Environment
。如果您需要将属性存储在范围以外的某个位置local
,则可以使用该scope
属性。如果您需要一个备用值(如果该属性未在 中设置Environment
),您可以使用该defaultValue
属性。以下示例显示了如何公开属性以在 Logback 中使用:
<springProperty scope="context" name="fluentHost" source="myapp.fluentd.host"
defaultValue="localhost"/>
<appender name="FLUENT" class="ch.qos.logback.more.appenders.DataFluentAppender">
<remoteHost>${fluentHost}</remoteHost>
...
</appender>
5.国际化
Spring Boot 支持本地化消息,以便您的应用程序可以满足不同语言偏好的用户。默认情况下,Spring Bootmessages
在类路径的根目录中查找资源包的存在。
可以使用命名空间配置资源包的基本名称以及其他几个属性spring.messages
,如下例所示:
特性
spring.messages.basename=messages,config.i18n.messages
spring.messages.fallback-to-system-locale=false
有关MessageSourceProperties更多支持的选项,请参阅。
6.JSON
Spring Boot 提供与三个 JSON 映射库的集成:
- 格森
- 杰克逊
- JSON-B
Jackson 是首选的默认库。
6.1杰克逊
提供了 Jackson 的自动配置,并且 Jackson 是spring-boot-starter-json
. 当 Jackson 在类路径上时,ObjectMapper
会自动配置一个 bean。提供了几个配置属性用于自定义ObjectMapper.
6.1.1. 自定义序列化器和反序列化器
如果您使用 Jackson 来序列化和反序列化 JSON 数据,您可能需要编写自己的类JsonSerializer
和JsonDeserializer
类。自定义序列化程序通常通过模块向 Jackson 注册,但 Spring Boot 提供了一个替代@JsonComponent
注解,可以更轻松地直接注册 Spring Bean。
您可以直接在或实现上使用@JsonComponent
注释。您还可以在包含序列化器/反序列化器作为内部类的类上使用它,如以下示例所示:JsonSerializer
JsonDeserializer
KeyDeserializer
@JsonComponent
public class MyJsonComponent {
public static class Serializer extends JsonSerializer<MyObject> {
@Override
public void serialize(MyObject value, JsonGenerator jgen, SerializerProvider serializers) throws IOException {
jgen.writeStartObject();
jgen.writeStringField("name", value.getName());
jgen.writeNumberField("age", value.getAge());
jgen.writeEndObject();
}
}
public static class Deserializer extends JsonDeserializer<MyObject> {
@Override
public MyObject deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException {
ObjectCodec codec = jsonParser.getCodec();
JsonNode tree = codec.readTree(jsonParser);
String name = tree.get("name").textValue();
int age = tree.get("age").intValue();
return new MyObject(name, age);
}
}
}
中的所有@JsonComponent
bean 都会ApplicationContext
自动向 Jackson 注册。因为@JsonComponent
是用 元注释的@Component
,所以通常的组件扫描规则适用。
Spring Boot also provides JsonObjectSerializer and JsonObjectDeserializer base classes that provide useful alternatives to the standard Jackson versions when serializing objects. See JsonObjectSerializer and JsonObjectDeserializer in the Javadoc for details.
The example above can be rewritten to use JsonObjectSerializer
/JsonObjectDeserializer
as follows:
@JsonComponent
public class MyJsonComponent {
public static class Serializer extends JsonObjectSerializer<MyObject> {
@Override
protected void serializeObject(MyObject value, JsonGenerator jgen, SerializerProvider provider)
throws IOException {
jgen.writeStringField("name", value.getName());
jgen.writeNumberField("age", value.getAge());
}
}
public static class Deserializer extends JsonObjectDeserializer<MyObject> {
@Override
protected MyObject deserializeObject(JsonParser jsonParser, DeserializationContext context, ObjectCodec codec,
JsonNode tree) throws IOException {
String name = nullSafeValue(tree.get("name"), String.class);
int age = nullSafeValue(tree.get("age"), Integer.class);
return new MyObject(name, age);
}
}
}
6.1.2. 混合
Jackson 支持 mixins,可用于将其他注释混合到已在目标类上声明的注释中。Spring Boot 的 Jackson 自动配置将扫描您应用程序的包以查找带有注释的类,@JsonMixin
并将它们注册到 auto-configuredObjectMapper
中。注册由 Spring Boot 的JsonMixinModule
.
6.2. 格森
提供了 Gson 的自动配置。当 Gson 在类路径上时,Gson
会自动配置一个 bean。提供了几个spring.gson.*
配置属性用于自定义配置。要进行更多控制,GsonBuilderCustomizer
可以使用一个或多个 bean。
6.3. JSON-B
提供了 JSON-B 的自动配置。当 JSON-B API 和实现在类路径上时,Jsonb
将自动配置一个 bean。首选的 JSON-B 实现是为其提供依赖管理的 Apache Johnzon。
7. 任务执行与调度
在上下文中没有Executor
bean 的情况下,Spring Boot 自动配置一个ThreadPoolTaskExecutor
合理的默认值,这些默认值可以自动关联到异步任务执行 ( @EnableAsync
) 和 Spring MVC 异步请求处理。
线程池使用8个核心线程,可以根据负载增长和收缩。这些默认设置可以使用命名空间进行微调spring.task.execution
,如以下示例所示:
特性
spring.task.execution.pool.max-size=16
spring.task.execution.pool.queue-capacity=100
spring.task.execution.pool.keep-alive=10s
这将线程池更改为使用有界队列,以便当队列已满(100 个任务)时,线程池增加到最多 16 个线程。由于线程在空闲 10 秒(而不是默认情况下为 60 秒)时被回收,因此池的收缩更具侵略性。
ThreadPoolTaskScheduler
如果需要与计划的任务执行相关联(@EnableScheduling
例如使用),也可以自动配置A。线程池默认使用一个线程,可以使用命名空间微调其设置spring.task.scheduling
,如下例所示:
特性
spring.task.scheduling.thread-name-prefix=scheduling-
spring.task.scheduling.pool.size=2
如果需要创建自定义执行程序或调度程序,则TaskExecutorBuilder
bean 和bean 在上下文中都可用。TaskSchedulerBuilder
8. 测试
Spring Boot 提供了许多实用程序和注释来帮助测试您的应用程序。测试支持由两个模块提供:spring-boot-test
包含核心项目,并spring-boot-test-autoconfigure
支持测试的自动配置。
大多数开发人员使用spring-boot-starter-test
“Starter”,它导入 Spring Boot 测试模块以及 JUnit Jupiter、AssertJ、Hamcrest 和许多其他有用的库。
hamcrest-core
被排除在外,赞成org.hamcrest:hamcrest
那是 的一部分spring-boot-starter-test
。
8.1测试范围依赖
“ spring-boot-starter-test
Starter”(在 中test
scope
)包含以下提供的库:
- JUnit 5:单元测试 Java 应用程序的事实标准。
- Spring Test & Spring Boot Test:Spring Boot 应用程序的实用程序和集成测试支持。
- AssertJ:一个流畅的断言库。
- Hamcrest:匹配器对象库(也称为约束或谓词)。
- Mockito:Java 模拟框架。
- JSONassert : JSON 的断言库。
- JsonPath:JSON 的 XPath。
我们通常发现这些通用库在编写测试时很有用。如果这些库不适合您的需求,您可以添加自己的其他测试依赖项。
8.2. 测试 Spring 应用程序
依赖注入的主要优点之一是它应该使您的代码更容易进行单元测试。您可以使用new
运算符来实例化对象,甚至无需涉及 Spring。您还可以使用模拟对象而不是真正的依赖项。
通常,您需要超越单元测试并开始集成测试(使用 Spring ApplicationContext
)。能够执行集成测试而不需要部署您的应用程序或需要连接到其他基础设施是很有用的。
Spring 框架包括一个用于此类集成测试的专用测试模块。你可以直接声明一个依赖org.springframework:spring-test
或者使用spring-boot-starter-test
“Starter”来传递它。
如果您以前没有使用过该spring-test
模块,则应首先阅读 Spring Framework 参考文档的相关部分。
8.3. 测试 Spring Boot 应用程序
Spring Boot 应用程序是 Spring ApplicationContext
,因此除了您通常使用普通 Spring 上下文执行的操作之外,无需进行任何特别的测试即可对其进行测试。
Spring Boot 提供了注解,当您需要 Spring Boot 特性时@SpringBootTest
,可以将其用作标准注解的替代方案。spring-test
@ContextConfiguration
注释通过在您的测试中创建ApplicationContextSpringApplication使用的. 除了@SpringBootTest
许多其他注释之外,还提供了用于测试应用程序更具体的切片。
默认情况下,@SpringBootTest
不会启动服务器。您可以使用 的webEnvironment
属性@SpringBootTest
来进一步优化测试的运行方式:
-
MOCK
(默认):加载网络ApplicationContext
并提供模拟网络环境。使用此注释时不启动嵌入式服务器。如果您的类路径上没有可用的 Web 环境,则此模式会透明地回退到创建常规的 non-webApplicationContext
。它可以与您的 Web 应用程序结合使用@AutoConfigureMockMvc或@AutoConfigureWebTestClient用于基于模拟的测试。 -
RANDOM_PORT
: 加载WebServerApplicationContext
并提供一个真实的网络环境。嵌入式服务器启动并侦听随机端口。 -
DEFINED_PORT
: 加载WebServerApplicationContext
并提供一个真实的网络环境。嵌入式服务器启动并侦听定义的端口(来自您的application.properties
)或8080
. -
NONE
ApplicationContext
:通过使用加载一个SpringApplication
但不提供任何Web 环境(模拟或其他)。
8.3.1. 检测 Web 应用程序类型
如果 Spring MVC 可用,则配置常规的基于 MVC 的应用程序上下文。如果您只有 Spring WebFlux,我们将检测到它并配置一个基于 WebFlux 的应用程序上下文。
如果两者都存在,则 Spring MVC 优先。如果要在这种情况下测试响应式 Web 应用程序,则必须设置spring.main.web-application-type
属性:
@SpringBootTest(properties = "spring.main.web-application-type=reactive")
class MyWebFluxTests {
// ...
}
8.3.2. 检测测试配置
如果您熟悉 Spring Test Framework,您可能习惯于使用@ContextConfiguration(classes=…)
以指定@Configuration
要加载的 Spring。或者,您可能经常@Configuration
在测试中使用嵌套类。
在测试 Spring Boot 应用程序时,通常不需要这样做。@*Test
只要您没有明确定义,Spring Boot 的注释就会自动搜索您的主要配置。
搜索算法从包含测试的包开始,直到找到一个用@SpringBootApplication
or注释的类@SpringBootConfiguration
。只要您以合理的方式构建代码,通常会找到您的主要配置。
如果要自定义主要配置,可以使用嵌套@TestConfiguration
类。与将@Configuration
使用嵌套类代替应用程序的主要配置不同,嵌套@TestConfiguration
类是在应用程序的主要配置之外使用的。
8.3.3. 排除测试配置
如果您的应用程序使用组件扫描(例如,如果您使用@SpringBootApplication
or @ComponentScan
),您可能会发现仅为特定测试创建的顶级配置类意外地在各处被拾取。
正如我们之前看到的,@TestConfiguration
可以在测试的内部类上使用来自定义主要配置。当放置在顶级类上时,@TestConfiguration
表示src/test/java
不应通过扫描获取其中的类。然后,您可以在需要的地方显式导入该类,如以下示例所示:
@SpringBootTest
@Import(MyTestsConfiguration.class)
class MyTests {
@Test
void exampleTest() {
// ...
}
}
8.3.4. 使用应用程序参数
如果您的应用程序需要arguments,您可以使用属性@SpringBootTest
注入它们。args
@SpringBootTest(args = "--app.test=one")
class MyApplicationArgumentTests {
@Test
void applicationArgumentsPopulated(@Autowired ApplicationArguments args) {
assertThat(args.getOptionNames()).containsOnly("app.test");
assertThat(args.getOptionValues("app.test")).containsOnly("one");
}
}
8.3.5使用模拟环境进行测试
默认情况下,@SpringBootTest
不会启动服务器,而是设置一个模拟环境来测试 Web 端点。
使用 Spring MVC,我们可以使用MockMvcor查询我们的 Web 端点WebTestClient
,如下例所示:
@SpringBootTest
@AutoConfigureMockMvc
class MyMockMvcTests {
@Test
void testWithMockMvc(@Autowired MockMvc mvc) throws Exception {
mvc.perform(get("/")).andExpect(status().isOk()).andExpect(content().string("Hello World"));
}
// If Spring WebFlux is on the classpath, you can drive MVC tests with a WebTestClient
@Test
void testWithWebTestClient(@Autowired WebTestClient webClient) {
webClient
.get().uri("/")
.exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("Hello World");
}
}
使用 Spring WebFlux 端点,您可以使用WebTestClient如下示例所示:
@SpringBootTest
@AutoConfigureWebTestClient
class MyMockWebTestClientTests {
@Test
void exampleTest(@Autowired WebTestClient webClient) {
webClient
.get().uri("/")
.exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("Hello World");
}
}
8.3.6. 使用正在运行的服务器进行测试
如果您需要启动一个完整运行的服务器,我们建议您使用随机端口。如果您使用@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
,则每次运行测试时都会随机选择一个可用端口。
@LocalServerPort
注释可用于将实际使用的端口注入到您的测试中。为方便起见,需要对启动的服务器进行 REST 调用的测试可以额外添加@Autowire
一个WebTestClient,它解析到正在运行的服务器的相关链接,并带有用于验证响应的专用 API,如下例所示:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyRandomPortWebTestClientTests {
@Test
void exampleTest(@Autowired WebTestClient webClient) {
webClient
.get().uri("/")
.exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("Hello World");
}
}
此设置需要spring-webflux
在类路径上。如果你不能或不会添加 webflux,Spring Boot 还提供了一个TestRestTemplate
工具:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyRandomPortTestRestTemplateTests {
@Test
void exampleTest(@Autowired TestRestTemplate restTemplate) {
String body = restTemplate.getForObject("/", String.class);
assertThat(body).isEqualTo("Hello World");
}
}
8.3.7. 自定义 WebTestClient
要自定义WebTestClient
bean,请配置一个WebTestClientBuilderCustomizer
bean。任何此类 bean 都WebTestClient.Builder
使用用于创建WebTestClient
.
8.3.8. 使用 JMX
由于测试上下文框架缓存了上下文,JMX 默认是禁用的,以防止相同的组件在同一个域上注册。如果此类测试需要访问MBeanServer
,请考虑将其标记为脏:
@SpringBootTest(properties = "spring.jmx.enabled=true")
@DirtiesContext
class MyJmxTests {
@Autowired
private MBeanServer mBeanServer;
@Test
void exampleTest() {
assertThat(this.mBeanServer.getDomains()).contains("java.lang");
// ...
}
}
8.3.9使用指标
无论您的类路径如何,使用@SpringBootTest
.
如果您需要在集成测试中将指标导出到不同的后端,请使用@AutoConfigureMetrics
.
8.3.10模拟和窥探 Bean
运行测试时,有时需要在应用程序上下文中模拟某些组件。例如,您可能有一些在开发期间不可用的远程服务的外观。当您想要模拟在真实环境中可能难以触发的故障时,模拟也很有用。
Spring Boot 包含一个@MockBean
注解,可用于为您的ApplicationContext
. 您可以使用注解添加新 bean 或替换单个现有 bean 定义。注释可以直接用于测试类、测试中的字段或@Configuration
类和字段。在字段上使用时,创建的模拟实例也会被注入。在每个测试方法之后,模拟 bean 都会自动重置。
以下示例将现有RemoteService
bean 替换为模拟实现:
@SpringBootTest
class MyTests {
@Autowired
private Reverser reverser;
@MockBean
private RemoteService remoteService;
@Test
void exampleTest() {
given(this.remoteService.getValue()).willReturn("spring");
String reverse = this.reverser.getReverseValue(); // Calls injected RemoteService
assertThat(reverse).isEqualTo("gnirps");
}
}
此外,您可以使用@SpyBean
Mockito 包装任何现有的 bean spy
。
8.3.11自动配置的测试
Spring Boot 的自动配置系统适用于应用程序,但有时对于测试来说有点太多了。它通常有助于仅加载测试应用程序“切片”所需的配置部分。例如,您可能想要测试 Spring MVC 控制器是否正确映射 URL,并且您不想在这些测试中涉及数据库调用,或者您可能想要测试 JPA 实体,而当这些测试运行。
该spring-boot-test-autoconfigure
模块包含许多注释,可用于自动配置此类“切片”。它们中的每一个都以类似的方式工作,提供一个@…Test
可以加载的注释ApplicationContext
以及一个或多个@AutoConfigure…
可用于自定义自动配置设置的注释。
8.3.12自动配置的 JSON 测试
要测试对象 JSON 序列化和反序列化是否按预期工作,您可以使用@JsonTest
注释。 @JsonTest
自动配置可用的支持 JSON 映射器,它可以是以下库之一:
- 杰克逊
ObjectMapper
,任何@JsonComponent
豆子和任何杰克逊Module
的 -
Gson
-
Jsonb
如果需要配置自动配置的元素,可以使用@AutoConfigureJsonTesters
注解。
Spring Boot 包括基于 AssertJ 的帮助程序,它们与 JSONAssert 和 JsonPath 库一起检查 JSON 是否按预期显示。、JacksonTester
、GsonTester
和类可分别用于 Jackson、Gson、Jsonb 和 Strings JsonbTester
。BasicJsonTester
测试类上的任何辅助字段都可以@Autowired
在使用@JsonTest
. 以下示例显示了 Jackson 的测试类:
@JsonTest
class MyJsonTests {
@Autowired
private JacksonTester<VehicleDetails> json;
@Test
void serialize() throws Exception {
VehicleDetails details = new VehicleDetails("Honda", "Civic");
// Assert against a `.json` file in the same package as the test
assertThat(this.json.write(details)).isEqualToJson("expected.json");
// Or use JSON path based assertions
assertThat(this.json.write(details)).hasJsonPathStringValue("@.make");
assertThat(this.json.write(details)).extractingJsonPathStringValue("@.make").isEqualTo("Honda");
}
@Test
void deserialize() throws Exception {
String content = "{\"make\":\"Ford\",\"model\":\"Focus\"}";
assertThat(this.json.parse(content)).isEqualTo(new VehicleDetails("Ford", "Focus"));
assertThat(this.json.parseObject(content).getMake()).isEqualTo("Ford");
}
}
如果您使用 Spring Boot 的基于 AssertJ 的帮助器对给定 JSON 路径中的数字值进行断言,则可能无法使用,isEqualTo
具体取决于类型。相反,您可以使用 AssertJsatisfies
断言该值与给定条件匹配。例如,以下示例断言实际数字是接近0.15
偏移量的浮点值0.01
。
@Test
void someTest() throws Exception {
SomeObject value = new SomeObject(0.152f);
assertThat(this.json.write(value)).extractingJsonPathNumberValue("@.test.numberValue")
.satisfies((number) -> assertThat(number.floatValue()).isCloseTo(0.15f, within(0.01f)));
}
8.3.13自动配置的 Spring MVC 测试
要测试 Spring MVC 控制器是否按预期工作,请使用@WebMvcTest
注解。 @WebMvcTest
自动配置 Spring MVC 基础结构并将扫描的 bean 限制为@Controller
, @ControllerAdvice
, @JsonComponent
, Converter
, GenericConverter
, Filter
, HandlerInterceptor
, WebMvcConfigurer
,WebMvcRegistrations
和HandlerMethodArgumentResolver
. 使用注解 时不会扫描常规@Component
和bean。可用于包含bean。@ConfigurationProperties
@WebMvcTest
@EnableConfigurationProperties
@ConfigurationProperties
通常,@WebMvcTest
仅限于单个控制器,并与 结合使用@MockBean
,为所需的协作者提供模拟实现。
@WebMvcTest
也自动配置MockMvc
。Mock MVC 提供了一种强大的方法来快速测试 MVC 控制器,而无需启动完整的 HTTP 服务器。
@WebMvcTest(UserVehicleController.class)
class MyControllerTests {
@Autowired
private MockMvc mvc;
@MockBean
private UserVehicleService userVehicleService;
@Test
void testExample() throws Exception {
given(this.userVehicleService.getVehicleDetails("sboot"))
.willReturn(new VehicleDetails("Honda", "Civic"));
this.mvc.perform(get("/sboot/vehicle").accept(MediaType.TEXT_PLAIN))
.andExpect(status().isOk())
.andExpect(content().string("Honda Civic"));
}
}
如果您使用 HtmlUnit 和 Selenium,自动配置还提供 HtmlUnit WebClient
bean 和/或 Selenium WebDriver
bean。以下示例使用 HtmlUnit:
@WebMvcTest(UserVehicleController.class)
class MyHtmlUnitTests {
@Autowired
private WebClient webClient;
@MockBean
private UserVehicleService userVehicleService;
@Test
void testExample() throws Exception {
given(this.userVehicleService.getVehicleDetails("sboot")).willReturn(new VehicleDetails("Honda", "Civic"));
HtmlPage page = this.webClient.getPage("/sboot/vehicle.html");
assertThat(page.getBody().getTextContent()).isEqualTo("Honda Civic");
}
}
如果类路径上有 Spring Security,@WebMvcTest
也会扫描WebSecurityConfigurer
bean。您可以使用 Spring Security 的测试支持,而不是完全禁用此类测试的安全性。
8.3.14自动配置的 Spring WebFlux 测试
要测试Spring WebFlux控制器是否按预期工作,您可以使用@WebFluxTest
注释。 @WebFluxTest
自动配置 Spring WebFlux 基础结构并将扫描的 bean 限制为@Controller
、@ControllerAdvice
、@JsonComponent
、Converter
、GenericConverter
、WebFilter
和WebFluxConfigurer
. 使用注解 时不会扫描常规@Component
和bean。可用于包含bean。@ConfigurationProperties
@WebFluxTest
@EnableConfigurationProperties
@ConfigurationProperties
通常,@WebFluxTest
仅限于单个控制器并与@MockBean
注释结合使用,为所需的协作者提供模拟实现。
@WebFluxTest
还有 auto-configures WebTestClient,它提供了一种强大的方法来快速测试 WebFlux 控制器,而无需启动完整的 HTTP 服务器。
@WebFluxTest(UserVehicleController.class)
class MyControllerTests {
@Autowired
private WebTestClient webClient;
@MockBean
private UserVehicleService userVehicleService;
@Test
void testExample() {
given(this.userVehicleService.getVehicleDetails("sboot"))
.willReturn(new VehicleDetails("Honda", "Civic"));
this.webClient.get().uri("/sboot/vehicle").accept(MediaType.TEXT_PLAIN).exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("Honda Civic");
}
}
8.3.15自动配置的 Spring GraphQL 测试
Spring GraphQL 提供了专门的测试支持模块;您需要将其添加到您的项目中:
马文
<dependencies>
<dependency>
<groupId>org.springframework.graphql</groupId>
<artifactId>spring-graphql-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Unless already present in the compile scope -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
摇篮
dependencies {
testImplementation("org.springframework.graphql:spring-graphql-test")
// Unless already present in the implementation configuration
testImplementation("org.springframework.boot:spring-boot-starter-webflux")
}
这个测试模块附带了GraphQlTester。测试仪在测试中大量使用,所以一定要熟悉使用它。有GraphQlTester
变体,Spring Boot 将根据测试类型自动配置它们:
- 在
ExecutionGraphQlServiceTester
服务器端执行测试,没有客户端也没有传输 - 使用
HttpGraphQlTester
连接到服务器的客户端执行测试,有或没有实时服务器
Spring Boot 可帮助您使用注释测试Spring GraphQL 控制器@GraphQlTest
。 @GraphQlTest
自动配置 Spring GraphQL 基础设施,不涉及任何传输或服务器。这会将扫描的bean 限制为@Controller
、RuntimeWiringConfigurer
、JsonComponent
、Converter
、GenericConverter
、DataFetcherExceptionResolver
和。使用注解 时不会扫描常规和bean。可用于包含bean。Instrumentation
GraphQlSourceBuilderCustomizer
@Component
@ConfigurationProperties
@GraphQlTest
@EnableConfigurationProperties
@ConfigurationProperties
通常,@GraphQlTest
仅限于一组控制器并与@MockBean
注释结合使用,为所需的协作者提供模拟实现。
@GraphQlTest(GreetingController.class)
class GreetingControllerTests {
@Autowired
private GraphQlTester graphQlTester;
@Test
void shouldGreetWithSpecificName() {
this.graphQlTester.document("{ greeting(name: \"Alice\") } ").execute().path("greeting").entity(String.class)
.isEqualTo("Hello, Alice!");
}
@Test
void shouldGreetWithDefaultName() {
this.graphQlTester.document("{ greeting } ").execute().path("greeting").entity(String.class)
.isEqualTo("Hello, Spring!");
}
}
@SpringBootTest
测试是完整的集成测试,涉及整个应用程序。当使用随机或定义的端口时,会配置一个实时服务器并HttpGraphQlTester
自动提供一个 bean,以便您可以使用它来测试您的服务器。配置 MOCK 环境后,您还可以HttpGraphQlTester
通过使用以下命令注释测试类来请求 bean @AutoConfigureHttpGraphQlTester
:
@AutoConfigureHttpGraphQlTester
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
class GraphQlIntegrationTests {
@Test
void shouldGreetWithSpecificName(@Autowired HttpGraphQlTester graphQlTester) {
HttpGraphQlTester authenticatedTester = graphQlTester.mutate()
.webTestClient(
(client) -> client.defaultHeaders((headers) -> headers.setBasicAuth("admin", "ilovespring")))
.build();
authenticatedTester.document("{ greeting(name: \"Alice\") } ").execute().path("greeting").entity(String.class)
.isEqualTo("Hello, Alice!");
}
}
8.3.16自动配置的数据 Cassandra 测试
您可以使用它@DataCassandraTest
来测试 Cassandra 应用程序。默认情况下,它配置一个CassandraTemplate
,扫描@Table
类,并配置 Spring Data Cassandra 存储库。使用注解 时不会扫描常规@Component
和bean。可用于包含bean。(有关在 Spring Boot 中使用 Cassandra 的更多信息,请参阅“ data.html ”。)@ConfigurationProperties
@DataCassandraTest
@EnableConfigurationProperties
@ConfigurationProperties
以下示例显示了在 Spring Boot 中使用 Cassandra 测试的典型设置:
@DataCassandraTest
class MyDataCassandraTests {
@Autowired
private SomeRepository repository;
}
8.3.17自动配置的 Data Couchbase 测试
您可以@DataCouchbaseTest
用来测试 Couchbase 应用程序。默认情况下,它配置一个CouchbaseTemplate
or ReactiveCouchbaseTemplate
,扫描@Document
类,并配置 Spring Data Couchbase 存储库。使用注解 时不会扫描常规@Component
和bean。可用于包含bean。(有关在 Spring Boot 中使用 Couchbase 的更多信息,请参阅本章前面的“ data.html ”。)@ConfigurationProperties
@DataCouchbaseTest
@EnableConfigurationProperties
@ConfigurationProperties
以下示例显示了在 Spring Boot 中使用 Couchbase 测试的典型设置:
@DataCouchbaseTest
class MyDataCouchbaseTests {
@Autowired
private SomeRepository repository;
// ...
}
8.3.18。自动配置的数据 Elasticsearch 测试
您可以使用它@DataElasticsearchTest
来测试 Elasticsearch 应用程序。默认情况下,它配置一个ElasticsearchRestTemplate
,扫描@Document
类,并配置 Spring Data Elasticsearch 存储库。使用注解 时不会扫描常规@Component
和bean。可用于包含bean。(有关在 Spring Boot 中使用 Elasticsearch 的更多信息,请参阅本章前面的“ data.html ”。)@ConfigurationProperties
@DataElasticsearchTest
@EnableConfigurationProperties
@ConfigurationProperties
以下示例显示了在 Spring Boot 中使用 Elasticsearch 测试的典型设置:
@DataElasticsearchTest
class MyDataElasticsearchTests {
@Autowired
private SomeRepository repository;
// ...
}
8.3.19自动配置的数据 JPA 测试
您可以使用@DataJpaTest
注释来测试 JPA 应用程序。默认情况下,它会扫描@Entity
类并配置 Spring Data JPA 存储库。如果类路径上有一个嵌入式数据库,它也会配置一个。默认情况下,通过将spring.jpa.show-sql
属性设置为 来记录 SQL 查询true
。这可以使用showSql()
注释的属性来禁用。
使用注解 时不会扫描常规@Component
和bean。可用于包含bean。@ConfigurationProperties
@DataJpaTest
@EnableConfigurationProperties
@ConfigurationProperties
默认情况下,数据 JPA 测试是事务性的,并在每个测试结束时回滚。有关更多详细信息,请参阅 Spring Framework 参考文档中的相关部分。如果这不是您想要的,您可以为测试或整个班级禁用事务管理,如下所示:
@DataJpaTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class MyNonTransactionalTests {
// ...
}
数据 JPA 测试也可以注入一个bean,它提供了一个专门为测试设计TestEntityManager的标准 JPA 的替代方案。EntityManager
JdbcTemplate
如果您需要,也可以使用A。以下示例显示了@DataJpaTest
正在使用的注释:
@DataJpaTest
class MyRepositoryTests {
@Autowired
private TestEntityManager entityManager;
@Autowired
private UserRepository repository;
@Test
void testExample() {
this.entityManager.persist(new User("sboot", "1234"));
User user = this.repository.findByUsername("sboot");
assertThat(user.getUsername()).isEqualTo("sboot");
assertThat(user.getEmployeeNumber()).isEqualTo("1234");
}
}
内存嵌入式数据库通常适用于测试,因为它们速度快且不需要任何安装。但是,如果您更喜欢针对真实数据库运行测试,则可以使用@AutoConfigureTestDatabase
注解,如以下示例所示:
@DataJpaTest
@AutoConfigureTestDatabase(replace = Replace.NONE)
class MyRepositoryTests {
// ...
}
8.3.20自动配置的 JDBC 测试
@JdbcTest
类似于@DataJpaTest
但适用于只需要 aDataSource
并且不使用 Spring Data JDBC 的测试。默认情况下,它配置一个内存嵌入式数据库和一个JdbcTemplate
. 使用注解 时不会扫描常规@Component
和bean。可用于包含bean。@ConfigurationProperties
@JdbcTest
@EnableConfigurationProperties
@ConfigurationProperties
默认情况下,JDBC 测试是事务性的,并在每次测试结束时回滚。有关更多详细信息,请参阅 Spring Framework 参考文档中的相关部分。如果这不是您想要的,您可以为测试或整个班级禁用事务管理,如下所示:
@JdbcTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class MyTransactionalTests {
}
如果您希望您的测试针对真实数据库运行,您可以使用与@AutoConfigureTestDatabase
for 相同的方式使用注解DataJpaTest
。