这一节深入研究了Spring Boot的细节。在这里,您可以了解您可能想要使用和定制的关键功能。如果您还没有这样做,您可能需要阅读“快速入门”和“使用Spring Boot开发”部分,这样您就有了很好的基础知识。
1. SpringApplication
SpringApplication
类提供了一种方便的方法来引导从main()
方法启动的Spring应用程序。在许多情况下,您可以委托静态SpringApplication.run
方法,如下例所示:
@SpringBootApplication public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } }
当您的应用程序启动时,您应该看到类似以下输出的内容:
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v3.0.0) 2022-11-24T17:03:48.214Z INFO 20764 --- [ main] o.s.b.d.f.s.MyApplication : Starting MyApplication using Java 17.0.5 with PID 20764 (/opt/apps/myapp.jar started by myuser in /opt/apps/) 2022-11-24T17:03:48.219Z INFO 20764 --- [ main] o.s.b.d.f.s.MyApplication : No active profile set, falling back to 1 default profile: "default" 2022-11-24T17:03:50.511Z INFO 20764 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2022-11-24T17:03:50.524Z INFO 20764 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2022-11-24T17:03:50.524Z INFO 20764 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.1] 2022-11-24T17:03:50.623Z INFO 20764 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2022-11-24T17:03:50.625Z INFO 20764 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2269 ms 2022-11-24T17:03:51.380Z INFO 20764 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2022-11-24T17:03:51.418Z INFO 20764 --- [ main] o.s.b.d.f.s.MyApplication : Started MyApplication in 3.872 seconds (process running for 5.008) 2022-11-24T17:03:51.506Z INFO 20764 --- [ionShutdownHook] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
默认情况下,会显示信息
日志记录消息,包括一些相关的启动详细信息,例如启动应用程序的用户。如果您需要信息
以外的日志级别,您可以设置它,如日志级别中所述。应用程序版本是使用主应用程序类的包中的实现版本确定的。可以通过将spring.main.log-startup-info
设置为FALSE
来关闭启动信息记录。这还将关闭应用程序的活动配置文件的记录。
To add additional logging during startup, you can override logStartupInfo(boolean) in a subclass of SpringApplication . |
1.1. Startup Failure
如果您的应用程序无法启动,注册的FailureAnalyzer
有机会提供专门的错误消息和修复问题的具体操作。例如,如果您在端口8080
上启动Web应用程序,并且该端口已在使用中,您应该会看到类似以下消息:
*************************** APPLICATION FAILED TO START *************************** Description: Embedded servlet container failed to start. Port 8080 was already in use. Action: Identify and stop the process that is listening on port 8080 or configure this application to listen on another port.
Spring Boot provides numerous FailureAnalyzer implementations, and you can add your own. |
如果没有故障分析器能够处理异常,您仍然可以显示完整的条件报告,以更好地了解哪里出了问题。为此,您需要为org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
.启用调试属性或启用调试日志记录
例如,如果您正在使用Java-jar
运行应用程序,则可以按如下方式启用调试
属性:
$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug
1.2. Lazy Initialization
SpringApplication
允许延迟初始化应用程序。启用延迟初始化时,将在需要时创建Bean,而不是在应用程序启动期间创建。因此,启用延迟初始化可以减少启动应用程序所需的时间。在Web应用程序中,启用延迟初始化将导致许多与Web相关的Bean在收到HTTP请求之前不会被初始化。
延迟初始化的一个缺点是它会延迟应用程序问题的发现。如果延迟初始化错误配置的Bean,则在启动过程中不会再出现故障,只有在初始化Bean时,问题才会变得明显。还必须注意确保JVM有足够的内存来容纳应用程序的所有Bean,而不仅仅是那些在启动期间初始化的Bean。由于这些原因,默认情况下不启用延迟初始化,建议在启用延迟初始化之前对JVM的堆大小进行微调。
可以使用SpringApplicationBuilder
上的lazyInitialization
方法或SpringApplication
上的setLazyInitialization
方法以编程方式启用延迟初始化。或者,也可以使用spring.main.lazy-Initialization
属性启用它,如下例所示:
spring.main.lazy-initialization=true
If you want to disable lazy initialization for certain beans while using lazy initialization for the rest of the application, you can explicitly set their lazy attribute to false using the @Lazy(false) annotation. |
1.3. Customizing the Banner
通过将banner.txt
文件添加到类路径或将spring.banner.Location
属性设置为此类文件的位置,可以更改启动时打印的横幅。如果文件的编码不是UTF-8,则可以设置spring.banner.charset
。
在banner.txt
文件中,您可以使用环境
中的任何键以及以下任何占位符:
Variable | Description |
---|---|
|
应用程序的版本号,在 |
|
应用程序的版本号,在 |
|
您正在使用的Spring Boot版本。例如 |
|
您正在使用的Spring Boot版本,经过格式化以便于显示(用括号括起来,并以 |
|
其中 |
|
应用程序的标题,在 |
The SpringApplication.setBanner(…) method can be used if you want to generate a banner programmatically. Use the org.springframework.boot.Banner interface and implement your own printBanner() method. |
您还可以使用spring.main.banner-mode
属性来确定是否必须在System.out
(控制台
)上打印横幅,将其发送到已配置的记录器(日志
),或者根本不生成横幅(关闭
)。
打印的横幅被注册为一个单独的Bean,名称如下:springBootBanner
。
仅当您使用的是Spring Boot启动器时,才能使用 这就是为什么我们建议您始终使用Java org.springframework.boot.loader.JarLauncher.启动未打包的JAR这将在构建类路径和启动应用程序之前初始化 |
1.4. Customizing SpringApplication
如果SpringApplication
的默认设置不合您的口味,您可以创建一个本地实例并对其进行自定义。例如,要关闭横幅,您可以这样写:
@SpringBootApplication public class MyApplication { public static void main(String[] args) { SpringApplication application = new SpringApplication(MyApplication.class); application.setBannerMode(Banner.Mode.OFF); application.run(args); } }
The constructor arguments passed to SpringApplication are configuration sources for Spring beans. In most cases, these are references to @Configuration classes, but they could also be direct references @Component classes. |
还可以使用应用程序属性
文件配置SpringApplication
。详情请参见外部化配置。
有关配置选项的完整列表,请参阅SpringApplication
Java。
1.5. Fluent Builder API
如果您需要构建ApplicationContext
层次结构(具有父/子关系的多个上下文),或者如果您更喜欢使用流畅的构建器API,则可以使用SpringApplicationBuilder
。
SpringApplicationBuilder
允许您将多个方法调用链接在一起,并包括允许您创建层次结构的父
和子
方法,如下例所示:
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);
There are some restrictions when creating an ApplicationContext hierarchy. For example, Web components must be contained within the child context, and the same Environment is used for both parent and child contexts. See the SpringApplicationBuilder Javadoc for full details. |
1.6. Application Availability
当部署在平台上时,应用程序可以使用诸如Kubernetes Probe之类的基础设施向平台提供有关其可用性的信息。Spring Boot包括对常用的“活跃度”和“就绪”可用性状态的开箱即用支持。如果您使用的是Spring Boot的“执行器”支持,那么这些状态将作为健康终结点组公开。
此外,您还可以通过将ApplicationAvailability
接口注入您自己的Bean来获取可用性状态。
1.6.1. Liveness State
应用程序的“活动”状态告诉它,它的内部状态是否允许它正常工作,或者如果它当前出现故障,它是否可以自行恢复。中断的“活跃度”状态意味着应用程序处于无法恢复的状态,基础设施应重新启动应用程序。
In general, the "Liveness" state should not be based on external checks, such as Health checks. If it did, a failing external system (a database, a Web API, an external cache) would trigger massive restarts and cascading failures across the platform. |
Spring Boot应用程序的内部状态主要由SpringApplicationContext
表示。如果应用程序上下文已成功启动,则Spring Boot假定应用程序处于有效状态。一旦上下文被刷新,应用程序就被认为是活动的,请参阅Spring Boot应用程序生命周期和相关应用程序事件。
1.6.2. Readiness State
应用程序的“就绪”状态告知应用程序是否已准备好处理流量。失败的“就绪”状态告诉平台,它暂时不应该将流量路由到应用程序。这通常发生在启动期间、正在处理CommandLineRunner
和ApplicationRunner
组件时,或者在应用程序确定太忙而无法进行额外通信的任何时候。
一旦调用了应用程序和命令行运行程序,就认为应用程序已经就绪,请参阅Spring Boot应用程序生命周期和相关的应用程序事件。
Tasks expected to run during startup should be executed by CommandLineRunner and ApplicationRunner components instead of using Spring component lifecycle callbacks such as @PostConstruct . |
1.6.3. Managing the Application Availability State
通过注入ApplicationAvailability
接口并调用接口上的方法,应用程序组件可以随时检索当前的可用性状态。更常见的情况是,应用程序希望监听状态更新或更新应用程序的状态。
例如,我们可以将应用程序的“就绪”状态导出到一个文件,以便Kubernetes“EXEC探测器”可以查看该文件:
@Component public class MyReadinessStateExporter { @EventListener public void onStateChange(AvailabilityChangeEvent<ReadinessState> event) { switch (event.getState()) { case ACCEPTING_TRAFFIC: // create file /tmp/healthy break; case REFUSING_TRAFFIC: // remove file /tmp/healthy break; } } }
我们还可以在应用程序中断且无法恢复时更新应用程序的状态:
@Component public class MyLocalCacheVerifier { private final ApplicationEventPublisher eventPublisher; public MyLocalCacheVerifier(ApplicationEventPublisher eventPublisher) { this.eventPublisher = eventPublisher; } public void checkLocalCache() { try { // ... } catch (CacheCompletelyBrokenException ex) { AvailabilityChangeEvent.publish(this.eventPublisher, ex, LivenessState.BROKEN); } } }
Spring Boot为Kubernetes HTTP探测器提供了Actuator Health Endpoint的“活跃性”和“就绪性”。有关在Kubernetes上部署Spring Boot应用程序的更多指导,请参阅专用部分。
1.7. Application Events and Listeners
除了通常的Spring框架事件,如ContextRefreshedEvent
,aSpringApplication
还会发送一些额外的应用程序事件。
有些事件实际上是在 如果希望自动注册这些侦听器,而不考虑应用程序的创建方式,则可以将<代码>META-INF/spring.Factory文件添加到您的项目中,并使用 org.springframework.context.ApplicationListener=com.example.project.MyListener |
应用程序运行时,应用程序事件按以下顺序发送:
-
ApplicationStartingEvent
在运行开始时但在任何处理之前发送,侦听器和初始值设定项的注册除外。 -
当知道要在上下文中使用的<
ApplicationEnvironmentPreparedEvent
>环境时,在创建上下文之前发送代码。 -
当准备好<
ApplicationContextInitializedEvent
>ApplicationContext并且调用了ApplicationContextInitializers时,在加载任何Bean定义之前发送一个Bean。 -
ApplicationPreparedEvent
在开始刷新之前但在加载Bean定义之后发送。 -
ApplicationStartedEvent
是在刷新上下文之后、调用任何应用程序和命令行运行程序之前发送的。 -
在
LivenessState.CORRECT
之后发送AvailablityChangeEvent
,以指示该应用程序被视为活动应用程序。 -
在调用了任何应用程序和命令行运行器之后,将发送
ApplicationReadyEvent
。 -
在
ReadinessState.ACCEPTING_TRAFFORM
之后发送AvailablityChangeEvent
,以指示应用程序已准备好为请求提供服务。 -
如果启动时出现异常,则发送
ApplicationFailedEvent
。
以上列表仅包括绑定到SpringApplication
的SpringApplicationEvent
。除此之外,还会在ApplicationPreparedEvent
之后、ApplicationStartedEvent
之前发布以下事件:
-
WebServer
就绪后发送WebServerInitializedEvent
。ServletWebServerInitializedEvent
和ReactiveWebServerInitializedEvent
分别是Servlet和反应型变量。 -
刷新
ApplicationContext
时发送ContextRereshedEvent
。
You often need not use application events, but it can be handy to know that they exist. Internally, Spring Boot uses events to handle a variety of tasks. |
Event listeners should not run potentially lengthy tasks as they execute in the same thread by default. Consider using application and command-line runners instead. |
应用程序事件是通过使用Spring框架的事件发布机制发送的。该机制的一部分确保发布到子上下文中的侦听器的事件也发布到任何祖先上下文中的侦听器。因此,如果您的应用程序使用SpringApplication
实例的层次结构,则侦听器可能会收到同一类型应用程序事件的多个实例。
为了允许侦听器区分其上下文的事件和子代上下文的事件,它应该请求注入其应用程序上下文,然后将注入的上下文与事件的上下文进行比较。可以通过实现ApplicationConextAware
来注入上下文,或者如果监听器是一个Bean,则使用@AuTower
。
1.8. Web Environment
SpringApplication
尝试代表您创建正确类型的ApplicationContext
。确定WebApplicationType
的算法如下:
-
如果存在Spring MVC,则使用
AnnotationConfigServletWebServerApplicationContext
-
如果不存在Spring MVC而存在Spring WebFlux,则使用
AnnotationConfigReactiveWebServerApplicationContext
-
否则,将使用
AnnotationConfigApplicationContext
这意味着如果您在同一个应用程序中使用Spring MVC和来自Spring WebFlux的新的WebClient
,那么默认情况下将使用Spring MVC。您可以通过调用setWebApplicationType(WebApplicationType)
.很容易地覆盖它
还可以完全控制通过调用setApplicationConextClass(…)使用的<代码>应用程序上下文
类型)
。
It is often desirable to call setWebApplicationType(WebApplicationType.NONE) when using SpringApplication within a JUnit test. |
1.9. Accessing Application Arguments
如果需要访问传递给SpringApplication.run(…)的应用程序参数代码)
,您可以注入一个Bean。ApplicationArguments
接口提供对原始字符串[]
参数以及已解析的选项
和非选项
参数的访问,如下例所示:
@Component public class MyBean { public MyBean(ApplicationArguments args) { boolean debug = args.containsOption("debug"); List<String> files = args.getNonOptionArgs(); if (debug) { System.out.println(files); } // if run with "--debug logfile.txt" prints ["logfile.txt"] } }
Spring Boot also registers a CommandLinePropertySource with the Spring Environment . This lets you also inject single application arguments by using the @Value annotation. |
1.10. Using the ApplicationRunner or CommandLineRunner
如果在SpringApplication
启动后需要运行某些特定代码,可以实现ApplicationRunner
或CommandLineRunner
接口。这两个接口以相同的方式工作,并提供单个<代码>Run
方法,该方法在<代码>SpringApplication.run(…)之前调用)完成。
This contract is well suited for tasks that should run after application startup but before it starts accepting traffic. |
CommandLineRunner
接口提供对字符串数组形式的应用程序参数的访问,而ApplicationRunner
接口使用前面讨论的ApplicationArguments
接口。下面的示例显示具有Run
方法的CommandLineRunner
:
@Component public class MyCommandLineRunner implements CommandLineRunner { @Override public void run(String... args) { // Do something... } }
如果定义了几个必须以特定顺序调用的CommandLineRunner
或ApplicationRunner
Bean,则可以另外实现org.springFramework.core.Orded
接口或使用org.springframework.core.annotation.Order
注释。
1.11. Application Exit
每个SpringApplication
都向JVM注册一个关闭挂钩,以确保ApplicationContext
在退出时正常关闭。所有标准的Spring生命周期回调(例如DisposableBean
接口或@PreDestroy
注释)都可以使用。
此外,如果在调用<org.springframework.boot.ExitCodeGenerator
>SpringApplication.it()时希望返回特定的退出代码,Bean可能会实现代码接口。然后,可以将此退出代码传递给System.exit()
,以将其作为状态代码返回,如下例所示:
@SpringBootApplication public class MyApplication { @Bean public ExitCodeGenerator exitCodeGenerator() { return () -> 42; } public static void main(String[] args) { System.exit(SpringApplication.exit(SpringApplication.run(MyApplication.class, args))); } }
此外,ExitCodeGenerator
接口可以由异常实现。当遇到这样的异常时,Spring Boot返回已实现的getExitCode()
方法提供的退出代码。
如果超过ExitCodeGenerator
,则使用生成的第一个非零退出代码。要控制调用生成器的顺序,请另外实现org.springFramework.core.Orded
接口或使用org.springframework.core.annotation.Order
注释。
1.12. Admin Features
可以通过指定spring.Applation.admin.Enabled
属性为应用程序启用与管理相关的功能。这将在平台上公开
SpringApplicationAdminMXBean
>MBeanServer。您可以使用此功能远程管理您的Spring Boot应用程序。此功能对于任何服务包装器实现也很有用。
If you want to know on which HTTP port the application is running, get the property with a key of local.server.port . |
1.13. Application Startup tracking
在应用程序启动期间,SpringApplication
和ApplicationContext
执行许多与应用程序生命周期、Bean生命周期甚至处理应用程序事件相关的任务。通过ApplicationStartup
,Spring框架允许您使用StartupStep
对象跟踪应用程序启动序列。收集这些数据可以用于分析目的,或者只是为了更好地了解应用程序启动过程。
您可以在设置SpringApplication
实例时选择ApplicationStartup
实现。例如,要使用BufferingApplicationStartup
,您可以编写:
@SpringBootApplication public class MyApplication { public static void main(String[] args) { SpringApplication application = new SpringApplication(MyApplication.class); application.setApplicationStartup(new BufferingApplicationStartup(2048)); application.run(args); } }
第一个可用的实现FlightRecorderApplicationStartup
是由Spring框架提供的。它将特定于Spring的启动事件添加到Java飞行记录器会话中,用于分析应用程序并将它们的Spring上下文生命周期与JVM事件(如分配、GC、类加载…)关联起来)。配置后,您可以通过在启用飞行记录器的情况下运行应用程序来记录数据:
$ java -XX:StartFlightRecording:filename=recording.jfr,duration=10s -jar demo.jar
Spring Boot附带了BufferingApplicationStartup
变量;该实现用于缓冲启动步骤并将它们排入外部指标系统。应用程序可以在任何组件中请求BufferingApplicationStartup
类型的Bean。
Spring Boot还可以配置为公开启动
端点,该端点以JSON文档的形式提供此信息。
2. Externalized Configuration
Spring Boot允许您将配置外部化,这样您就可以在不同的环境中使用相同的应用程序代码。您可以使用各种外部配置源,包括Java属性文件、YAML文件、环境变量和命令行参数。
属性值可以通过使用@Value
注释直接注入到您的Bean中,通过Spring的Environment
抽象访问,或者通过@ConfigurationProperties
绑定到结构化对象。
Spring Boot使用了一个非常特殊的PropertySource
顺序,旨在允许合理地重写值。以后的特性源可以替代以前的特性源中定义的值。信息来源按以下顺序考虑:
-
默认属性(通过设置
SpringApplication.setDefaultProperties
).指定 -
@Configuration
类上的@PropertySource
批注。请注意,在刷新应用程序上下文之前,此类属性源不会添加到环境
。这太晚了,无法配置在刷新开始之前读取的某些属性,如Logging.*
和spring.main.*
。 -
配置数据(如
Applation.Properties
文件)。 -
仅在
Ranom.*
中具有属性的RandomValuePropertySource
。 -
操作系统环境变量。
-
Java系统属性(
System.getProperties()
)。 -
来自
Java:comp/env
的JNDI属性。 -
ServletContext
初始化参数。 -
ServletConfig
初始化参数。 -
来自
SPUNG_APPLICATION_JSON
的属性(嵌入在环境变量或系统属性中的内联JSON)。 -
命令行参数。
-
测试上的
属性
属性。在@SpringBootTest
和测试批注上提供,用于测试应用程序的特定片段。
-
当DevTools处于活动状态时,DevTools全局设置属性位于
$HOME/.config/SpringBoot
目录中。
配置数据文件按以下顺序考虑:
-
打包在JAR中的应用程序属性(
应用程序属性
和YAML变量)。 -
特定于配置文件的应用程序属性打包在您的JAR(
application-{profile}.properties
和Yaml变体中)。 -
应用程序属性在打包的JAR之外(
Application.Properties
和YAML变体)。 -
特定于配置文件的应用程序属性在打包的JAR(
application-{profile}.properties
和Yaml变体之外)。
It is recommended to stick with one format for your entire application. If you have configuration files with both .properties and .yml format in the same location, .properties takes precedence. |
为了提供一个具体的示例,假设您开发了一个使用name
属性的@Component
,如下例所示:
@Component public class MyBean { @Value("${name}") private String name; // ... }
在您的应用程序类路径上(例如,在您的JAR中),您可以拥有一个为name
提供合理的默认属性值的Application.Properties
文件。当在新环境中运行时,可以在您的JAR外部提供一个覆盖名称
的Application.Properties
文件。对于一次性测试,您可以使用特定的命令行开关(例如,Java-jar app.jar--name=“Spring”
)启动。
The env and configprops endpoints can be useful in determining why a property has a particular value. You can use these two endpoints to diagnose unexpected property values. See the "Production ready features" section for details. |
2.1. Accessing Command Line Properties
默认情况下,SpringApplication
将任何命令行选项参数(即以--
开头的参数,如--server.port=9000
)转换为属性
,并将它们添加到Spring环境
。如前所述,命令行特性始终优先于基于文件的特性源。
如果不希望将命令行属性添加到环境
,可以使用SpringApplication.setAddCommandLineProperties(false)
.禁用它们
2.2. JSON Application Properties
环境变量和系统属性通常有一些限制,这意味着某些属性名称不能使用。为了帮助实现这一点,Spring Boot允许您将属性块编码到单个JSON结构中。
当您的应用程序启动时,任何spring.applation.json
或Spring_APPLICATION_JSON
属性都将被解析并添加到Environment
。
例如,SPUNG_APPLICATION_JSON
属性可以作为环境变量在UN*X外壳的命令行中提供:
$ SPRING_APPLICATION_JSON='{"my":{"name":"test"}}' java -jar myapp.jar
在前面的示例中,您在SpringEnvironment
中得到了my.name=test
。
同样的JSON也可以作为系统属性提供:
$ java -Dspring.application.json='{"my":{"name":"test"}}' -jar myapp.jar
或者,您可以使用命令行参数提供JSON:
$ java -jar myapp.jar --spring.application.json='{"my":{"name":"test"}}'
如果要部署到标准应用程序服务器,还可以使用名为java:comp/env/spring.application.json
.的jndi变量
Although null values from the JSON will be added to the resulting property source, the PropertySourcesPropertyResolver treats null properties as missing values. This means that the JSON cannot override properties from lower order property sources with a null value. |
2.3. External Application Properties
当您的应用程序启动时,Spring Boot将自动从以下位置查找并加载Application.Properties
和Applation.yaml
文件:
-
从类路径
-
类路径根
-
类路径
/config
包
-
-
从当前目录
-
当前目录
-
当前目录中的
config/
子目录 -
config/
子目录的直接子目录
-
该列表按优先级排序(较低项的值优先于较早项的值)。加载文件中的文档将作为PropertySources
添加到Spring环境
。
如果您不喜欢应用程序
作为配置文件名,可以通过指定spring.config.name
环境属性切换到另一个文件名。例如,要查找myproject t.properties
和myproject t.yaml
文件,您可以按如下方式运行应用程序:
$ java -jar myproject.jar --spring.config.name=myproject
您还可以通过使用spring.config.Location
环境属性来引用显式位置。此属性接受要检查的一个或多个位置的逗号分隔列表。
以下示例显示如何指定两个不同的文件:
$ java -jar myproject.jar --spring.config.location=\ optional:classpath:/default.properties,\ optional:classpath:/override.properties
Use the prefix optional: if the locations are optional and you do not mind if they do not exist. |
spring.config.name , spring.config.location , and spring.config.additional-location are used very early to determine which files have to be loaded. They must be defined as an environment property (typically an OS environment variable, a system property, or a command-line argument). |
如果spring.config.Location
包含目录(而不是文件),则它们应该以/
结尾。在运行时,它们将在加载之前附加由spring.config.name
生成的名称。直接导入在spring.config.Location
中指定的文件。
Both directory and file location values are also expanded to check for profile-specific files. For example, if you have a spring.config.location of classpath:myconfig.properties , you will also find appropriate classpath:myconfig-<profile>.properties files are loaded. |
在大多数情况下,您添加的每个spring.config.Location
项都将引用单个文件或目录。位置按照定义的顺序进行处理,较晚的位置可以覆盖较早位置的值。
如果您有一个复杂的位置设置,并且您使用特定于配置文件的配置文件,那么您可能需要提供进一步的提示,以便Spring Boot知道应该如何对它们进行分组。位置组是所有被视为同一级别的位置的集合。例如,您可能希望对所有类路径位置进行分组,然后对所有外部位置进行分组。位置组中的项目应使用;
分隔。有关更多详细信息,请参阅“配置文件特定文件部分中的示例。
使用spring.config.Location
配置的位置替换默认位置。例如,如果使用值配置
,则考虑的完整位置集为:spring.config.Location
:可选:classpath:/Custom-config/,可选:file:./Custom-config/
-
optional:classpath:custom-config/
-
可选:文件:./定制配置/
如果您更喜欢添加其他位置,而不是替换它们,则可以使用spring.config.additional-location
.从其他位置加载的特性可以覆盖默认位置中的特性。例如,如果使用值<spring.config.additional-location
>配置:类路径:/自定义配置/,可选:文件:./自定义配置/
,则考虑的完整位置集为:
-
optional:classpath:/;optional:classpath:/config/
-
optional:file:./;optional:file:./config/;optional:file:./config/*/
-
optional:classpath:custom-config/
-
可选:文件:./定制配置/
这种搜索顺序允许您在一个配置文件中指定默认值,然后有选择地覆盖另一个配置文件中的这些值。您可以在其中一个默认位置的Application.Properties
(或使用spring.config.name
选择的任何其他基本名称)中为您的应用程序提供默认值。然后,可以在运行时使用位于其中一个自定义位置的不同文件覆盖这些缺省值。
If you use environment variables rather than system properties, most operating systems disallow period-separated key names, but you can use underscores instead (for example, SPRING_CONFIG_NAME instead of spring.config.name ). See Binding From Environment Variables for details. |
If your application runs in a servlet container or application server, then JNDI properties (in java:comp/env ) or servlet context initialization parameters can be used instead of, or as well as, environment variables or system properties. |
2.3.1. Optional Locations
默认情况下,当指定的配置数据位置不存在时,Spring Boot将抛出一个ConfigDataLocationNotFoundException
,并且您的应用程序不会启动。
如果您想指定一个位置,但不介意它不总是存在,您可以使用可选:
前缀。您可以将该前缀与spring.config.Location
spring.config.additional-location
>和href=“0”>spring.config.import
属性一起使用,也可以与
例如,<optional:file:./myconfig.properties
>的spring.config.import
值允许应用程序启动,即使myconfig.properties
文件丢失也是如此。
如果您希望忽略所有代码并始终继续启动您的应用程序,您可以使用<ConfigDataLocationNotFoundExceptions
>spring.config.on-Not-Found属性。使用SpringApplication.setDefaultProperties(…将该值设置为<代码>忽略
)
或使用系统/环境变量。
2.3.2. Wildcard Locations
如果配置文件位置包含最后一个路径段的*
字符,则将其视为通配符位置。加载配置时会展开通配符,以便也会检查直接子目录。当存在多个配置属性源时,通配符位置在Kubernetes等环境中特别有用。
例如,如果您有一些Redis配置和一些MySQL配置,您可能希望将这两部分配置分开,同时要求这两部分都存在于一个Application.Properties
文件中。这可能会导致两个单独的应用程序属性
文件安装在不同的位置,如/config/redis/application.properties
和/config/mysql/application.properties
.在这种情况下,通配符位置为config/*/
将导致处理这两个文件。
默认情况下,Spring Boot在默认搜索位置包含config/*/
。这意味着将搜索JAR之外的/config
目录的所有子目录。
您可以通过spring.config.Location
和spring.config.additional-location
属性自己使用通配符位置。
A wildcard location must contain only one * and end with */ for search locations that are directories or */<filename> for search locations that are files. Locations with wildcards are sorted alphabetically based on the absolute path of the file names. |
Wildcard locations only work with external directories. You cannot use a wildcard in a classpath: location. |
2.3.3. Profile Specific Files
除了应用程序
属性文件,Spring Boot还将尝试使用命名约定应用程序-{配置文件}
加载特定于配置文件的文件。例如,如果您的应用程序激活了一个名为prod
的配置文件并使用YAML文件,那么Application.yml
和application-prod.yml
都将被考虑。
特定于配置文件的属性从与标准应用程序相同的位置加载。属性
,特定于配置文件的文件总是覆盖非特定的文件。如果指定了多个配置文件,则应用最后获胜策略。例如,如果配置文件prod、live
由spring.profiles.active
属性指定,则application-prod.properties
中的值可以被application-live.properties
中的值覆盖。
例如,继续上面的 /cfg application-live.properties /ext application-live.properties application-prod.properties 当我们有
当我们使用
|
Environment
有一组默认配置文件(默认情况下为[Default]
),如果未设置活动配置文件,则使用这些配置文件。换句话说,如果没有显式激活配置文件,则考虑来自应用程序默认
的属性。
Properties files are only ever loaded once. If you have already directly imported a profile specific property files then it will not be imported a second time. |
2.3.4. Importing Additional Data
应用程序属性可以使用spring.config.import
属性从其他位置导入进一步的配置数据。在发现导入时对其进行处理,并将其视为紧接在声明导入的文档下面插入的附加文档。
例如,您的类路径应用程序属性
文件中可能包含以下内容:
spring.application.name=myapp
spring.config.import=optional:file:./dev.properties
这将触发导入当前目录中的dev.properties
文件(如果存在这样的文件)。来自导入的dev.Properties
的值将优先于触发导入的文件。在上面的示例中,dev.properties
可以将spring.Applation.name
重新定义为不同的值。
无论申报多少次,导入都只会导入一次。在属性/YAML文件中的单个文档中定义导入的顺序并不重要。例如,下面的两个示例产生相同的结果:
spring.config.import=my.properties
my.property=value
my.property=value
spring.config.import=my.properties
在上述两个示例中,来自my.properties
文件的值将优先于触发其导入的文件。
可以在单个spring.config.import
项下指定多个位置。将按照定义的顺序处理位置,以后的导入优先。
When appropriate, Profile-specific variants are also considered for import. The example above would import both my.properties as well as any my-<profile>.properties variants. |
Spring Boot包括可插拔的API,允许支持各种不同的位置地址。默认情况下,您可以导入Java Properties、YAML和“配置树。 第三方JAR可以提供对其他技术的支持(不要求文件必须是本地的)。例如,您可以想象配置数据来自外部存储,如Consul、ApacheZooKeeper或Netflix Archaius。 如果您希望支持您自己的位置,请参见 |
2.3.5. Importing Extensionless Files
有些云平台无法为卷装载文件添加文件扩展名。要导入这些无扩展文件,您需要给Spring Boot一个提示,以便它知道如何加载它们。您可以通过将扩展提示放在方括号中来完成此操作。
例如,假设您有一个希望作为YAML导入的/etc/config/myconfig
文件。您可以使用以下内容从应用程序
导入它:
spring.config.import=file:/etc/config/myconfig[.yaml]
2.3.6. Using Configuration Trees
在云平台(如Kubernetes)上运行应用程序时,您经常需要读取平台提供的配置值。将环境变量用于此类目的并不少见,但这样做可能会有缺点,特别是在应该对值保密的情况下。
作为环境变量的替代方案,许多云平台现在允许您将配置映射到已装载的数据卷。例如,Kubernetes可以卷装载ConfigMaps
和
秘密
。
可以使用两种常见的卷装载模式:
-
一个文件包含一组完整的属性(通常写为YAML)。
-
多个文件被写入目录树,其中文件名成为“关键字”,内容成为“值”。
对于第一种情况,您可以使用上述中描述的spring.config.import
直接导入YAML或Properties文件。对于第二种情况,您需要使用configtree:
前缀,以便Spring Boot知道它需要将所有文件公开为属性。
例如,假设Kubernetes挂载了以下卷:
etc/ config/ myapp/ username password
用户名
文件的内容将是配置值,而密码
的内容将是机密。
要导入这些属性,您可以将以下内容添加到Application.Properties
或Application.yaml
文件中:
spring.config.import=optional:configtree:/etc/config/
然后,您可以按照通常的方式从Environment
访问或注入myapp.username
和myapp.password
属性。
The folders under the config tree form the property name. In the above example, to access the properties as username and password , you can set spring.config.import to optional:configtree:/etc/config/myapp . |
Filenames with dot notation are also correctly mapped. For example, in the above example, a file named myapp.username in /etc/config would result in a myapp.username property in the Environment . |
Configuration tree values can be bound to both string String and byte[] types depending on the contents expected. |
如果要从同一父文件夹导入多个配置树,则可以使用通配符快捷方式。任何以/*/
结尾的configtree:
位置都会将所有直接子对象作为配置树导入。
例如,给定以下卷:
etc/ config/ dbconfig/ db/ username password mqconfig/ mq/ username password
您可以使用configtree:/etc/config/*/
作为导入位置:
spring.config.import=optional:configtree:/etc/config/*/
这将添加db.username
、db.password
、mq.username
和mq.password
属性。
Directories loaded using a wildcard are sorted alphabetically. If you need a different order, then you should list each location as a separate import |
配置树也可以用于Docker机密。当Docker群服务被授予访问秘密的权限时,该秘密被装载到容器中。例如,如果将名为db.password
的密码挂载在/run/secrets/
位置,则可以使用以下命令使db.password
可用于Spring环境:
spring.config.import=optional:configtree:/run/secrets/
2.3.7. Property Placeholders
Applation.Properties
和Applation.yml
中的值在使用时会通过现有的Environment
进行筛选,因此您可以引用以前定义的值(例如,从系统属性或环境变量)。标准${name}
属性占位符语法可以在值内的任何位置使用。属性占位符还可以使用:
指定默认值,以将默认值与属性名称分开,例如${name:Default}
。
下例显示了带有和不带有默认值的占位符的用法:
app.name=MyApp
app.description=${app.name} is a Spring Boot application written by ${username:Unknown}
假设用户名
属性没有在其他地方设置,app.Description
的值将是MyApp是由未知的
编写的Spring Boot应用程序。
您应该始终使用占位符中的属性名称的规范形式(仅使用小写字母的烤肉串大小写)来引用属性名称。这将允许Spring Boot使用与松散绑定 例如, |
You can also use this technique to create “short” variants of existing Spring Boot properties. See the howto.html how-to for details. |
2.3.8. Working With Multi-Document Files
Spring Boot允许您将单个物理文件拆分成多个逻辑文档,每个逻辑文档都是独立添加的。文件是按照从上到下的顺序处理的。以后的文档可以覆盖以前的文档中定义的属性。
对于applation.yml
文件,使用标准的YAML多文档语法。三个连续的连字符表示一个文档的结束,以及下一个文档的开始。
例如,下面的文件有两个逻辑文档:
spring:
application:
name: "MyApp"
---
spring:
application:
name: "MyCloudApp"
config:
activate:
on-cloud-platform: "kubernetes"
对于Applation.Properties
文件,使用特殊的#-
或!-
注释来标记文档拆分:
spring.application.name=MyApp
#---
spring.application.name=MyCloudApp
spring.config.activate.on-cloud-platform=kubernetes
Property file separators must not have any leading whitespace and must have exactly three hyphen characters. The lines immediately before and after the separator must not be same comment prefix. |
Multi-document property files are often used in conjunction with activation properties such as spring.config.activate.on-profile . See the next section for details. |
Multi-document property files cannot be loaded by using the @PropertySource or @TestPropertySource annotations. |
2.3.9. Activation Properties
有时,仅在满足某些条件时激活一组给定的属性非常有用。例如,您可能具有仅在特定配置文件处于活动状态时才相关的属性。
您可以有条件地使用spring.config.active.*
来激活属性文档。
以下激活属性可用:
Property | Note |
---|---|
|
文档必须匹配才能处于活动状态的配置文件表达式。 |
|
必须检测到的 |
例如,下面的代码指定第二个文档仅当在Kubernetes上运行时才处于活动状态,并且仅当“Prod”或“Staging”配置文件处于活动状态时才处于活动状态:
myprop=always-set
#---
spring.config.activate.on-cloud-platform=kubernetes
spring.config.activate.on-profile=prod | staging
myotherprop=sometimes-set
2.4. Encrypting Properties
Spring Boot没有为加密属性值提供任何内置支持,但是,它确实提供了修改SpringEnvironment
中包含的值所需的钩点。Environment PostProcessor
接口允许您在应用程序启动之前操作Environment
。有关详细信息,请参阅howto.html。
如果您需要一种安全的方式来存储凭据和密码,Spring Cloud文件库项目支持在HashiCorp文件库中存储外部化配置。
2.5. Working With YAML
If you use “Starters”, SnakeYAML is automatically provided by spring-boot-starter . |
2.5.1. Mapping YAML to Properties
需要将YAML文档从其分层格式转换为可与Spring环境
一起使用的平面结构。例如,考虑以下YAML文档:
environments:
dev:
url: "https://dev.example.com"
name: "Developer Setup"
prod:
url: "https://another.example.com"
name: "My Cool App"
为了从环境
访问这些属性,它们将按如下方式展开:
environments.dev.url=https://dev.example.com
environments.dev.name=Developer Setup
environments.prod.url=https://another.example.com
environments.prod.name=My Cool App
同样,YAML列表也需要扁平化。它们被表示为带有[index]
取消引用的属性键。例如,考虑以下YAML:
my:
servers:
- "dev.example.com"
- "another.example.com"
前面的示例将转换为以下属性:
my.servers[0]=dev.example.com
my.servers[1]=another.example.com
Properties that use the [index] notation can be bound to Java List or Set objects using Spring Boot’s Binder class. For more details see the “Type-safe Configuration Properties” section below. |
YAML files cannot be loaded by using the @PropertySource or @TestPropertySource annotations. So, in the case that you need to load values that way, you need to use a properties file. |
2.6. Configuring Random Values
RandomValuePropertySource
对于注入随机值(例如,注入机密或测试用例)很有用。它可以生成整数、长整型、uuid或字符串,如下例所示:
my.secret=${random.value}
my.number=${random.int}
my.bignumber=${random.long}
my.uuid=${random.uuid}
my.number-less-than-ten=${random.int(10)}
my.number-in-range=${random.int[1024,65536]}
语法是OPEN VALUE(,max)CLOSE
,其中OPEN,CLOSE
是任意字符,VALUE,MAX
是整数。如果提供了max
,则值
是最小值,max
是最大值(独占)。
2.7. Configuring System Environment Properties
Spring Boot支持为环境属性设置前缀。如果系统环境由多个具有不同配置要求的Spring Boot应用程序共享,这将非常有用。可以在SpringApplication
上直接设置系统环境属性的前缀。
例如,如果将前缀设置为输入
,则在系统环境中,诸如emote.timeout
之类的属性也将被解析为input.emote.timeout
。
2.8. Type-safe Configuration Properties
使用@Value(“${Property}”)
注释注入配置属性有时可能很麻烦,尤其是在您使用多个属性或数据本质上是分层的情况下。Spring Boot提供了另一种处理属性的方法,该方法允许强类型的Bean管理和验证应用程序的配置。
2.8.1. JavaBean Properties Binding
可以绑定声明标准JavaBean属性的Bean,如下例所示:
@ConfigurationProperties("my.service") public class MyProperties { private boolean enabled; private InetAddress remoteAddress; private final Security security = new Security(); public static class Security { private String username; private String password; private List<String> roles = new ArrayList<>(Collections.singleton("USER")); } }
前面的POJO定义了以下属性:
-
my.service.Enabled
,默认为False
。 -
my.service.Remote-Address
,其类型可以从字符串
强制。 -
my.service.security.username
,具有嵌套的“Security”对象,其名称由属性的名称确定。特别是,那里根本没有使用该类型,并且可能是SecurityProperties
。 -
my.service.security.password
。 -
my.service.security.Roles
,其中字符串
集合默认为用户
。
The properties that map to @ConfigurationProperties classes available in Spring Boot, which are configured through properties files, YAML files, environment variables, and other mechanisms, are public API but the accessors (getters/setters) of the class itself are not meant to be used directly. |
这种安排依赖于缺省的空构造函数,而getter和setter通常是强制的,因为绑定是通过标准的Java Beans属性描述符进行的,就像在Spring MVC中一样。在下列情况下,可以省略定位器:
有些人使用Project Lombok自动添加getter和setter。确保Lombok不会为这种类型生成任何特定的构造函数,因为容器会自动使用它来实例化对象。 最后,只考虑标准的Java Bean属性,不支持绑定静态属性。 |
2.8.2. Constructor Binding
上一节中的示例可以以不变的方式重写,如下例所示:
@ConfigurationProperties("my.service") public class MyProperties { public MyProperties(boolean enabled, InetAddress remoteAddress, Security security) { this.enabled = enabled; this.remoteAddress = remoteAddress; this.security = security; } public static class Security { public Security(String username, String password, @DefaultValue("USER") List<String> roles) { this.username = username; this.password = password; this.roles = roles; } } }
在此设置中,单个参数化构造器的存在意味着应该使用构造器绑定。这意味着绑定器将找到一个具有您希望绑定的参数的构造函数。如果您的类有多个构造函数,@ConstructorBinding
注释可用于指定用于构造函数绑定的构造函数。要为具有单个参数化构造器的类选择不绑定构造器,构造器必须用@Autwire
注释。如果您使用的是Java 16或更高版本,则可以对记录使用构造函数绑定。除非您的记录有多个构造函数,否则不需要使用@ConstructorBinding
。
构造函数绑定类的嵌套成员(如上面示例中的Security
)也将通过它们的构造函数进行绑定。
可以在构造函数参数和记录组件上使用@DefaultValue
指定默认值。将应用转换服务将批注的字符串
值强制为缺少属性的目标类型。
参考前面的示例,如果没有属性绑定到Security
,MyProperties
实例将包含安全性
的空
值。要使其包含Security
的非空实例,即使在没有绑定任何属性的情况下(使用Kotlin时,这将要求将Security
的用户名
和密码
参数声明为可以为空,因为它们没有默认值),请使用空的@DefaultValue
批注:
public MyProperties(boolean enabled, InetAddress remoteAddress, @DefaultValue Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
To use constructor binding the class must be enabled using @EnableConfigurationProperties or configuration property scanning. You cannot use constructor binding with beans that are created by the regular Spring mechanisms (for example @Component beans, beans created by using @Bean methods or beans loaded by using @Import ) |
To use constructor binding in a native image the class must be compiled with -parameters . This will happen automatically if you use Spring Boot’s Gradle plugin or if you use Maven and spring-boot-starter-parent . |
The use of java.util.Optional with @ConfigurationProperties is not recommended as it is primarily intended for use as a return type. As such, it is not well-suited to configuration property injection. For consistency with properties of other types, if you do declare an Optional property and it has no value, null rather than an empty Optional will be bound. |
2.8.3. Enabling @ConfigurationProperties-annotated Types
Spring Boot提供了绑定@ConfigurationProperties
类型并将它们注册为Bean的基础设施。您可以逐个类地启用配置属性,也可以启用与组件扫描类似的配置属性扫描。
有时,使用@ConfigurationProperties
注释的类可能不适合扫描,例如,如果您正在开发自己的自动配置或希望有条件地启用它们。在这些情况下,使用@EnableConfigurationProperties
注释指定要处理的类型列表。这可以在任何@Configuration
类上完成,如下例所示:
@Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(SomeProperties.class) public class MyConfiguration { }
要使用配置属性扫描,请将@ConfigurationPropertiesScan
批注添加到您的应用程序。通常,它被添加到用@SpringBootApplication
注释的主应用程序类中,但也可以添加到任何@Configuration
类中。默认情况下,扫描将从声明注释的类的包进行。如果要定义要扫描的特定程序包,可以执行以下示例所示的操作:
@SpringBootApplication @ConfigurationPropertiesScan({ "com.example.app", "com.example.another" }) public class MyApplication { }
当使用配置属性扫描或通过 上例中的Bean名称为 |
我们建议@ConfigurationProperties
只处理环境,特别是不要从上下文注入其他Bean。对于特殊情况,可以使用setter注入,也可以使用框架提供的任何*Aware
接口(如果需要访问Environment
,则可以使用Environment Aware
)。如果您仍然希望使用构造函数注入其他Bean,则配置属性Bean必须使用@Component
进行注释,并使用基于Java Bean的属性绑定。
2.8.4. Using @ConfigurationProperties-annotated Types
这种配置风格特别适用于SpringApplication
外部YAML配置,如下例所示:
my:
service:
remote-address: 192.168.1.1
security:
username: "admin"
roles:
- "USER"
- "ADMIN"
要使用@ConfigurationProperties
Bean,您可以像注入任何其他Bean一样注入它们,如下例所示:
@Service public class MyService { private final MyProperties properties; public MyService(MyProperties properties) { this.properties = properties; } public void openConnection() { Server server = new Server(this.properties.getRemoteAddress()); server.start(); // ... } // ... }
Using @ConfigurationProperties also lets you generate metadata files that can be used by IDEs to offer auto-completion for your own keys. See the appendix for details. |
2.8.5. Third-party Configuration
除了使用@ConfigurationProperties
注释类之外,您还可以在公共@Bean
方法上使用它。当您想要将属性绑定到您无法控制的第三方组件时,这样做可能特别有用。
要从Environment
属性配置Bean,请将@ConfigurationProperties
添加到其Bean注册中,如下例所示:
@Configuration(proxyBeanMethods = false) public class ThirdPartyConfiguration { @Bean @ConfigurationProperties(prefix = "another") public AnotherComponent anotherComponent() { return new AnotherComponent(); } }
用另一个
前缀定义的任何JavaBean属性都映射到那个AnotherComponent
Bean上,其方式类似于前面的SomeProperties
示例。
2.8.6. Relaxed Binding
Spring Boot使用一些宽松的规则将Environment
属性绑定到@ConfigurationProperties
Bean,因此Environment
属性名称和Bean属性名称之间不需要完全匹配。这很有用的常见示例包括以破折号分隔的环境属性(例如,上下文路径
绑定到上下文路径
)和大写环境属性(例如,端口
绑定到端口
)。
例如,考虑以下@ConfigurationProperties
类:
@ConfigurationProperties(prefix = "my.main-project.person") public class MyPersonProperties { private String firstName; public String getFirstName() { return this.firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } }
在前面的代码中,可以使用以下属性名称:
Property | Note |
---|---|
|
烤肉串大小写,建议在 |
|
标准的驼峰大小写语法。 |
|
下划线表示法,这是在 |
|
大写格式,使用系统环境变量时建议使用。 |
The prefix value for the annotation must be in kebab case (lowercase and separated by - , such as my.main-project.person ). |
Property Source | Simple | List |
---|---|---|
属性文件 |
驼色大小写、烤肉串大小写或下划线记法 |
使用 |
YAML文件 |
驼色大小写、烤肉串大小写或下划线记法 |
标准YAML列表语法或逗号分隔值 |
环境变量 |
以下划线为分隔符的大写格式(请参阅从环境变量绑定)。 |
用下划线括起来的数值(请参阅从环境变量绑定) |
系统属性 |
驼色大小写、烤肉串大小写或下划线记法 |
使用 |
We recommend that, when possible, properties are stored in lower-case kebab format, such as my.person.first-name=Rod . |
Binding Maps
绑定到Map
属性时,可能需要使用特殊的括号表示法,以便保留原始的键
值。如果键没有被[]
括起来,则删除所有不是字母数字、-
或.
的字符。
例如,考虑将以下属性绑定到Map<;字符串
:
my.map.[/key1]=value1
my.map.[/key2]=value2
my.map./key3=value3
For YAML files, the brackets need to be surrounded by quotes for the keys to be parsed properly. |
上面的属性将绑定到映射
,其中/key1
、/key2
和key3
作为映射中的键。已从key3
中删除斜杠,因为它没有用方括号括起来。
绑定到标量值时,其中包含.
的键不需要用[]
括起来。标量值包括枚举和java.lang
包中除对象
之外的所有类型。将a.b=c
绑定到Map<;字符串&>
将保留键中的.
,并返回带有条目{“A.B”=“c”}
的Map。对于任何其他类型,如果键
包含.
,则需要使用方括号表示法。例如,将a.b=c
绑定到Map<;字符串,对象&>
将返回条目{“a”={“b”=“c”}}
的Map,而[A.B]=c
将返回条目{“A.B”=“c”}
的Map。
Binding From Environment Variables
大多数操作系统对可用于环境变量的名称实施了严格的规则。例如,Linux外壳变量只能包含字母(a
到z
或A
到Z
)、数字(0
到9
)或下划线字符(_
)。按照惯例,Unix外壳变量的名称也是大写的。
Spring Boot松散的绑定规则尽可能地设计为与这些命名限制兼容。
要将规范格式的属性名称转换为环境变量名称,可以遵循以下规则:
-
将点(
.
)替换为下划线(_
)。 -
删除所有破折号(
-
)。 -
转换为大写。
例如,配置属性spring.main.log-startup-info
将是一个名为Spring_main_LOGSTARTUPINFO
的环境变量。
绑定到对象列表时也可以使用环境变量。若要绑定到列表
,应在变量名中用下划线将元素编号括起来。
例如,配置属性my.service[0].Other
将使用名为MY_SERVICE_0_OTHER
的环境变量。
2.8.7. Merging Complex Types
当在多个位置配置列表时,覆盖的工作方式是替换整个列表。
例如,假定MyPojo
对象的名称
和描述
属性在默认情况下为空
。下面的示例公开MyProperties
中的MyPojo
对象的列表:
@ConfigurationProperties("my") public class MyProperties { private final List<MyPojo> list = new ArrayList<>(); public List<MyPojo> getList() { return this.list; } }
请考虑以下配置:
my.list[0].name=my name
my.list[0].description=my description
#---
spring.config.activate.on-profile=dev
my.list[0].name=my another name
如果dev
配置文件处于非活动状态,则MyProperties.list
包含一个MyPojo
条目,如前所述。但是,如果启用了dev
配置文件,列表
仍然仅包含一个条目(名称为My Another Name
,描述为NULL
)。此配置不会将第二个MyPojo
实例添加到列表中,也不会合并这些项。
当在多个配置文件中指定列表
时,将使用具有最高优先级的配置文件(且仅使用该配置文件)。请考虑以下示例:
my.list[0].name=my name
my.list[0].description=my description
my.list[1].name=another name
my.list[1].description=another description
#---
spring.config.activate.on-profile=dev
my.list[0].name=my another name
在前面的示例中,如果dev
配置文件处于活动状态,则MyProperties.list
包含一个MyPojo
条目(名称为My Another Name
,描述为NULL
)。对于YAML,逗号分隔的列表和YAML列表都可以用于完全覆盖列表的内容。
对于Map
属性,您可以绑定从多个来源提取的属性值。但是,对于多个源中的同一属性,将使用具有最高优先级的属性。下面的示例公开MyProperties
中的Map<;字符串MyPojo&>
:
@ConfigurationProperties("my") public class MyProperties { private final Map<String, MyPojo> map = new LinkedHashMap<>(); public Map<String, MyPojo> getMap() { return this.map; } }
请考虑以下配置:
my.map.key1.name=my name 1
my.map.key1.description=my description 1
#---
spring.config.activate.on-profile=dev
my.map.key1.name=dev name 1
my.map.key2.name=dev name 2
my.map.key2.description=dev description 2
如果dev
配置文件处于非活动状态,则MyProperties.map
包含一个键为key1
的条目(名称为My Name 1
,描述为My Description 1
)。但是,如果启用了dev
配置文件,map
将包含两个条目,其中键key1
(名称为dev name 1
,描述为My Description 1
)和key2
(名称为dev name 2
,描述为dev Description 2
)。
The preceding merging rules apply to properties from all property sources, and not just files. |
2.8.8. Properties Conversion
当Spring Boot绑定到@ConfigurationProperties
Bean时,它试图将外部应用程序属性强制为正确的类型。如果您需要自定义类型转换,您可以提供ConversionService
Bean(具有名为ConversionService
的Bean)或自定义属性编辑器(通过CustomEditorConfigurer
Bean)或自定义Converters
(将Bean定义注释为@ConfigurationPropertiesBinding
).
As this bean is requested very early during the application lifecycle, make sure to limit the dependencies that your ConversionService is using. Typically, any dependency that you require may not be fully initialized at creation time. You may want to rename your custom ConversionService if it is not required for configuration keys coercion and only rely on custom converters qualified with @ConfigurationPropertiesBinding . |
Converting Durations
Spring Boot专门支持表示持续时间。如果您公开java.time.Duration
属性,则应用程序属性中的以下格式可用:
-
常规
长
表示形式(使用毫秒作为默认单位,除非已指定@DurationUnit
) -
由使用的标准ISO-8601格式
-
将值和单位耦合在一起的更易读的格式(
10s
表示10秒)
请考虑以下示例:
@ConfigurationProperties("my") public class MyProperties { @DurationUnit(ChronoUnit.SECONDS) private Duration sessionTimeout = Duration.ofSeconds(30); private Duration readTimeout = Duration.ofMillis(1000); }
要将会话超时指定为30秒,30
、PT30S
和30s
都是等效的。读取超时500ms可以指定为以下任何形式:500
、PT0.5S
和500ms
。
您也可以使用任何受支持的单位。它们是:
-
ns
,表示纳秒 -
us
微秒 -
ms
表示毫秒 -
%s
秒数 -
m
分钟 -
h
小时 -
d
天数
默认单位为毫秒,可以使用@DurationUnit
覆盖,如上面的示例所示。
如果您更喜欢使用构造函数绑定,则可以公开相同的属性,如下例所示:
@ConfigurationProperties("my") public class MyProperties { public MyProperties(@DurationUnit(ChronoUnit.SECONDS) @DefaultValue("30s") Duration sessionTimeout, @DefaultValue("1000ms") Duration readTimeout) { this.sessionTimeout = sessionTimeout; this.readTimeout = readTimeout; } }
If you are upgrading a Long property, make sure to define the unit (using @DurationUnit ) if it is not milliseconds. Doing so gives a transparent upgrade path while supporting a much richer format. |
Converting Periods
除了持续时间,Spring Boot还可以使用java.time.Period
类型。可以在应用程序属性中使用以下格式:
-
常规的
int
表示形式(使用天数作为默认单位,除非已指定@PerioUnit
) -
Java.time.Period使用的标准ISO-8601格式
-
将值和单位对耦合在一起的更简单的格式(
1y3d
表示1年零3天)
SIMPLE格式支持以下单位:
-
y
多年 -
m
几个月 -
w
数周 -
d
天数
The java.time.Period type never actually stores the number of weeks, it is a shortcut that means “7 days”. |
Converting Data Sizes
Spring框架具有以字节表示大小的DataSize
值类型。如果公开DataSize
属性,则应用程序属性中的以下格式可用:
-
常规
长
表示形式(使用字节作为默认单位,除非已指定@DataSizeUnit
) -
将值和单位耦合在一起的可读性更强的格式(
10MB
表示10MB)
请考虑以下示例:
@ConfigurationProperties("my") public class MyProperties { @DataSizeUnit(DataUnit.MEGABYTES) private DataSize bufferSize = DataSize.ofMegabytes(2); private DataSize sizeThreshold = DataSize.ofBytes(512); }
若要将缓冲区大小指定为10MB,10
和10MB
是等效的。256字节的大小阈值可以指定为256
或256B
。
您也可以使用任何受支持的单位。它们是:
-
B
表示字节 -
KB
(千字节) -
MB
表示MB -
GB
表示GB -
TB
表示TB
默认单位是字节,可以使用@DataSizeUnit
覆盖,如上面的示例所示。
如果您更喜欢使用构造函数绑定,则可以公开相同的属性,如下例所示:
@ConfigurationProperties("my") public class MyProperties { public MyProperties(@DataSizeUnit(DataUnit.MEGABYTES) @DefaultValue("2MB") DataSize bufferSize, @DefaultValue("512B") DataSize sizeThreshold) { this.bufferSize = bufferSize; this.sizeThreshold = sizeThreshold; } }
If you are upgrading a Long property, make sure to define the unit (using @DataSizeUnit ) if it is not bytes. Doing so gives a transparent upgrade path while supporting a much richer format. |
2.8.9. @ConfigurationProperties Validation
只要用Spring的@valated
批注来批注类,Spring Boot就会尝试验证@ConfigurationProperties
类。您可以直接在配置类上使用JSR-303javax.valify
约束批注。为此,请确保类路径上存在兼容的JSR-303实现,然后向字段添加约束注释,如下例所示:
@ConfigurationProperties("my.service") @Validated public class MyProperties { @NotNull private InetAddress remoteAddress; }
You can also trigger validation by annotating the @Bean method that creates the configuration properties with @Validated . |
为了确保始终触发对嵌套属性的验证,即使没有找到任何属性,关联的字段也必须使用@Valid
进行注释。下面的示例基于前面的MyProperties
示例:
@ConfigurationProperties("my.service") @Validated public class MyProperties { @NotNull private InetAddress remoteAddress; @Valid private final Security security = new Security(); public static class Security { @NotEmpty private String username; } }
您还可以通过创建名为configurationPropertiesValidator
.的Bean定义来添加自定义Spring<代码>验证器
@Bean
方法应声明为静态
。配置属性验证器是在应用程序生命周期的早期创建的,如果将@Bean
方法声明为静态方法,则无需实例化@Configuration
类即可创建Bean。这样做可以避免早期实例化可能导致的任何问题。
The spring-boot-actuator module includes an endpoint that exposes all @ConfigurationProperties beans. Point your web browser to /actuator/configprops or use the equivalent JMX endpoint. See the "Production ready features" section for details. |
2.8.10. @ConfigurationProperties vs. @Value
@Value
注释是核心容器功能,它不提供与类型安全配置属性相同的功能。下表总结了@ConfigurationProperties
和@Value
支持的功能:
Feature | @ConfigurationProperties |
@Value |
---|---|---|
是 |
有限(请参阅下面的说明) |
|
是 |
不是 |
|
|
不是 |
是 |
如果您确实想要使用 例如, |
如果您为自己的组件定义了一组配置键,我们建议您将它们分组到用@ConfigurationProperties
注释的POJO中。这样做将为您提供结构化的、类型安全的对象,您可以将其注入到您自己的Bean中。
Spel
应用程序属性文件中的表达式在分析这些文件并填充环境时不会被处理。但是,可以在@Value
中编写Spel
表达式。如果应用程序属性文件中的属性的值是Spel
表达式,则在通过@Value
消费时将对其求值。
3. Profiles
Spring Profile提供了一种分离应用程序配置部分的方法,并使其仅在某些环境中可用。任何@Component
、@Configuration
或@ConfigurationProperties
都可以在加载时标记为@Profile
进行限制,如下例所示:
@Configuration(proxyBeanMethods = false) @Profile("production") public class ProductionConfiguration { // ... }
If @ConfigurationProperties beans are registered through @EnableConfigurationProperties instead of automatic scanning, the @Profile annotation needs to be specified on the @Configuration class that has the @EnableConfigurationProperties annotation. In the case where @ConfigurationProperties are scanned, @Profile can be specified on the @ConfigurationProperties class itself. |
您可以使用spring.profiles.active
Environment
属性指定哪些配置文件处于活动状态。您可以用本章前面介绍的任何方式指定该属性。例如,您可以将其包含在应用程序中。属性
,如下例所示:
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. Adding Active Profiles
spring.profiles.active
属性遵循与其他属性相同的排序规则:最高的PropertySource
获胜。这意味着您可以在Application.Properties
中指定活动配置文件,然后使用命令行开关替换它们。
有时,让向活动配置文件添加而不是替换它们的属性很有用。spring.profiles.clude
属性可用于在由spring.profiles.active
属性激活的配置文件之上添加活动配置文件。SpringApplication
入口点还具有用于设置其他配置文件的Java API。请参阅SpringApplication中的setAdditionalProfiles()
方法。
例如,当运行具有以下属性的应用程序时,即使使用--spring.profiles.active开关运行,公共配置文件和本地配置文件也将被激活:
spring.profiles.include[0]=common
spring.profiles.include[1]=local
Similar to spring.profiles.active , spring.profiles.include can only be used in non-profile specific documents. This means it cannot be included in profile specific files or documents activated by spring.config.activate.on-profile . |
如果给定的配置文件处于活动状态,则下一节中介绍的配置文件组也可用于添加活动配置文件。
3.2. Profile Groups
有时,您在应用程序中定义和使用的配置文件粒度太细,使用起来很麻烦。例如,您可能有proddb
和prodmq
配置文件,用于独立启用数据库和消息传递功能。
为了帮助实现这一点,Spring Boot允许您定义配置文件组。配置文件组允许您为相关的配置文件组定义逻辑名称。
例如,我们可以创建由proddb
和prodmq
配置文件组成的Product
组。
spring.profiles.group.production[0]=proddb
spring.profiles.group.production[1]=prodmq
现在可以使用--spring.profiles.active=production
启动我们的应用程序,以一次激活<代码>生产
、<代码>产品
和<代码>产品
配置文件。
3.3. Programmatically Setting Profiles
您可以通过调用SpringApplication.setAdditionalProfiles(…以编程方式设置活动配置文件)
。还可以使用Spring的ConfigurableEnvironment
接口激活配置文件。
3.4. Profile-specific Configuration Files
通过@ConfigurationProperties
引用的文件和Application.yml
的配置文件特定变体都被视为文件并加载。有关详细信息,请参阅配置文件特定文件。
4. Logging
Spring Boot使用Commons Logging进行所有内部日志记录,但底层日志实现是开放的。提供了Java Util日志、Log4j2和Logback的默认配置。在每种情况下,记录器都预先配置为使用控制台输出,还可以使用可选的文件输出。
默认情况下,如果您使用starters,则使用Logback进行日志记录。还包括适当的Logback路由,以确保使用Java Util日志记录、Commons日志记录、Log4J或SLF4J的依赖库都能正常工作。
There are a lot of logging frameworks available for Java. Do not worry if the above list seems confusing. Generally, you do not need to change your logging dependencies and the Spring Boot defaults work just fine. |
When you deploy your application to a servlet container or application server, logging performed with the Java Util Logging API is not routed into your application’s logs. This prevents logging performed by the container or other applications that have been deployed to it from appearing in your application’s logs. |
4.1. Log Format
Spring Boot的默认日志输出类似于以下示例:
2022-11-24T17:02:47.423Z INFO 18487 --- [ main] o.s.b.d.f.s.MyApplication : Starting MyApplication using Java 17.0.5 with PID 18487 (/opt/apps/myapp.jar started by myuser in /opt/apps/) 2022-11-24T17:02:47.428Z INFO 18487 --- [ main] o.s.b.d.f.s.MyApplication : No active profile set, falling back to 1 default profile: "default" 2022-11-24T17:02:49.682Z INFO 18487 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2022-11-24T17:02:49.709Z INFO 18487 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2022-11-24T17:02:49.710Z INFO 18487 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.1] 2022-11-24T17:02:49.877Z INFO 18487 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2022-11-24T17:02:49.880Z INFO 18487 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2384 ms 2022-11-24T17:02:50.499Z INFO 18487 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2022-11-24T17:02:50.524Z INFO 18487 --- [ main] o.s.b.d.f.s.MyApplication : Started MyApplication in 4.578 seconds (process running for 5.179)
将输出以下项目:
-
日期和时间:毫秒精度,易于分类。
-
日志级别:
错误
、警告
、信息
、调试
或跟踪
。 -
进程ID。
-
用于区分实际日志消息开头的
-
分隔符。 -
线程名称:括在方括号中(可能会被截断以用于控制台输出)。
-
记录器名称:这通常是源类名称(通常缩写)。
-
日志消息。
Logback does not have a FATAL level. It is mapped to ERROR . |
4.2. Console Output
默认日志配置在写入消息时将消息回显到控制台。默认情况下,会记录错误
级别、警告
级别和信息
级别的消息。您还可以通过使用--DEBUG
标志启动应用程序来启用“调试”模式。
$ java -jar myapp.jar --debug
You can also specify debug=true in your application.properties . |
当启用调试模式时,一些核心记录器(嵌入式容器、休眠和Spring Boot)被配置为输出更多信息。启用调试模式不会将应用程序配置为以调试
级别记录所有消息。
或者,您可以通过使用--trace
标志(或Application.Properties
中的trace=true
)启动应用程序来启用“跟踪”模式。这样做可以为一系列核心记录器(嵌入式容器、Hibernate模式生成和整个Spring产品组合)启用跟踪日志记录。
4.2.1. Color-coded Output
如果您的终端支持ANSI,则使用颜色输出来提高可读性。您可以将spring.output.ansi.Enabled
设置为支持的值以覆盖自动检测。
使用%clr
转换字配置颜色编码。在其最简单的形式中,转换器根据对数级别为输出着色,如下例所示:
%clr(%5p)
下表描述了日志级别到颜色的映射:
Level | Color |
---|---|
|
红色 |
|
红色 |
|
黄色 |
|
绿色 |
|
绿色 |
|
绿色 |
或者,您可以通过将颜色或样式作为选项提供给转换来指定应该使用的颜色或样式。例如,要将文本设置为黄色,请使用以下设置:
%clr(%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX}){yellow}
支持以下颜色和样式:
-
蓝色
-
青色
-
晕倒
-
绿色
-
洋红色
-
红色
-
黄色
4.3. File Output
默认情况下,Spring Boot只记录到控制台,不写入日志文件。如果除了控制台输出之外还要编写日志文件,则需要设置logging.file.name
或logging.file.Path
属性(例如,在您的应用程序.Properties
中)。
下表显示了如何一起使用Logging.*
属性:
logging.file.name |
logging.file.path |
Example | Description |
---|---|---|---|
(无) |
(无) |
仅控制台日志记录。 |
|
特定文件 |
(无) |
|
写入指定的日志文件。名称可以是确切的位置,也可以是相对于当前目录的位置。 |
(无) |
特定目录 |
|
将 |
日志文件在达到10 MB时会循环,并且与控制台输出一样,默认情况下会记录错误
级别、警告
级别和信息
级别的消息。
Logging properties are independent of the actual logging infrastructure. As a result, specific configuration keys (such as logback.configurationFile for Logback) are not managed by spring Boot. |
4.4. File Rotation
如果您正在使用Logback,则可以使用您的Application.Properties
或Application.yaml
文件来微调日志轮换设置。对于所有其他日志记录系统,您需要直接自己配置循环设置(例如,如果使用Log4j2,则可以添加log4j2.xml
或log4j2-spring.xml
文件)。
支持以下循环策略属性:
Name | Description |
---|---|
|
用于创建日志存档的文件名模式。 |
|
是否应在应用程序启动时进行日志归档清理。 |
|
存档前日志文件的最大大小。 |
|
删除之前可以占用的最大日志档案大小。 |
|
要保留的归档日志文件的最大数量(默认为7)。 |
4.5. Log Levels
所有受支持的日志记录系统都可以通过使用logging.level.<;logger-name>;=<;level>;
在Spring环境
(例如,在Application.Properties
中)设置记录器级别,其中级别
是TRACE、DEBUG、INFO、WARN、ERROR、FATAL或OFF之一。根
记录器可以使用logging.vel.root
进行配置。
以下示例显示了Applation.Properties
中的潜在日志记录设置:
logging.level.root=warn
logging.level.org.springframework.web=debug
logging.level.org.hibernate=error
还可以使用环境变量设置日志记录级别。例如,LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_WEB=DEBUG
会将org.springFrawork.web
设置为调试
。
The above approach will only work for package level logging. Since relaxed binding always converts environment variables to lowercase, it is not possible to configure logging for an individual class in this way. If you need to configure logging for a class, you can use the SPRING_APPLICATION_JSON variable. |
4.6. Log Groups
能够将相关的记录器分组在一起,以便可以同时配置它们,这通常很有用。例如,您可能通常会更改所有Tomcat相关记录器的日志记录级别,但您很难记住顶级包。
为了帮助实现这一点,Spring Boot允许您在Spring环境
中定义日志记录组。例如,您可以通过将“tomcat”组添加到应用程序中来定义它。属性
:
logging.group.tomcat=org.apache.catalina,org.apache.coyote,org.apache.tomcat
定义后,您可以使用一行更改组中所有记录器的级别:
logging.level.tomcat=trace
Spring Boot包括以下可开箱即用的预定义日志记录组:
Name | Loggers |
---|---|
万维网 |
|
SQL |
|
4.7. Using a Log Shutdown Hook
为了在应用程序终止时释放日志记录资源,提供了一个关闭钩子,它将在JVM退出时触发日志系统清理。除非您的应用程序部署为WAR文件,否则会自动注册此Shutdown挂钩。如果您的应用程序具有复杂的上下文层次结构,则关闭挂钩可能无法满足您的需要。如果没有,请禁用关机挂钩并调查底层日志记录系统直接提供的选项。例如,Logback提供了上下文选择器,允许在其自己的上下文中创建每个Logger。您可以使用logging.Register-Shutdown-Hook
属性禁用关闭挂钩。将其设置为False
将禁用注册。您可以在Application.Properties
或Applation.yaml
文件中设置该属性:
logging.register-shutdown-hook=false
4.8. Custom Log Configuration
可以通过在类路径上包含适当的库来激活各种日志记录系统,还可以通过在类路径的根目录或由以下SpringEnvironment
属性指定的位置提供适当的配置文件来进一步定制日志系统:logging.config
。
您可以使用org.springframework.boot.logging.LoggingSystem
系统属性强制Spring Boot使用特定的日志记录系统。该值应该是LoggingSystem
实现的完全限定类名。您还可以使用None
值来完全禁用Spring Boot的日志记录配置。
Since logging is initialized before the ApplicationContext is created, it is not possible to control logging from @PropertySources in Spring @Configuration files. The only way to change the logging system or disable it entirely is through System properties. |
根据您的日志记录系统,将加载以下文件:
Logging System | Customization |
---|---|
登录 |
|
Log4j2 |
|
JDK(Java Util日志记录) |
|
When possible, we recommend that you use the -spring variants for your logging configuration (for example, logback-spring.xml rather than logback.xml ). If you use standard configuration locations, Spring cannot completely control log initialization. |
There are known classloading issues with Java Util Logging that cause problems when running from an 'executable jar'. We recommend that you avoid it when running from an 'executable jar' if at all possible. |
为了帮助进行定制,将其他一些属性从Spring环境
传输到系统属性,如下表所述:
Spring Environment | System Property | Comments |
---|---|---|
|
|
记录异常时使用的转换字。 |
|
|
如果已定义,它将在默认日志配置中使用。 |
|
|
如果已定义,它将在默认日志配置中使用。 |
|
|
要在控制台上使用的日志模式(标准输出)。 |
|
|
日志日期格式的附加器模式。 |
|
|
用于控制台日志记录的字符集。 |
|
|
要在文件中使用的日志模式(如果启用了 |
|
|
用于文件日志记录的字符集(如果启用了 |
|
|
呈现日志级别时使用的格式(默认 |
|
|
当前进程ID(如果可能且尚未定义为操作系统环境变量时已发现)。 |
如果使用Logback,还会传输以下属性:
Spring Environment | System Property | Comments |
---|---|---|
|
|
转存日志文件名的模式(默认为 |
|
|
是否在启动时清除存档日志文件。 |
|
|
最大日志文件大小。 |
|
|
要保留的日志备份的总大小。 |
|
|
要保留的最大归档日志文件数。 |
所有受支持的日志记录系统在解析其配置文件时都可以参考系统属性。示例请参考Spring-boot.jar
中的默认配置:
如果希望在日志属性中使用占位符,则应该使用Spring Boot的语法,而不是底层框架的语法。值得注意的是,如果您使用Logback,您应该使用 |
您可以通过仅覆盖 2019-08-30 12:30:04.031 user:someone INFO 22174 --- [ nio-8080-exec-0] demo.Controller Handling authenticated request |
4.9. Logback Extensions
Spring Boot包括许多对Logback的扩展,可以帮助进行高级配置。您可以在Logback-spring.xml
配置文件中使用这些扩展。
Because the standard logback.xml configuration file is loaded too early, you cannot use extensions in it. You need to either use logback-spring.xml or define a logging.config property. |
The extensions cannot be used with Logback’s configuration scanning. If you attempt to do so, making changes to the configuration file results in an error similar to one of the following being logged: |
ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:71 - no applicable action for [springProperty], current ElementPath is [[configuration][springProperty]] ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:71 - no applicable action for [springProfile], current ElementPath is [[configuration][springProfile]]
4.9.1. Profile-specific Configuration
<;springProfile>;
标记允许您选择包含或排除基于活动的Spring配置文件的配置部分。配置文件节在<;configuration>;
元素中的任何位置都受支持。使用name
属性指定哪个配置文件接受配置。<;springProfile>;
标记可以包含配置文件名称(例如分段
)或配置文件表达式。配置文件表达式允许表达更复杂的配置文件逻辑,例如Products&;(EU-Central|EU-West)
。有关详细信息,请查看Spring框架参考指南。下面的清单显示了三个示例配置文件:
<springProfile name="staging">
<!-- configuration to be enabled when the "staging" profile is active -->
</springProfile>
<springProfile name="dev | staging">
<!-- configuration to be enabled when the "dev" or "staging" profiles are active -->
</springProfile>
<springProfile name="!production">
<!-- configuration to be enabled when the "production" profile is not active -->
</springProfile>
4.9.2. Environment Properties
<;springProperty>;
标记允许您公开SpringEnvironment
中的属性,以便在Logback中使用。如果您想要访问Logback配置中的应用程序属性
文件中的值,那么这样做会很有用。该标记的工作方式类似于Logback的标准<;Property>;
标记。但是,不是直接指定值
,而是指定属性的源
(从Environment
)。如果需要将属性存储在本地
范围之外的其他位置,则可以使用范围
属性。如果需要回退值(如果Environment
中未设置该属性),则可以使用defaultValue
属性。以下示例显示如何公开属性以在Logback中使用:
<springProperty scope="context" name="fluentHost" source="myapp.fluentd.host" defaultValue="localhost"/>
<appender name="FLUENT" class="ch.qos.logback.more.appenders.DataFluentAppender">
<remoteHost>${fluentHost}</remoteHost>
...
</appender>
The source must be specified in kebab case (such as my.property-name ). However, properties can be added to the Environment by using the relaxed rules. |
4.10. Log4j2 Extensions
Spring Boot包括许多对Log4j2的扩展,可以帮助进行高级配置。您可以在任何log4j2-spring.xml
配置文件中使用这些扩展。
Because the standard log4j2.xml configuration file is loaded too early, you cannot use extensions in it. You need to either use log4j2-spring.xml or define a logging.config property. |
The extensions supersede the Spring Boot support provided by Log4J. You should make sure not to include the org.apache.logging.log4j:log4j-spring-boot module in your build. |
4.10.1. Profile-specific Configuration
<;SpringProfile>;
标记允许您选择包含或排除基于活动的Spring配置文件的配置部分。配置文件节在<;configuration>;
元素中的任何位置都受支持。使用name
属性指定哪个配置文件接受配置。<;SpringProfile&>
标记可以包含配置文件名称(例如分段
)或配置文件表达式。配置文件表达式允许表达更复杂的配置文件逻辑,例如Products&;(EU-Central|EU-West)
。有关详细信息,请查看Spring框架参考指南。下面的清单显示了三个示例配置文件:
<SpringProfile name="staging">
<!-- configuration to be enabled when the "staging" profile is active -->
</SpringProfile>
<SpringProfile name="dev | staging">
<!-- configuration to be enabled when the "dev" or "staging" profiles are active -->
</SpringProfile>
<SpringProfile name="!production">
<!-- configuration to be enabled when the "production" profile is not active -->
</SpringProfile>
4.10.2. Environment Properties Lookup
如果您想在Log4j2配置中引用来自您的SpringEnvironment
的属性,您可以使用前缀Spring:
查找。如果您想要访问Log4j2配置中的应用程序属性
文件中的值,那么这样做会很有用。
下面的示例显示如何设置名为ApplationName
的Log4j2属性,该属性从Spring环境
读取spring.applation.name
:
<Properties>
<Property name="applicationName">${spring:spring.application.name}</property>
</Properties>
The lookup key should be specified in kebab case (such as my.property-name ). |
4.10.3. Log4j2 System Properties
Log4j2初始化后加载的所有系统属性都可以从SpringEnvironment
获取。例如,您可以将log4j2.skipJansi=FALSE
添加到Application.Properties
文件中,以使ConsoleAppender
在Windows上使用JANSI。
The Spring Environment is only considered when system properties and OS environment variables do not contain the value being loaded. |
System properties that are loaded during early Log4j2 initialization cannot reference the Spring Environment . For example, the property Log4j2 uses to allow the default Log4j2 implementation to be chosen is used before the Spring Environment is available. |
5. Internationalization
Spring Boot支持本地化消息,因此您的应用程序可以迎合不同语言偏好的用户。默认情况下,Spring Boot在类路径的根目录下查找是否存在消息
资源包。
The auto-configuration applies when the default properties file for the configured resource bundle is available (messages.properties by default). If your resource bundle contains only language-specific properties files, you are required to add the default. If no properties file is found that matches any of the configured base names, there will be no auto-configured MessageSource . |
可以使用spring.Messages
命名空间配置资源包的基本名称以及其他几个属性,如下例所示:
spring.messages.basename=messages,config.i18n.messages
spring.messages.fallback-to-system-locale=false
spring.messages.basename supports comma-separated list of locations, either a package qualifier or a resource resolved from the classpath root. |
有关更多支持的选项,请参阅MessageSourceProperties
。
6. JSON
Spring Boot提供了与三个JSON映射库的集成:
-
GSON
-
杰克逊
-
JSON-B
Jackson是首选的和默认的库。
6.1. Jackson
提供了Jackson的自动配置,Jackson是Spring-Boot-starter-json
的一部分。当Jackson在类路径上时,会自动配置一个ObjectMapper
Bean。为定制对象映射器
的配置提供了几个配置属性。
6.1.1. Custom Serializers and Deserializers
如果您使用Jackson来序列化和反序列化JSON数据,您可能希望编写您自己的JsonSerializer
和JsonDisializer
类。定制序列化程序通常通过模块注册到Jackson,但是Spring Boot提供了一个替代的@JsonComponent
注释,使直接注册SpringBean变得更容易。
您可以将@JsonComponent
注释直接用于JsonSerializer
、JsonOverializer
或KeyDisializer
实现。您还可以在包含序列化程序/反序列化程序作为内部类的类上使用它,如下例所示:
@JsonComponent public class MyJsonComponent { public static class Serializer extends JsonSerializer<MyObject> { @Override public void serialize(MyObject value, JsonGenerator jgen, SerializerProvider serializers) throws IOException { jgen.writeStartObject(); jgen.writeStringField("name", value.getName()); jgen.writeNumberField("age", value.getAge()); jgen.writeEndObject(); } } public static class Deserializer extends JsonDeserializer<MyObject> { @Override public MyObject deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException { ObjectCodec codec = jsonParser.getCodec(); JsonNode tree = codec.readTree(jsonParser); String name = tree.get("name").textValue(); int age = tree.get("age").intValue(); return new MyObject(name, age); } } }
ApplicationContext
中的所有@JsonComponent
Bean都自动注册到Jackson。因为@JsonComponent
是用@Component
元注释的,所以通常的组件扫描规则适用。
Spring Boot还提供了JsonObjectSerializer
和JsonObjectDeserializer
基类,这些基类在序列化对象时提供了标准Jackson版本的有用替代方案。有关详细信息,请参阅Java中的JsonObjectSerializer
和JsonObjectDeserializer
。
上面的示例可以重写为使用JsonObjectSerializer
/JsonObjectDeserializer
,如下所示:
@JsonComponent public class MyJsonComponent { public static class Serializer extends JsonObjectSerializer<MyObject> { @Override protected void serializeObject(MyObject value, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeStringField("name", value.getName()); jgen.writeNumberField("age", value.getAge()); } } public static class Deserializer extends JsonObjectDeserializer<MyObject> { @Override protected MyObject deserializeObject(JsonParser jsonParser, DeserializationContext context, ObjectCodec codec, JsonNode tree) throws IOException { String name = nullSafeValue(tree.get("name"), String.class); int age = nullSafeValue(tree.get("age"), Integer.class); return new MyObject(name, age); } } }
7. Task Execution and Scheduling
在上下文中没有Executor
Bean的情况下,Spring Boot自动配置一个ThreadPoolTaskExecutor
,它具有合理的默认值,可以自动与异步任务执行(@EnableAsync
)和Spring MVC异步请求处理相关联。
如果您在上下文中定义了自定义 自动配置的 |
线程池使用8个核心线程,可以根据负载增长和缩小。可以使用spring.task.ecution
命名空间对这些默认设置进行微调,如下例所示:
spring.task.execution.pool.max-size=16
spring.task.execution.pool.queue-capacity=100
spring.task.execution.pool.keep-alive=10s
这会将线程池更改为使用有界队列,以便当队列已满(100个任务)时,线程池将增加到最多16个线程。池的缩小更为激进,因为线程在空闲10秒(而不是默认的60秒)时被回收。
如果需要关联到计划的任务执行(例如使用@EnableScheduling
),也可以自动配置ThreadPoolTaskScheduler
。线程池默认使用一个线程,可以使用spring.task.Scheduling
命名空间对其设置进行微调,如下例所示:
spring.task.scheduling.thread-name-prefix=scheduling-
spring.task.scheduling.pool.size=2
如果需要创建自定义执行器或调度程序,则可以在上下文中使用TaskExecutorBuilder
Bean和TaskSchedulerBuilder
Bean。
8. Testing
Spring Boot在测试应用程序时提供了许多实用程序和注释来帮助您。测试支持由两个模块提供:Spring-boot-test
包含核心项,Spring-ot-test-autoconfiguration
支持自动配置测试。
大多数开发人员使用SpringBoot-starter-test
“starter”,它导入了Spring Boot测试模块以及JUnitJupiter、AssertJ、Hamcrest和许多其他有用的库。
如果您有使用JUnit4的测试,则可以使用JUnit5的老式引擎来运行它们。要使用Vintage引擎,请添加对
|
hamcrest-core
被排除,而支持org.hamcrest:hamcrest
,后者是Spring-boot-starter-test
的一部分。
8.1. Test Scope Dependencies
Spring-boot-starter-test
“starter”(在test
作用域
中)包含以下提供的库:
我们通常发现这些通用库在编写测试时很有用。如果这些库不能满足您的需要,您可以添加自己的其他测试依赖项。
8.2. Testing Spring Applications
依赖项注入的主要优势之一是它应该使您的代码更容易进行单元测试。您可以使用new
操作符实例化对象,甚至不需要使用Spring。您还可以使用模拟对象而不是实际依赖项。
通常,您需要超越单元测试,开始集成测试(使用SpringApplicationContext
)。能够在不需要部署应用程序或连接到其他基础设施的情况下执行集成测试是很有用的。
Spring框架包括用于此类集成测试的专用测试模块。您可以直接向org.springframework:Spring-test
声明依赖项,或者使用Spring-ot-starter-test
“starter”将其传递地拉入。
如果您以前没有使用过Spring-test
模块,那么您应该从阅读Spring框架参考文档的相关小节开始。
8.3. Testing Spring Boot Applications
一个Spring Boot应用程序是一个SpringApplicationContext
,因此除了您通常使用普通的Spring上下文进行测试之外,不需要做任何非常特殊的事情来测试它。
External properties, logging, and other features of Spring Boot are installed in the context by default only if you use SpringApplication to create it. |
Spring Boot提供了一个@SpringBootTest
注释,当您需要Spring Boot功能时,可以使用它作为标准Spring-test
@ConextConfiguration
注释的替代。注释的工作方式是通过SpringApplication
创建测试中使用的ApplicationContext
。除了@SpringBootTest
之外,还提供了许多其他注释,用于测试应用程序的更具体的片段。
If you are using JUnit 4, do not forget to also add @RunWith(SpringRunner.class) to your test, otherwise the annotations will be ignored. If you are using JUnit 5, there is no need to add the equivalent @ExtendWith(SpringExtension.class) as @SpringBootTest and the other @…Test annotations are already annotated with it. |
默认情况下,@SpringBootTest
不会启动服务器。您可以使用@SpringBootTest
的webEnvironment
属性进一步改进测试的运行方式:
-
模拟
(默认):加载WebApplicationContext
并提供模拟Web环境。使用此注释时,嵌入式服务器不会启动。如果您的类路径上没有可用的Web环境,则此模式将透明地退回到创建常规的非WebApplicationContext
。它可以与@AutoConfigureMockMvc
或@AutoConfigureWebTestClient
结合使用,用于基于模拟的Web应用程序测试。 -
RANDOM_PORT
:加载WebServerApplicationContext
,并提供真实的Web环境。启动嵌入式服务器并在随机端口上侦听。 -
Defined_Port
:加载WebServerApplicationContext
并提供真实的Web环境。嵌入式服务器在已定义的端口(从应用程序属性
)或默认端口8080
上启动和侦听。 -
无
:使用SpringApplication
加载ApplicationContext
,但不提供任何Web环境(模拟或其他)。
If your test is @Transactional , it rolls back the transaction at the end of each test method by default. However, as using this arrangement with either RANDOM_PORT or DEFINED_PORT implicitly provides a real servlet environment, the HTTP client and server run in separate threads and, thus, in separate transactions. Any transaction initiated on the server does not roll back in this case. |
@SpringBootTest with webEnvironment = WebEnvironment.RANDOM_PORT will also start the management server on a separate random port if your application uses a different port for the management server. |
8.3.1. Detecting Web Application Type
如果Spring MVC可用,则配置常规的基于MVC的应用程序上下文。如果您只有Spring WebFlux,我们将检测到这一点并配置一个基于WebFlux的应用程序上下文。
如果两者都存在,则优先使用Spring MVC。如果要在此方案中测试反应式Web应用程序,则必须设置spring.main.web-app-type
属性:
@SpringBootTest(properties = "spring.main.web-application-type=reactive") class MyWebFluxTests { // ... }
8.3.2. Detecting Test Configuration
如果您熟悉Spring测试框架,您可能会习惯于使用<代码>@ConextConfiguration(CLASSES=…),以指定要加载哪个Spring<代码>@配置
。或者,您可能经常在测试中使用嵌套的@configuration
类。
在测试Spring Boot应用程序时,这通常不是必需的。每当您没有显式定义主配置时,Spring Boot的@*测试
注释就会自动搜索您的主配置。
搜索算法从包含测试的包开始运行,直到找到一个用@SpringBootApplication
或@SpringBootConfiguration
注释的类。只要您以合理的方式组织代码,通常就可以找到您的主要配置。
如果您使用测试批注来测试应用程序的更具体部分,则应该避免在main方法的应用程序类上添加特定于特定区域的配置设置。
|
如果您想定制主配置,您可以使用嵌套的@TestConfiguration
类。与嵌套的@Configuration
类不同,嵌套的@TestConfiguration
类除了应用程序的主要配置外,还将使用嵌套的@TestConfiguration
类。
Spring’s test framework caches application contexts between tests. Therefore, as long as your tests share the same configuration (no matter how it is discovered), the potentially time-consuming process of loading the context happens only once. |
8.3.3. Using the Test Configuration Main Method
通常,@SpringBootTest
发现的测试配置将是您的主@SpringBootApplication
。在大多数结构良好的应用程序中,此配置类还将包括用于启动应用程序的main
方法。
例如,以下是典型的Spring Boot应用程序的一个非常常见的代码模式:
@SpringBootApplication public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } }
在上面的示例中,main
方法除了委托给SpringApplication.run
外,不执行任何操作。但是,也可以使用更复杂的main
方法,该方法在调用SpringApplication.run
之前应用定制。
例如,下面是一个更改横幅模式并设置其他配置文件的应用程序:
@SpringBootApplication public class MyApplication { public static void main(String[] args) { SpringApplication application = new SpringApplication(MyApplication.class); application.setBannerMode(Banner.Mode.OFF); application.setAdditionalProfiles("myprofile"); application.run(args); } }
由于main
方法中的自定义设置可能会影响生成的ApplicationContext
,因此您可能还希望使用main
方法来创建测试中使用的ApplicationContext
。默认情况下,@SpringBootTest
不会调用您的main
方法,而是直接使用类本身创建ApplicationContext
如果要更改此行为,可以将@SpringBootTest
的useMainMethod
属性更改为UseMainMethod.ALWAYS
或UseMainMethod.WHEN_Available
。设置为Always
时,如果找不到main
方法,则测试将失败。当设置为When_Available
时,如果main
方法可用,将使用该方法,否则将使用标准加载机制。
例如,下面的测试将调用MyApplication
的main
方法,以创建ApplicationContext
。如果Main方法设置了其他配置文件,则在ApplicationContext
启动时这些配置文件将处于活动状态。
@SpringBootTest(useMainMethod = UseMainMethod.ALWAYS) public class MyApplicationTests { @Test void exampleTest() { // ... } }
8.3.4. Excluding Test Configuration
如果您的应用程序使用组件扫描(例如,如果您使用@SpringBootApplication
或@ComponentScan
),您可能会发现您仅为特定测试创建的顶级配置类被意外地到处拾取。
正如我们前面所看到的,@TestConfiguration
可以在测试的内部类上使用,以定制主要配置。当放在顶级类上时,@TestConfiguration
表示src/test/Java
中的类不应该通过扫描获得。然后,您可以在需要的地方显式导入该类,如下例所示:
@SpringBootTest @Import(MyTestsConfiguration.class) class MyTests { @Test void exampleTest() { // ... } }
If you directly use @ComponentScan (that is, not through @SpringBootApplication ) you need to register the TypeExcludeFilter with it. See the Javadoc for details. |
8.3.5. Using Application Arguments
如果您的应用程序需要参数,您可以使用args
属性让@SpringBootTest
注入它们。
@SpringBootTest(args = "--app.test=one") class MyApplicationArgumentTests { @Test void applicationArgumentsPopulated(@Autowired ApplicationArguments args) { assertThat(args.getOptionNames()).containsOnly("app.test"); assertThat(args.getOptionValues("app.test")).containsOnly("one"); } }
8.3.6. Testing With a Mock Environment
默认情况下,@SpringBootTest
不会启动服务器,而是设置一个模拟环境来测试Web端点。
有了Spring MVC,我们可以使用MockMvc
或WebTestClient
查询我们的Web端点,如下例所示:
@SpringBootTest @AutoConfigureMockMvc class MyMockMvcTests { @Test void testWithMockMvc(@Autowired MockMvc mvc) throws Exception { mvc.perform(get("/")).andExpect(status().isOk()).andExpect(content().string("Hello World")); } // If Spring WebFlux is on the classpath, you can drive MVC tests with a WebTestClient @Test void testWithWebTestClient(@Autowired WebTestClient webClient) { webClient .get().uri("/") .exchange() .expectStatus().isOk() .expectBody(String.class).isEqualTo("Hello World"); } }
If you want to focus only on the web layer and not start a complete ApplicationContext , consider using @WebMvcTest instead. |
对于Spring WebFlux端点,您可以使用WebTestClient
,如下例所示:
@SpringBootTest @AutoConfigureWebTestClient class MyMockWebTestClientTests { @Test void exampleTest(@Autowired WebTestClient webClient) { webClient .get().uri("/") .exchange() .expectStatus().isOk() .expectBody(String.class).isEqualTo("Hello World"); } }
在模拟环境中进行测试通常比在完整的Servlet容器中运行更快。然而,由于模仿发生在Spring MVC层,依赖于较低级别的Servlet容器行为的代码不能直接使用MockMvc进行测试。 例如,Spring Boot的错误处理基于Servlet容器提供的“错误页面”支持。这意味着,虽然您可以按预期测试MVC层抛出和处理异常,但您不能直接测试是否呈现了特定的自定义错误页面。如果您需要测试这些较低级别的关注点,您可以启动一个完全运行的服务器,如下一节所述。 |
8.3.7. Testing With a Running Server
如果您需要启动完全运行的服务器,我们建议您使用随机端口。如果您使用@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
,,则每次测试运行时都会随机选择一个可用的端口。
@LocalServerPort
注释可用于将实际使用的端口注入测试。为方便起见,需要对启动的服务器进行REST调用的测试可以另外@AuTower
aWebTestClient
,它解析到正在运行的服务器的相对链接,并附带用于验证响应的专用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"); } }
WebTestClient can be used against both live servers and mock environments. |
这个设置需要类路径上的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.8. Customizing WebTestClient
若要自定义WebTestClient
Bean,请配置WebTestClientBuilderCustomizer
Bean。使用用于创建WebTestClient
的WebTestClient.Builder
调用任何此类Bean。
8.3.9. Using 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.10. Using Metrics
无论您的类路径是什么,在使用@SpringBootTest
时,仪表注册中心(内存中支持的除外)不会自动配置。
如果您需要将指标导出到不同的后端,作为集成测试的一部分,请使用@AutoConfigureObservability
对其进行注释。
8.3.11. Using Tracing
无论您的类路径是什么,当使用@SpringBootTest
时,跟踪都不会自动配置。
如果您需要将跟踪作为集成测试的一部分,请使用@AutoConfigureObservability
对其进行注释。
8.3.12. Mocking and Spying Beans
在运行测试时,有时有必要模拟应用程序上下文中的某些组件。例如,您可能有一个外观覆盖在开发期间不可用的某些远程服务。当您想要模拟在真实环境中可能很难触发的故障时,模拟也很有用。
Spring Boot包含一个@MockBean
注释,可用于为ApplicationContext
中的Bean定义Mockito模拟。您可以使用注释来添加新的Bean或替换单个现有的Bean定义。该注释可以直接用于测试类、测试中的字段或@Configuration
类和字段。当在一个字段上使用时,创建的模拟的实例也被注入。模拟Bean在每个测试方法之后自动重置。
如果您的测试使用了Spring Boot的某个测试注释(如
Java
Kotlin
|
下面的示例用模拟实现替换现有的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"); } }
@MockBean cannot be used to mock the behavior of a bean that is exercised during application context refresh. By the time the test is executed, the application context refresh has completed and it is too late to configure the mocked behavior. We recommend using a @Bean method to create and configure the mock in this situation. |
此外,您可以使用@SpyBean
用Mockitospy
包装任何现有的Bean。有关详细信息,请参阅Javadoc。
CGLib proxies, such as those created for scoped beans, declare the proxied methods as final . This stops Mockito from functioning correctly as it cannot mock or spy on final methods in its default configuration. If you want to mock or spy on such a bean, configure Mockito to use its inline mock maker by adding org.mockito:mockito-inline to your application’s test dependencies. This allows Mockito to mock and spy on final methods. |
While Spring’s test framework caches application contexts between tests and reuses a context for tests sharing the same configuration, the use of @MockBean or @SpyBean influences the cache key, which will most likely increase the number of contexts. |
If you are using @SpyBean to spy on a bean with @Cacheable methods that refer to parameters by name, your application must be compiled with -parameters . This ensures that the parameter names are available to the caching infrastructure once the bean has been spied upon. |
When you are using @SpyBean to spy on a bean that is proxied by Spring, you may need to remove Spring’s proxy in some situations, for example when setting expectations using given or when . Use AopTestUtils.getTargetObject(yourProxiedSpy) to do so. |
8.3.13. Auto-configured Tests
Spring Boot的自动配置系统对于应用程序工作得很好,但有时测试起来可能有点困难。只加载测试应用程序的“切片”所需的配置部分通常很有帮助。例如,您可能希望测试Spring MVC控制器是否正确映射URL,并且您不希望在这些测试中涉及数据库调用,或者您可能希望测试JPA实体,并且在这些测试运行时您对Web层不感兴趣。
春秋-引导-测试-自动配置
模块包括许多可用于自动配置此类“片”的注释。它们的工作方式都相似,都提供了一个<代码>@…加载<>应用程序上下文和一个或多个<代码>@AutoConfigure…的测试批注可用于自定义自动配置设置的批注。
Each slice restricts component scan to appropriate components and loads a very restricted set of auto-configuration classes. If you need to exclude one of them, most @…Test annotations provide an excludeAutoConfiguration attribute. Alternatively, you can use @ImportAutoConfiguration#exclude . |
Including multiple “slices” by using several @…Test annotations in one test is not supported. If you need multiple “slices”, pick one of the @…Test annotations and include the @AutoConfigure… annotations of the other “slices” by hand. |
It is also possible to use the @AutoConfigure… annotations with the standard @SpringBootTest annotation. You can use this combination if you are not interested in “slicing” your application but you want some of the auto-configured test beans. |
8.3.14. Auto-configured JSON Tests
要测试对象JSON序列化和反序列化是否按预期工作,可以使用@JsonTest
注释。@JsonTest
自动配置可用的受支持的JSON映射器,它可以是下列库之一:
-
Jackson
对象映射器
、任何@JsonComponent
Bean和任何Jackson模块
-
gson
-
Jsonb
A list of the auto-configurations that are enabled by @JsonTest can be found in the appendix. |
如果需要配置自动配置的元素,可以使用@AutoConfigureJsonTesters
注释。
Spring Boot包括基于AssertJ的帮助器,它们使用JSONAssert和JsonPath库来检查JSON是否按预期显示。JacksonTester
、GsonTester
、JsonbTester
和BasicJsonTester
类分别可用于Jackson、gson、Jsonb和Strings。当使用@JsonTest
时,测试类上的任何helper字段都可以是@AuTower
。以下示例显示了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"); } }
JSON helper classes can also be used directly in standard unit tests. To do so, call the initFields method of the helper in your @Before method if you do not use @JsonTest . |
如果使用Spring Boot的基于AssertJ的帮助器来断言给定JSON路径上的数值,则可能无法根据类型使用isEqualTo
。相反,您可以使用AssertJ的满足值
来断言该值匹配给定的条件。例如,下面的示例断言实际数字是偏移量0.01
内接近0.15
的浮点值。
@Test
void someTest() throws Exception {
SomeObject value = new SomeObject(0.152f);
assertThat(this.json.write(value)).extractingJsonPathNumberValue("@.test.numberValue")
.satisfies((number) -> assertThat(number.floatValue()).isCloseTo(0.15f, within(0.01f)));
}
8.3.15. Auto-configured Spring MVC Tests
要测试Spring MVC控制器是否按预期工作,请使用@WebMvcTest
注释。@WebMvcTest
自动配置Spring MVC基础设施,并将扫描的Bean限制为@Controller
、@ControllerAdvice
、@JsonComponent
、Converter
、GenericConverter
、Filter
、HandlerInterceptor
、WebMvcConfigurer
、WebMvcRegistrations
和HandlerMethodArgentResolver
。使用@WebMvcTest
注释时,不会扫描常规的@Component
和@ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含@ConfigurationProperties
Bean。
A list of the auto-configuration settings that are enabled by @WebMvcTest can be found in the appendix. |
If you need to register extra components, such as the Jackson Module , you can import additional configuration classes by using @Import on your test. |
通常,@WebMvcTest
仅限于单个控制器,并与@MockBean
结合使用,为所需的协作者提供模拟实现。
@WebMvcTest
还会自动配置MockMvc
。模拟MVC提供了一种强大的方法来快速测试MVC控制器,而无需启动完整的HTTP服务器。
You can also auto-configure MockMvc in a non-@WebMvcTest (such as @SpringBootTest ) by annotating it with @AutoConfigureMockMvc . The following example uses MockMvc : |
@WebMvcTest(UserVehicleController.class) class MyControllerTests { @Autowired private MockMvc mvc; @MockBean private UserVehicleService userVehicleService; @Test void testExample() throws Exception { given(this.userVehicleService.getVehicleDetails("sboot")) .willReturn(new VehicleDetails("Honda", "Civic")); this.mvc.perform(get("/sboot/vehicle").accept(MediaType.TEXT_PLAIN)) .andExpect(status().isOk()) .andExpect(content().string("Honda Civic")); } }
If you need to configure elements of the auto-configuration (for example, when servlet filters should be applied) you can use attributes in the @AutoConfigureMockMvc annotation. |
如果您使用HtmlUnit和Selify,自动配置还会提供一个HtmlUnitWebClient
Bean和/或一个SelifyWebDriver
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"); } }
By default, Spring Boot puts WebDriver beans in a special “scope” to ensure that the driver exits after each test and that a new instance is injected. If you do not want this behavior, you can add @Scope("singleton") to your WebDriver @Bean definition. |
The webDriver scope created by Spring Boot will replace any user defined scope of the same name. If you define your own webDriver scope you may find it stops working when you use @WebMvcTest . |
如果类路径上有Spring Security,@WebMvcTest
还将扫描WebSecurityConfigurer
Bean。您可以使用Spring Security的测试支持,而不是完全禁用此类测试的安全性。有关如何使用Spring Security的MockMvc
支持的更多详细信息,可以在howto.html方法部分找到。
Sometimes writing Spring MVC tests is not enough; Spring Boot can help you run full end-to-end tests with an actual server. |
8.3.16. Auto-configured Spring WebFlux Tests
要测试Spring WebFlux控制器是否按预期工作,可以使用@WebFlosTest
注释。@WebFlosTest
自动配置Spring WebFlux基础设施,并将扫描的Bean限制为@Controller
、@ControllerAdvice
、@JsonComponent
、Converter
、GenericConverter
、WebFilter
和WebFLuxConfigurer
。使用@WebFlosTest
注释时,不会扫描常规的@Component
和@ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含@ConfigurationProperties
Bean。
A list of the auto-configurations that are enabled by @WebFluxTest can be found in the appendix. |
If you need to register extra components, such as Jackson Module , you can import additional configuration classes using @Import on your test. |
通常,@WebFlosTest
被限制为单个控制器,并与@MockBean
注释结合使用,为所需的协作者提供模拟实现。
@WebFlosTest
还自动配置WebTestClient
,这提供了一种强大的方法来快速测试WebFlux控制器,而无需启动完整的HTTP服务器。
You can also auto-configure WebTestClient in a non-@WebFluxTest (such as @SpringBootTest ) by annotating it with @AutoConfigureWebTestClient . The following example shows a class that uses both @WebFluxTest and a WebTestClient : |
@WebFluxTest(UserVehicleController.class) class MyControllerTests { @Autowired private WebTestClient webClient; @MockBean private UserVehicleService userVehicleService; @Test void testExample() { given(this.userVehicleService.getVehicleDetails("sboot")) .willReturn(new VehicleDetails("Honda", "Civic")); this.webClient.get().uri("/sboot/vehicle").accept(MediaType.TEXT_PLAIN).exchange() .expectStatus().isOk() .expectBody(String.class).isEqualTo("Honda Civic"); } }
This setup is only supported by WebFlux applications as using WebTestClient in a mocked web application only works with WebFlux at the moment. |
@WebFluxTest cannot detect routes registered through the functional web framework. For testing RouterFunction beans in the context, consider importing your RouterFunction yourself by using @Import or by using @SpringBootTest . |
@WebFluxTest cannot detect custom security configuration registered as a @Bean of type SecurityWebFilterChain . To include that in your test, you will need to import the configuration that registers the bean by using @Import or by using @SpringBootTest . |
Sometimes writing Spring WebFlux tests is not enough; Spring Boot can help you run full end-to-end tests with an actual server. |
8.3.17. Auto-configured Spring GraphQL Tests
Spring GraphQL提供了专用的测试支持模块;您需要将其添加到您的项目中:
<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。Spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/testing.adoc
8.3.18. Auto-configured Data Cassandra Tests
您可以使用@DataCassandraTest
测试Cassandra应用程序。默认情况下,它配置CassandraTemplate
,扫描@Table
类,并配置Spring数据Cassandra存储库。使用@DataCassandraTest
注释时,不会扫描常规的@Component
和@ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含@ConfigurationProperties
Bean。(有关在Spring Boot中使用Cassandra的更多信息,请参阅“data.html”。)
A list of the auto-configuration settings that are enabled by @DataCassandraTest can be found in the appendix. |
以下示例显示了在Spring Boot中使用Cassandra测试的典型设置:
@DataCassandraTest class MyDataCassandraTests { @Autowired private SomeRepository repository; }
8.3.19. Auto-configured Data Couchbase Tests
您可以使用@DataCouchbase测试
来测试Couchbase应用程序。默认情况下,它配置Couchbase模板
或Reactive Couchbase模板
,扫描@Document
类,并配置Spring data Couchbase存储库。当使用@DataCouchbase测试
注释时,不会扫描常规的@Component
和@ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含@ConfigurationProperties
Bean。(有关在Spring Boot中使用Couchbase的更多信息,请参阅本章前面的“data.html”)。
A list of the auto-configuration settings that are enabled by @DataCouchbaseTest can be found in the appendix. |
以下示例显示了在Spring Boot中使用Couchbase测试的典型设置:
@DataCouchbaseTest class MyDataCouchbaseTests { @Autowired private SomeRepository repository; // ... }
8.3.20. Auto-configured Data Elasticsearch Tests
您可以使用@DataElasticearch测试
来测试Elasticearch应用程序。默认情况下,它配置Elasticearch RestTemplate
,扫描@Document
类,并配置Spring data Elasticearch存储库。使用@DataElasticearch Test
注释时,不会扫描常规的@Component
和@ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含@ConfigurationProperties
Bean。(有关在Spring Boot中使用Elasticearch的更多信息,请参阅本章前面的“data.html”)。
A list of the auto-configuration settings that are enabled by @DataElasticsearchTest can be found in the appendix. |
下面的示例显示了在Spring Boot中使用Elasticearch测试的典型设置:
@DataElasticsearchTest class MyDataElasticsearchTests { @Autowired private SomeRepository repository; // ... }
8.3.21. Auto-configured Data JPA Tests
您可以使用@DataJpaTest
注释来测试JPA应用程序。默认情况下,它扫描@Entity
类并配置Spring data JPA存储库。如果类路径上有嵌入式数据库可用,它也会配置一个。默认情况下,通过将spring.jpa.show-SQL
属性设置为true
来记录SQL查询。这可以使用注释的showSql()
属性禁用。
使用@DataJpaTest
注释时,不会扫描常规的@Component
和@ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含@ConfigurationProperties
Bean。
A list of the auto-configuration settings that are enabled by @DataJpaTest can be found in the appendix. |
默认情况下,数据JPA测试是事务性的,并在每次测试结束时回滚。有关更多详细信息,请参阅Spring框架参考文档中的相关小节。如果这不是您想要的,您可以禁用一个测试或整个类的事务管理,如下所示:
@DataJpaTest @Transactional(propagation = Propagation.NOT_SUPPORTED) class MyNonTransactionalTests { // ... }
TestEntityManager can also be auto-configured to any of your Spring-based test class by adding @AutoConfigureTestEntityManager . When doing so, make sure that your test is running in a transaction, for instance by adding @Transactional on your test class or method. |
如果您需要,也可以使用JdbcTemplate
。下面的示例显示正在使用的@DataJpaTest
批注:
@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.22. Auto-configured JDBC Tests
@JdbcTest
类似于@DataJpaTest
,但用于只需要DataSource
且不使用Spring数据JDBC的测试。默认情况下,它配置一个内存中的嵌入式数据库和一个JdbcTemplate
。使用@JdbcTest
注释时,不会扫描常规的@Component
和@ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含@ConfigurationProperties
Bean。
A list of the auto-configurations that are enabled by @JdbcTest can be found in the appendix. |
默认情况下,JDBC测试是事务性的,并在每次测试结束时回滚。有关更多详细信息,请参阅Spring框架参考文档中的相关小节。如果这不是您想要的,您可以禁用测试或整个类的事务管理,如下所示:
@JdbcTest @Transactional(propagation = Propagation.NOT_SUPPORTED) class MyTransactionalTests { }
如果您希望测试在真实的数据库上运行,您可以使用@AutoConfigureTestDatabase
注释,方法与DataJpaTest
相同。(请参阅“自动配置数据JPA测试”。)
8.3.23. Auto-configured Data JDBC Tests
@DataJdbcTest
类似于@JdbcTest
,但用于使用Spring data JDBC存储库的测试。默认情况下,它配置内存中的嵌入式数据库、JdbcTemplate
和Spring data JDBC存储库。当使用@DataJdbcTest
批注时,只扫描AbstractJdbcConfiguration
子类,不扫描常规的@Component
和@ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含@ConfigurationProperties
Bean。
A list of the auto-configurations that are enabled by @DataJdbcTest can be found in the appendix. |
默认情况下,数据JDBC测试是事务性的,并在每次测试结束时回滚。有关更多详细信息,请参阅Spring框架参考文档中的相关小节。如果这不是您想要的,您可以禁用一个测试或整个测试类的事务管理,如所示。
如果您希望测试在真实的数据库上运行,您可以使用@AutoConfigureTestDatabase
注释,方法与DataJpaTest
相同。(请参阅“自动配置数据JPA测试”。)
8.3.24. Auto-configured jOOQ Tests
您可以使用@JooqTest
与@JdbcTest
类似的方式,但用于与jOOQ相关的测试。由于jOOQ在很大程度上依赖于与数据库模式对应的基于Java的模式,因此使用了现有的DataSource
。如果您想用内存中的数据库替换它,您可以使用@AutoConfigureTestDatabase
覆盖这些设置。(有关在Spring Boot中使用jOOQ的更多信息,请参阅“data.html”。)使用@JooqTest
注释时,不会扫描常规的@Component
和@ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含@ConfigurationProperties
Bean。
A list of the auto-configurations that are enabled by @JooqTest can be found in the appendix. |
@JooqTest
配置DSLContext
。下面的示例显示正在使用的@JooqTest
批注:
@JooqTest class MyJooqTests { @Autowired private DSLContext dslContext; // ... }
JOOQ测试是事务性的,默认情况下会在每次测试结束时回滚。如果这不是您想要的,您可以禁用测试或整个测试类的事务管理,如所示,如JDBC示例所示。
8.3.25. Auto-configured Data MongoDB Tests
您可以使用@DataMongoTest
测试MongoDB应用程序。默认情况下,它配置一个MongoTemplate
,扫描@Document
类,并配置Spring data MongoDB存储库。使用@DataMongoTest
注释时,不会扫描常规的@Component
和@ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含@ConfigurationProperties
Bean。(有关在Spring Boot中使用MongoDB的更多信息,请参阅“data.html”。)
A list of the auto-configuration settings that are enabled by @DataMongoTest can be found in the appendix. |
下面的类显示了正在使用的@DataMongoTest
批注:
@DataMongoTest class MyDataMongoDbTests { @Autowired private MongoTemplate mongoTemplate; // ... }
8.3.26. Auto-configured Data Neo4j Tests
您可以使用@DataNeo4jTest
测试Neo4j应用程序。默认情况下,它扫描@Node
类,并配置Spring data Neo4j存储库。使用@DataNeo4jTest
注释时,不扫描常规的@Component
和@ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含@ConfigurationProperties
Bean。(有关在Spring Boot中使用Neo4J的更多信息,请参阅“data.html”。)
A list of the auto-configuration settings that are enabled by @DataNeo4jTest can be found in the appendix. |
以下示例显示了在Spring Boot中使用Neo4J测试的典型设置:
@DataNeo4jTest class MyDataNeo4jTests { @Autowired private SomeRepository repository; // ... }
默认情况下,Data Neo4j测试是事务性的,并在每次测试结束时回滚。有关更多详细信息,请参阅Spring框架参考文档中的相关小节。如果这不是您想要的,您可以禁用测试或整个类的事务管理,如下所示:
@DataNeo4jTest @Transactional(propagation = Propagation.NOT_SUPPORTED) class MyDataNeo4jTests { }
Transactional tests are not supported with reactive access. If you are using this style, you must configure @DataNeo4jTest tests as described above. |
8.3.27. Auto-configured Data Redis Tests
您可以使用@DataRedisTest
测试Redis应用程序。默认情况下,它扫描@RedisHash
类并配置Spring data Redis存储库。使用@DataRedisTest
注释时,不会扫描常规的@Component
和@ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含@ConfigurationProperties
Bean。(有关在Spring Boot中使用Redis的更多信息,请参阅“data.html”。)
A list of the auto-configuration settings that are enabled by @DataRedisTest can be found in the appendix. |
下面的示例显示正在使用的@DataRedisTest
批注:
@DataRedisTest class MyDataRedisTests { @Autowired private SomeRepository repository; // ... }
8.3.28. Auto-configured Data LDAP Tests
您可以使用@DataLdapTest
来测试LDAP应用程序。默认情况下,它配置内存中的嵌入式LDAP(如果可用)、配置LdapTemplate
、扫描@Entry
类以及配置Spring data LDAP存储库。使用@DataLdapTest
注释时,不会扫描常规的@Component
和@ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含@ConfigurationProperties
Bean。(有关通过Spring Boot使用LDAP的更多信息,请参阅“data.html
A list of the auto-configuration settings that are enabled by @DataLdapTest can be found in the appendix. |
下面的示例显示正在使用的@DataLdapTest
批注:
@DataLdapTest class MyDataLdapTests { @Autowired private LdapTemplate ldapTemplate; // ... }
内存中的嵌入式LDAP通常可以很好地用于测试,因为它速度很快,不需要任何开发人员安装。但是,如果您更喜欢在实际的LDAP服务器上运行测试,则应该排除嵌入式LDAP自动配置,如下例所示:
@DataLdapTest(excludeAutoConfiguration = EmbeddedLdapAutoConfiguration.class) class MyDataLdapTests { // ... }
8.3.29. Auto-configured REST Clients
您可以使用@RestClientTest
注释来测试REST客户端。默认情况下,它自动配置Jackson、gson和Jsonb支持,配置RestTemplateBuilder
,并添加对MockRestServiceServer
的支持。使用@RestClientTest
注释时,不会扫描常规的@Component
和@ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含@ConfigurationProperties
Bean。
A list of the auto-configuration settings that are enabled by @RestClientTest can be found in the appendix. |
应使用@RestClientTest
的值
或组件
属性指定要测试的特定Bean,如下例所示:
@RestClientTest(RemoteVehicleDetailsService.class) class MyRestClientTests { @Autowired private RemoteVehicleDetailsService service; @Autowired private MockRestServiceServer server; @Test void getVehicleDetailsWhenResultIsSuccessShouldReturnDetails() { this.server.expect(requestTo("/greet/details")).andRespond(withSuccess("hello", MediaType.TEXT_PLAIN)); String greeting = this.service.callRestService(); assertThat(greeting).isEqualTo("hello"); } }
8.3.30. Auto-configured Spring REST Docs Tests
您可以使用@AutoConfigureRestDocs
注释在您的Mock MVC、REST Assured或WebTestClient测试中使用Spring rest Docs。它消除了在Spring rest文档中使用JUnit扩展的需要。
@AutoConfigureRestDocs
可用于覆盖默认输出目录(如果您使用的是Maven,则目标/生成的代码片段
;如果您使用的是Gradle,则构建/生成的代码片段
)。它还可用于配置出现在任何记录的URI中的主机、方案和端口。
Auto-configured Spring REST Docs Tests With Mock MVC
@AutoConfigureRestDocs
定制MockMvc
Bean,在测试基于Servlet的Web应用程序时使用Spring REST文档。您可以使用@Autwire
注入它,并像使用Mock MVC和Spring REST文档时一样在测试中使用它,如下例所示:
@WebMvcTest(UserController.class) @AutoConfigureRestDocs class MyUserDocumentationTests { @Autowired private MockMvc mvc; @Test void listUsers() throws Exception { this.mvc.perform(get("/users").accept(MediaType.TEXT_PLAIN)) .andExpect(status().isOk()) .andDo(document("list-users")); } }
如果您需要比<RestDocsMockMvcConfigurationCustomizer
>@AutoConfigureRestDocs属性所提供的更多的对Spring rest Docs配置的控制,您可以使用Spring Bean,如下例所示:
@TestConfiguration(proxyBeanMethods = false) public class MyRestDocsConfiguration implements RestDocsMockMvcConfigurationCustomizer { @Override public void customize(MockMvcRestDocumentationConfigurer configurer) { configurer.snippets().withTemplateFormat(TemplateFormats.markdown()); } }
如果您希望利用Spring rest Docs对参数化输出目录的支持,您可以创建一个RestDocumentationResultHandler
Bean。自动配置总是使用此结果处理程序调用Do
,从而导致每个MockMvc
调用自动生成默认代码片段。下面的示例显示了正在定义的RestDocumentationResultHandler
:
@TestConfiguration(proxyBeanMethods = false) public class MyResultHandlerConfiguration { @Bean public RestDocumentationResultHandler restDocumentation() { return MockMvcRestDocumentation.document("{method-name}"); } }
Auto-configured Spring REST Docs Tests With WebTestClient
@AutoConfigureRestDocs
在测试反应性Web应用程序时还可以与WebTestClient
一起使用。您可以使用@AuTower
注入它,并在测试中使用它,就像您通常使用@WebFlosTest
和Spring REST文档一样,如下例所示:
@WebFluxTest @AutoConfigureRestDocs class MyUsersDocumentationTests { @Autowired private WebTestClient webTestClient; @Test void listUsers() { this.webTestClient .get().uri("/") .exchange() .expectStatus() .isOk() .expectBody() .consumeWith(document("list-users")); } }
如果您需要比<RestDocsWebTestClientConfigurationCustomizer
>@AutoConfigureRestDocs属性所提供的更多的对Spring rest Docs配置的控制,您可以使用Spring Bean,如下例所示:
@TestConfiguration(proxyBeanMethods = false) public class MyRestDocsConfiguration implements RestDocsWebTestClientConfigurationCustomizer { @Override public void customize(WebTestClientRestDocumentationConfigurer configurer) { configurer.snippets().withEncoding("UTF-8"); } }
如果您想使用Spring REST Docs对参数化输出目录的支持,您可以使用WebTestClientBuilderCustomizer
为每个实体交换结果配置一个使用者。下面的示例显示正在定义这样一个WebTestClientBuilderCustomizer
:
@TestConfiguration(proxyBeanMethods = false) public class MyWebTestClientBuilderCustomizerConfiguration { @Bean public WebTestClientBuilderCustomizer restDocumentation() { return (builder) -> builder.entityExchangeResultConsumer(document("{method-name}")); } }
Auto-configured Spring REST Docs Tests With REST Assured
@AutoConfigureRestDocs
使RequestSpecification
Bean可用于您的测试,该Bean已预配置为使用Spring REST文档。您可以使用@Autwire
注入它,并像使用REST Assured和Spring REST文档时一样在测试中使用它,如下例所示:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @AutoConfigureRestDocs class MyUserDocumentationTests { @Test void listUsers(@Autowired RequestSpecification documentationSpec, @LocalServerPort int port) { given(documentationSpec) .filter(document("list-users")) .when() .port(port) .get("/") .then().assertThat() .statusCode(is(200)); } }
如果您需要比<RestDocsRestAssuredConfigurationCustomizer
>@AutoConfigureRestDocs属性更好地控制Spring rest Docs配置,则可以使用Spring Bean,如下例所示:
@TestConfiguration(proxyBeanMethods = false) public class MyRestDocsConfiguration implements RestDocsRestAssuredConfigurationCustomizer { @Override public void customize(RestAssuredRestDocumentationConfigurer configurer) { configurer.snippets().withTemplateFormat(TemplateFormats.markdown()); } }
8.3.31. Auto-configured Spring Web Services Tests
Auto-configured Spring Web Services Client Tests
您可以使用@WebServiceClientTest
来测试使用Spring Web Services项目调用Web服务的应用程序。默认情况下,它配置一个模拟WebServiceServer
Bean,并自动定制您的WebServiceTemplateBuilder
。(有关在Spring Boot中使用Web服务的更多信息,请参阅“io.html”。)
A list of the auto-configuration settings that are enabled by @WebServiceClientTest can be found in the appendix. |
下面的示例显示正在使用的@WebServiceClientTest
批注:
@WebServiceClientTest(SomeWebService.class) class MyWebServiceClientTests { @Autowired private MockWebServiceServer server; @Autowired private SomeWebService someWebService; @Test void mockServerCall() { this.server .expect(payload(new StringSource("<request/>"))) .andRespond(withPayload(new StringSource("<response><status>200</status></response>"))); assertThat(this.someWebService.test()) .extracting(Response::getStatus) .isEqualTo(200); } }
Auto-configured Spring Web Services Server Tests
您可以使用@WebServiceServerTest
来测试使用Spring Web Services项目实现Web服务的应用程序。默认情况下,它配置一个可用于调用您的Web服务端点的MockWebServiceClient
Bean。(有关在Spring Boot中使用Web服务的更多信息,请参阅“io.html”。)
A list of the auto-configuration settings that are enabled by @WebServiceServerTest can be found in the appendix. |
下面的示例显示正在使用的@WebServiceServerTest
批注:
@WebServiceServerTest(ExampleEndpoint.class) class MyWebServiceServerTests { @Autowired private MockWebServiceClient client; @Test void mockServerCall() { this.client .sendRequest(RequestCreators.withPayload(new StringSource("<ExampleRequest/>"))) .andExpect(ResponseMatchers.payload(new StringSource("<ExampleResponse>42</ExampleResponse>"))); } }
8.3.32. Additional Auto-configuration and Slicing
每个切片提供一个或多个@AutoConfigure…注释,即定义应该作为片的一部分包括的自动配置。通过创建自定义@AutoConfigure…,可以在逐个测试的基础上添加其他自动配置批注或将@ImportAutoConfiguration
添加到测试中,如下例所示:
@JdbcTest @ImportAutoConfiguration(IntegrationAutoConfiguration.class) class MyJdbcTests { }
Make sure to not use the regular @Import annotation to import auto-configurations as they are handled in a specific way by Spring Boot. |
或者,通过将切片批注注册到存储在META-INF/Spring
中的文件中,可以为切片批注的任何使用添加其他自动配置,如下例所示:
com.example.IntegrationAutoConfiguration
在本例中,在使用<com.example.IntegrationAutoConfiguration
>@JDBCTest注释的每个测试上都启用了代码。
You can use comments via # in this file. |
A slice or @AutoConfigure… annotation can be customized this way as long as it is meta-annotated with @ImportAutoConfiguration . |
8.3.33. User Configuration and Slicing
如果您以合理的方式组织代码,则您的@SpringBootApplication
类默认用作测试的配置。
然后,重要的是不要在应用程序的主类中使用特定于其功能的特定区域的配置设置。
假设您使用的是Spring Batch,并且依赖于它的自动配置。您可以按如下方式定义@SpringBootApplication
:
@SpringBootApplication @EnableBatchProcessing public class MyApplication { // ... }
因为这个类是测试的源代码配置,所以任何切片测试实际上都会尝试启动Spring Batch,这绝对不是您想要做的事情。推荐的方法是将该区域特定的配置移动到与您的应用程序处于同一级别的单独@Configuration
类,如下例所示:
@Configuration(proxyBeanMethods = false) @EnableBatchProcessing public class MyBatchConfiguration { // ... }
Depending on the complexity of your application, you may either have a single @Configuration class for your customizations or one class per domain area. The latter approach lets you enable it in one of your tests, if necessary, with the @Import annotation. See this how-to section for more details on when you might want to enable specific @Configuration classes for slice tests. |
测试切片从扫描中排除@Configuration
类。例如,对于@WebMvcTest
,以下配置不会在测试片加载的应用程序上下文中包括给定的WebMvcConfigurer
Bean:
@Configuration(proxyBeanMethods = false) public class MyWebConfiguration { @Bean public WebMvcConfigurer testConfigurer() { return new WebMvcConfigurer() { // ... }; } }
然而,下面的配置将导致测试切片加载定制的WebMvcConfigurer
。
@Component public class MyWebMvcConfigurer implements WebMvcConfigurer { // ... }
另一个令人困惑的原因是类路径扫描。假设虽然您以合理的方式构建了代码,但您需要扫描一个额外的包。您的应用程序可能类似于以下代码:
@SpringBootApplication @ComponentScan({ "com.example.app", "com.example.another" }) public class MyApplication { // ... }
这样做有效地覆盖了默认的组件扫描指令,其副作用是扫描这两个包,而不管您选择的是哪个切片。例如,@DataJpaTest
似乎突然扫描应用程序的组件和用户配置。同样,将定制指令移到单独的类中是解决此问题的好方法。
If this is not an option for you, you can create a @SpringBootConfiguration somewhere in the hierarchy of your test so that it is used instead. Alternatively, you can specify a source for your test, which disables the behavior of finding a default one. |
8.3.34. Using Spock to Test Spring Boot Applications
Spock 2.2或更高版本可用于测试Spring Boot应用程序。为此,将Spock的-groovy-4.0
版本的Spock-Spring模块的依赖项添加到应用程序的构建中。Spock-Spring
将Spring的测试框架集成到Spock中。有关详细信息,请参阅Spock的Spring模块文档。
8.4. Test Utilities
在测试应用程序时通常有用的几个测试实用程序类被打包为SpringBoot
的一部分。
8.4.1. ConfigDataApplicationContextInitializer
ConfigDataApplicationContextInitializer
是一个ApplicationContextInitializer
,您可以将其应用于您的测试以加载Spring BootApplication.Properties
文件。当您不需要@SpringBootTest
提供的全套功能时,可以使用它,如下例所示:
@ContextConfiguration(classes = Config.class, initializers = ConfigDataApplicationContextInitializer.class) class MyConfigFileTests { // ... }
Using ConfigDataApplicationContextInitializer alone does not provide support for @Value("${…}") injection. Its only job is to ensure that application.properties files are loaded into Spring’s Environment . For @Value support, you need to either additionally configure a PropertySourcesPlaceholderConfigurer or use @SpringBootTest , which auto-configures one for you. |
8.4.2. TestPropertyValues
TestPropertyValues
允许您向ConfigurableEnvironment
或ConfigurableApplicationContext
快速添加属性。您可以使用key=Value
字符串进行调用,如下所示:
class MyEnvironmentTests { @Test void testPropertySources() { MockEnvironment environment = new MockEnvironment(); TestPropertyValues.of("org=Spring", "name=Boot").applyTo(environment); assertThat(environment.getProperty("name")).isEqualTo("Boot"); } }
8.4.3. OutputCapture
OutputCapture
是一个JUnit扩展
,可用于捕获System.out
和System.err
输出。要使用Add@ExtendWith(OutputCaptureExtension.class)
并将CapturedOutput
作为参数注入测试类构造函数或测试方法,如下所示:
@ExtendWith(OutputCaptureExtension.class) class MyOutputCaptureTests { @Test void testName(CapturedOutput output) { System.out.println("Hello World!"); assertThat(output).contains("World"); } }
8.4.4. TestRestTemplate
TestRestTemplate
是用于集成测试的Spring的RestTemplate
的一个方便的替代方案。您可以获得普通模板或发送基本HTTP身份验证的模板(带有用户名和密码)。在任何一种情况下,模板都是容错的。这意味着它以一种测试友好的方式运行,不会在4xx和5xx错误中引发异常。相反,可以通过返回的ResponseEntity
及其状态代码来检测此类错误。
Spring Framework 5.0 provides a new WebTestClient that works for WebFlux integration tests and both WebFlux and MVC end-to-end testing. It provides a fluent API for assertions, unlike TestRestTemplate . |
建议(但不是强制)使用Apache HTTP客户端(版本4.3.2或更高版本)。如果您的类路径中有它,TestRestTemplate
通过适当地配置客户端来响应。如果您使用的是ApacheHTTP客户端,则会启用一些额外的测试友好特性:
-
不遵循重定向(因此您可以断言响应位置)。
-
Cookie被忽略(因此模板是无状态的)。
TestRestTemplate
可以在集成测试中直接实例化,如下例所示:
class MyTests { private final TestRestTemplate template = new TestRestTemplate(); @Test void testRequest() { ResponseEntity<String> headers = this.template.getForEntity("https://myhost.example.com/example", String.class); assertThat(headers.getHeaders().getLocation()).hasHost("other.example.com"); } }
或者,如果您将@SpringBootTest
批注与WebEnvironmental ment.RANDOM_PORT
或WebEnvironmental ment.DEFINED_PORT
一起使用,则可以注入一个完全配置的TestRestTemplate
并开始使用它。如果需要,可以通过RestTemplateBuilder
Bean应用其他定制。任何未指定主机和端口的URL都会自动连接到嵌入式服务器,如下例所示:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) class MySpringBootTests { @Autowired private TestRestTemplate template; @Test void testRequest() { HttpHeaders headers = this.template.getForEntity("/example", String.class).getHeaders(); assertThat(headers.getLocation()).hasHost("other.example.com"); } @TestConfiguration(proxyBeanMethods = false) static class RestTemplateBuilderConfiguration { @Bean RestTemplateBuilder restTemplateBuilder() { return new RestTemplateBuilder().setConnectTimeout(Duration.ofSeconds(1)) .setReadTimeout(Duration.ofSeconds(1)); } } }
9. Creating Your Own Auto-configuration
如果您在一家开发共享库的公司工作,或者如果您在开放源码或商业库上工作,您可能希望开发自己的自动配置。自动配置类可以捆绑在外部JAR中,并且仍然可以由Spring Boot获取。
自动配置可以与提供自动配置代码以及您将与其一起使用的典型库的“启动器”相关联。我们首先介绍构建您自己的自动配置所需了解的知识,然后介绍创建自定义入门程序所需的典型步骤。
9.1. Understanding Auto-configured Beans
实现自动配置的类使用@Autoconfiguration
进行注释。该注释本身使用@configuration
进行元注释,从而使自动配置成为标准的@configuration
类。附加的@Conditional
注释用于约束何时应用自动配置。通常,自动配置类使用@ConditionalOnClass
和@ConditionalOnMissingBean
注释。这确保了只有当找到相关类并且您没有声明您自己的@configuration
时,才会应用自动配置。
您可以浏览spring-boot-autoconfigure
的源代码以查看Spring提供的<代码>@AutoConfiguration类
(参见META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
文件)。
9.2. Locating Auto-configuration Candidates
Spring Boot检查已发布的JAR中是否存在META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
文件。该文件应列出您的配置类,每行一个类名,如下例所示:
com.mycorp.libx.autoconfigure.LibXAutoConfiguration com.mycorp.libx.autoconfigure.LibXWebAutoConfiguration
You can add comments to the imports file using the # character. |
Auto-configurations must be loaded only by being named in the imports file. Make sure that they are defined in a specific package space and that they are never the target of component scanning. Furthermore, auto-configuration classes should not enable component scanning to find additional components. Specific @Import s should be used instead. |
如果您的配置需要以特定的顺序应用,您可以在@AutoConfigurationTM@AutoConfigureBefore
>批注或专用的
WebMvcAutoConfiguration
之后应用。
如果您想订购某些不应该相互直接了解的自动配置,您还可以使用@AutoConfigureOrder
。该注释与常规的@Order
注释具有相同的语义,但为自动配置类提供了专用的顺序。
与标准的@configuration
类一样,应用自动配置类的顺序只影响定义它们的Bean的顺序。随后创建这些Bean的顺序不受影响,并由每个Bean的依赖关系和任何@DependsOn
关系确定。
9.3. Condition Annotations
您几乎总是希望在自动配置类中包含一个或多个@Conditional
注释。@ConditionalOnMissingBean
注释是一个常见的示例,用于允许开发人员在对您的默认设置不满意时覆盖自动配置。
Spring Boot包括许多@Conditional
批注,您可以通过批注@Configuration
类或单个@Bean
方法在您自己的代码中重用这些批注。这些注释包括:
9.3.1. Class Conditions
@ConditionalOnClass
和@ConditionalOnMissingClass
批注允许根据是否存在特定类来包括@Configuration
类。由于注释元数据是使用ASM进行解析的,因此您可以使用值
属性来引用实际的类,即使该类可能并不实际出现在运行的应用程序类路径中。如果您喜欢使用字符串
值指定类名,也可以使用name
属性。
这种机制不适用于@Bean
方法,在@Bean
方法中,返回类型通常是条件的目标:在方法上的条件应用之前,JVM将加载类和可能已处理的方法引用,如果类不存在,这些引用将失败。
要处理此场景,可以使用单独的@Configuration
类来隔离该条件,如下例所示:
@AutoConfiguration // Some conditions ... public class MyAutoConfiguration { // Auto-configured beans ... @Configuration(proxyBeanMethods = false) @ConditionalOnClass(SomeService.class) public static class SomeServiceConfiguration { @Bean @ConditionalOnMissingBean public SomeService someService() { return new SomeService(); } } }
If you use @ConditionalOnClass or @ConditionalOnMissingClass as a part of a meta-annotation to compose your own composed annotations, you must use name as referring to the class in such a case is not handled. |
9.3.2. Bean Conditions
@ConditionalOnBean
和@ConditionalOnMissingBean
注释允许根据是否存在特定的Bean来包含Bean。您可以使用值
属性按类型指定Bean,或使用名称
按名称指定Bean。搜索
属性允许您限制在搜索Bean时应考虑的ApplicationContext
层次结构。
当放置在@Bean
方法上时,目标类型默认为该方法的返回类型,如下例所示:
@AutoConfiguration public class MyAutoConfiguration { @Bean @ConditionalOnMissingBean public SomeService someService() { return new SomeService(); } }
在前面的示例中,如果ApplicationContext
中尚未包含任何SomeService
类型的Bean,则将创建SomeService
Bean。
You need to be very careful about the order in which bean definitions are added, as these conditions are evaluated based on what has been processed so far. For this reason, we recommend using only @ConditionalOnBean and @ConditionalOnMissingBean annotations on auto-configuration classes (since these are guaranteed to load after any user-defined bean definitions have been added). |
@ConditionalOnBean and @ConditionalOnMissingBean do not prevent @Configuration classes from being created. The only difference between using these conditions at the class level and marking each contained @Bean method with the annotation is that the former prevents registration of the @Configuration class as a bean if the condition does not match. |
When declaring a @Bean method, provide as much type information as possible in the method’s return type. For example, if your bean’s concrete class implements an interface the bean method’s return type should be the concrete class and not the interface. Providing as much type information as possible in @Bean methods is particularly important when using bean conditions as their evaluation can only rely upon to type information that is available in the method signature. |
9.3.3. Property Conditions
@ConditionalOnProperty
注释允许基于Spring Environment属性包括配置。使用前缀
和名称
属性指定应该检查的属性。默认情况下,匹配存在且不等于False
的任何属性。您还可以使用havingValue
和matchIfMissing
属性创建更高级的检查。
9.3.4. Resource Conditions
@ConditionalOnResource
注释允许仅在存在特定资源时才包括配置。可以使用常用的Spring约定指定资源,如下面的示例所示:file:/home/user/test.dat
。
9.3.5. Web Application Conditions
@ConditionalOnWebApplication
和@ConditionalOnNotWebApplication
注释允许根据应用程序是否为“Web应用程序”来包含配置。基于Servlet的Web应用程序是使用SpringWebApplicationContext
、定义会话
作用域或具有ConfigurableWebEnvironment
的任何应用程序。反应式Web应用程序是使用<ConfigurableReactiveWebEnvironment
.>Reactive WebApplicationContext或具有
@ConditionalOnWarDeployment
注释允许根据应用程序是否是部署到容器的传统WAR应用程序来包括配置。对于使用嵌入式服务器运行的应用程序,此条件不匹配。
9.3.6. SpEL Expression Conditions
@ConditionalOnExpression
注释允许根据Spel表达式的结果包括配置。
Referencing a bean in the expression will cause that bean to be initialized very early in context refresh processing. As a result, the bean won’t be eligible for post-processing (such as configuration properties binding) and its state may be incomplete. |
9.4. Testing your Auto-configuration
自动配置可能受许多因素的影响:用户配置(@Bean
定义和环境
定制)、条件评估(特定库的存在)以及其他。具体地说,每个测试都应该创建一个定义良好的ApplicationContext
,表示这些定制的组合。ApplicationConextRunner
提供了一种很好的方法来实现这一点。
ApplicationConextRunner
通常被定义为测试类的一个字段,用于收集基本的公共配置。下面的示例确保始终调用MyServiceAutoConfiguration
:
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(MyServiceAutoConfiguration.class));
If multiple auto-configurations have to be defined, there is no need to order their declarations as they are invoked in the exact same order as when running the application. |
每个测试都可以使用Runner来表示特定的用例。例如,下面的示例调用一个用户配置(UserConfiguration
),并检查自动配置是否正确后退。调用Run
提供可与AssertJ
一起使用的回调上下文。
@Test
void defaultServiceBacksOff() {
this.contextRunner.withUserConfiguration(UserConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(MyService.class);
assertThat(context).getBean("myCustomService").isSameAs(context.getBean(MyService.class));
});
}
@Configuration(proxyBeanMethods = false)
static class UserConfiguration {
@Bean
MyService myCustomService() {
return new MyService("mine");
}
}
还可以轻松自定义环境
,如下例所示:
@Test
void serviceNameCanBeConfigured() {
this.contextRunner.withPropertyValues("user.name=test123").run((context) -> {
assertThat(context).hasSingleBean(MyService.class);
assertThat(context.getBean(MyService.class).getName()).isEqualTo("test123");
});
}
运行器还可用于显示ConditionEvaluationReport
。报告可以在信息
或调试
级别打印。以下示例显示如何在自动配置测试中使用ConditionEvaluationReportLoggingListener
打印报告。
class MyConditionEvaluationReportingTests { @Test void autoConfigTest() { new ApplicationContextRunner() .withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO)) .run((context) -> { // Test something... }); } }
9.4.1. Simulating a Web Context
如果您需要测试仅在Servlet或反应式Web应用程序上下文中操作的自动配置,请分别使用WebApplicationConextRunner
或ReactiveWebApplicationContextRunner
。
9.4.2. Overriding the Classpath
还可以测试当特定类和/或包在运行时不存在时会发生什么。Spring Boot附带了一个FilteredClassLoader
,运行者可以轻松地使用它。在下面的示例中,我们断言如果MyService
不存在,则自动配置被正确禁用:
@Test
void serviceIsIgnoredIfLibraryIsNotPresent() {
this.contextRunner.withClassLoader(new FilteredClassLoader(MyService.class))
.run((context) -> assertThat(context).doesNotHaveBean("myService"));
}
9.5. Creating Your Own Starter
典型的Spring Boot starter包含自动配置和定制给定技术的基础设施的代码,我们称其为“acme”。为了使其易于扩展,可以向环境公开专用命名空间中的多个配置键。最后,提供了单一的“starter”依赖关系,以帮助用户尽可能轻松地开始。
具体地说,自定义启动器可以包含以下内容:
-
自动配置
模块,包含“acme”的自动配置代码。 -
starter
模块,它为自动配置
模块以及“acme”和任何通常有用的其他依赖项提供依赖项。简而言之,添加入门程序应该可以提供开始使用该库所需的一切。
这种在两个模块中分开的方式是没有必要的。如果“acme”有几种风格、选项或可选功能,那么最好将自动配置分开,因为您可以清楚地表示某些功能是可选的。此外,您还可以创建一个启动器,提供有关这些可选依赖项的意见。与此同时,其他人只能依靠自动配置
模块,并以不同的观点定制自己的Starter。
如果自动配置相对简单,并且没有可选功能,那么将启动器中的两个模块合并绝对是一个选择。
9.5.1. Naming
您应该确保为您的初学者提供适当的命名空间。即使您使用不同的MavengroupID
,模块名称也不要以SpringBoot
开头。我们可能会在未来为您自动配置的东西提供官方支持。
根据经验,您应该以启动器的名字命名一个组合模块。例如,假设您正在为“acme”创建一个starter,并将自动配置模块命名为acme-Spring-boot
,将starter命名为acme-Spring-ot-starter
。如果您只有一个将这两个模块组合在一起的模块,那么将其命名为acme-Spring-ot-starter
。
9.5.2. Configuration keys
如果您的启动程序提供了配置密钥,请为它们使用唯一的命名空间。特别是,不要将键包含在Spring Boot使用的名称空间中(例如服务器
、管理
、Spring
等等)。如果您使用相同的命名空间,我们将来可能会以破坏您的模块的方式修改这些命名空间。经验法则是,在所有键前面加上您拥有的名称空间(例如acme
)。
确保通过为每个属性添加字段javadoc来记录配置密钥,如下例所示:
@ConfigurationProperties("acme") public class AcmeProperties { /** * Whether to check the location of acme resources. */ private boolean checkLocation = true; /** * Timeout for establishing a connection to the acme server. */ private Duration loginTimeout = Duration.ofSeconds(3); }
You should only use plain text with @ConfigurationProperties field Javadoc, since they are not processed before being added to the JSON. |
以下是我们在内部遵循的一些规则,以确保描述的一致性:
-
不要以“The”或“A”作为描述的开头。
-
对于
布尔
类型,描述以“是否”或“启用”开头。 -
对于基于集合的类型,说明以“逗号分隔列表”开头
-
使用
java.time.Duration
而不是long
,如果默认单位与毫秒不同,请描述默认单位,例如“如果没有指定持续时间后缀,则将使用秒”。 -
除非必须在运行时确定,否则请勿在描述中提供默认值。
确保触发元数据生成,以便IDE帮助您的键也可用。您可能希望查看生成的元数据(META-INF/spring-configuration-metadata.json
),以确保正确记录了密钥。在兼容的IDE中使用您自己的Starter来验证元数据的质量也是一个好主意。
9.5.3. The “autoconfigure” Module
自动配置
模块包含开始使用该库所需的所有内容。它还可以包含配置键定义(如@ConfigurationProperties
)和任何可用于进一步定制组件初始化方式的回调接口。
You should mark the dependencies to the library as optional so that you can include the autoconfigure module in your projects more easily. If you do it that way, the library is not provided and, by default, Spring Boot backs off. |
Spring Boot使用注释处理器在元数据文件(META-INF/spring-autoconfigure-metadata.properties
).中收集关于自动配置的条件如果该文件存在,则它被用来急切地过滤不匹配的自动配置,这将缩短启动时间。
使用Maven构建时,建议在包含自动配置的模块中添加以下依赖项:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure-processor</artifactId>
<optional>true</optional>
</dependency>
如果您已经在应用程序中直接定义了自动配置,请确保配置Spring-ot-maven-plugin
,以防止重新打包
目标将依赖项添加到FAT JAR中:
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure-processor</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
使用Gradle时,应在注解处理器
配置中声明依赖项,如下例所示:
dependencies {
annotationProcessor "org.springframework.boot:spring-boot-autoconfigure-processor"
}
9.5.4. Starter Module
开胃菜实际上是一个空罐子。它的唯一目的是提供与库一起工作所需的依赖项。你可以把它看作是一种对开始需要什么的固执己见的观点。
不要对添加了您的初学者的项目做出假设。如果您正在自动配置的库通常需要其他启动器,那么也要提到它们。如果可选依赖项的数量很多,则提供一组适当的默认依赖项可能很困难,因为您应该避免包括库的典型使用所不必要的依赖项。换句话说,您不应该包括可选的依赖项。
Either way, your starter must reference the core Spring Boot starter (spring-boot-starter ) directly or indirectly (there is no need to add it if your starter relies on another starter). If a project is created with only your custom starter, Spring Boot’s core features will be honoured by the presence of the core starter. |
10. Kotlin Support
Spring Boot通过利用其他Spring项目中的支持来提供Kotlin支持,比如Spring框架、Spring data和Reader。有关详细信息,请参阅Spring框架Kotlin支持文档。
开始使用Spring Boot和Kotlin的最简单方法是按照本综合教程进行操作。您可以使用start.spring.io创建新的Kotlin项目。如果您需要支持,请随时加入Kotlin Slack的#Spring频道,或者使用Stack Overflow上的Spring
和Kotlin
标签提问。
10.1. Requirements
Spring Boot至少需要Kotlin 1.7.x,并通过依赖管理管理合适的Kotlin版本。要使用kotlin,类路径上必须存在org.jetbrains.kotlin:kotlin-stdlib
和org.jetbrains.kotlin:kotlin-reflect
。也可以使用kotlin-stdlib
变体kotlin-stdlib-jdk7
和kotlin-stdlib-jdk8
。
由于kotlin类在默认情况下是最终的,因此您可能希望配置kotlin-Spring插件,以便自动打开带Spring注释的类,以便可以代理它们。
在Kotlin中序列化/反序列化JSON数据需要Jackson的Kotlin模块。当在类路径上找到它时,它会自动注册。如果杰克逊和科特林存在,但杰克逊·科特林模块不存在,则会记录一条警告消息。
These dependencies and plugins are provided by default if one bootstraps a Kotlin project on start.spring.io. |
10.2. Null-safety
Kotlin的主要功能之一是空安全。它在编译时处理NULL
值,而不是将问题推迟到运行时并遇到NullPointerException
。这有助于消除常见的错误来源,而无需支付像可选
这样的包装器的成本。Kotlin还允许使用具有可空值的函数构造,如Kotlin中的空安全综合指南中所述。
尽管Java不允许在其类型系统中表示空安全,但Spring框架、Spring data和Reader现在通过工具友好的注释为它们的API提供了空安全。默认情况下,Kotlin中使用的Java API的类型被识别为放宽了空检查的平台类型。Kotlin对JSR 305批注的支持与可为空性批注相结合,为Kotlin中的相关Spring API提供了空安全性。
可以通过添加带有以下选项的-Xjsr305
编译器标志来配置JSR305检查:-Xjsr305={STRICT|WARN|IGNORE}
。默认行为与-Xjsr305=warn
相同。为了在从Spring API推断的Kotlin类型中考虑空安全性,Strong
值是必需的,但在使用时应该知道,即使在次要版本之间也可能演变Spring API的为空性声明,并且将来可能会添加更多检查)。
Generic type arguments, varargs and array elements nullability are not yet supported. See SPR-15942 for up-to-date information. Also be aware that Spring Boot’s own API is not yet annotated. |
10.3. Kotlin API
10.3.1. runApplication
Spring Boot提供了一种使用runApplication<;MyApplication>;(*args)
运行应用程序的惯用方法,如以下示例所示:
@SpringBootApplication class MyApplication fun main(args: Array<String>) { runApplication<MyApplication>(*args) }
这是SpringApplication.run(MyApplication::class.java,*args的临时替代品)
。它还允许定制应用程序,如下例所示:
runApplication<MyApplication>(*args) { setBannerMode(OFF) }
10.3.2. Extensions
Kotlin扩展提供了使用附加功能扩展现有类的能力。Spring Boot Kotlin API利用这些扩展将特定于Kotlin的新功能添加到现有API中。
TestRestTemplate
扩展,类似于Spring框架中的RestOperations
提供的扩展。除了其他功能外,这些扩展还使利用Kotlin实例化类型参数成为可能。
10.4. Dependency management
为了避免在类路径上混合不同版本的Kotlin依赖项,Spring Boot导入了Kotlin BOM。
使用Maven,可以通过设置kotlin.Version
属性定制kotlin版本,并为kotlin-maven-plugin
提供插件管理。使用Gradle,Spring Boot插件会自动将kotlin.version
与Kotlin插件的版本对齐。
Spring Boot还通过导入Kotlin Coroutines BOM来管理协程依存关系的版本。可以通过设置kotlin-coroutines.Version
属性来自定义版本。
org.jetbrains.kotlinx:kotlinx-coroutines-reactor dependency is provided by default if one bootstraps a Kotlin project with at least one reactive dependency on start.spring.io. |
10.5. @ConfigurationProperties
@ConfigurationProperties
与构造函数绑定配合使用时,支持具有不可变的val
属性的类,如下例所示:
@ConfigurationProperties("example.kotlin")
data class KotlinExampleProperties(
val name: String,
val description: String,
val myService: MyService) {
data class MyService(
val apiToken: String,
val uri: URI
)
}
To generate your own metadata using the annotation processor, kapt should be configured with the spring-boot-configuration-processor dependency. Note that some features (such as detecting the default value or deprecated items) are not working due to limitations in the model kapt provides. |
10.6. Testing
虽然可以使用JUnit4测试Kotlin代码,但默认情况下会提供JUnit5,建议使用JUnit5。JUnit5允许一个测试类实例化一次,然后在类的所有测试中重复使用。这使得在非静态方法上使用@BeForeAll
和@After All
注释成为可能,这非常适合Kotlin。
要模拟Kotlin类,建议使用MockK。如果您需要与特定于Mockito的@MockBean
和@SpyBean
批注对应的Mockk
,您可以使用提供类似@MockkBean
和@SpykBean
批注的SpringMockK。
10.7. Resources
10.7.2. Examples
-
Spring-boot-kotlin-demo:常规Spring Boot+Spring data JPA项目
-
Mixit:Spring Boot 2+WebFlux+反应式Spring数据MongoDB
-
Spring-kotlin-fullstack:使用kotlin2js作为前端的WebFlux kotlin全栈示例,而不是使用脚本或打字脚本
-
Spring-petClinic-kotlin:Spring PetClinic示例应用程序的kotlin版本
-
从Boot 1.0+Java到Boot 2.0+Kotlin的分步迁移
-
Spring-boot-coroutines-demo:coroutines示例项目
11. What to Read Next
如果您想了解本节中讨论的任何类的更多信息,请参阅Spring Boot API文档,或者可以直接浏览源代码。如果您有特定的问题,请参阅操作方法部分。
如果您对Spring Boot的核心特性感到满意,可以继续阅读生产就绪特性。