没有腹肌的西瓜 · JEECG技术论坛 - 基于BPM的低代码开发平台· 2 天前 · |
直爽的黑框眼镜 · 无法访问org.apache.lucene. ...· 1 月前 · |
茫然的茶叶 · 内乡县高级中学_百度百科· 4 月前 · |
稳重的警车 · Research on the ...· 6 月前 · |
挂过科的熊猫 · Vue-grid-layout实现web拖拽 ...· 11 月前 · |
刚毅的硬币 · 【百度云资源分享】しゃべくり007 ...· 11 月前 · |
spring自定义注解 log文件 yaml bean |
http://docs.jcohy.com/docs/spring-boot/2.2.5.RELEASE/html5/zh-cn/spring-boot-features.html |
悲伤的山羊
10 月前 |
@ConfigurationProperties
注解的类型
@ConfigurationProperties
注解类型
@ConfigurationProperties
与
@Value
对比
RSocketRequester
调用RSocket服务
public static void main(String[] args) {
SpringApplication.run(MySpringConfiguration.class, args);
当应用启动时,您应该会看到类似以下的内容输出:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: v2.2.5.RELEASE
2019-04-31 13:09:54.117 INFO 56603 --- [ main] o.s.b.s.app.SampleApplication : Starting SampleApplication v0.1.0 on mycomputer with PID 56603 (/apps/myapp.jar started by pwebb)
2019-04-31 13:09:54.166 INFO 56603 --- [ main] ationConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6e5a8246: startup date [Wed Jul 31 00:08:16 PDT 2013]; root of context hierarchy
2019-04-01 13:09:56.912 INFO 41370 --- [ main] .t.TomcatServletWebServerFactory : Server initialized with port: 8080
2019-04-01 13:09:57.501 INFO 41370 --- [ main] o.s.b.s.app.SampleApplication : Started SampleApplication in 2.992 seconds (JVM running for 3.658)
默认情况下,将显示 INFO
级别的日志信息,包括一些应用启动相关信息. 如果您需要修改 INFO
日志级别,请参考日志等级.
使用主应用程序类包中的实现版本来确定应用程序版本. 可以通过将 spring.main.log-startup-info
设置为 false
来关闭启动信息记录. 这还将关闭对应用程序 active 配置文件的日志记录.
如果没有失败分析器能够处理的异常,您仍然可以显示完整的条件报告以便更好地了解出现的问题. 为此,您需要针对 org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
启用 debug
属性 或者开启 DEBUG
日志.
例如,如果您使用 java -jar
运行应用,可以按以下方式启用 debug
属性:
$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug
1.2. 延迟初始化
SpringApplication
允许延迟地初始化应用程序. 启用延迟初始化后,将根据需要创建bean,而不是在应用程序启动期间创建bean. 因此,启用延迟初始化可以减少应用程序启动所需的时间. 在Web应用程序中,启用延迟初始化将导致许多与Web相关的Bean直到收到HTTP请求后才被初始化.
延迟初始化的缺点是,它可能会延迟发现应用程序问题的时间. 如果错误配置的Bean延迟初始化,则启动期间将不再发生故障,并且只有在初始化Bean时问题才会变得明显. 还必须注意确保JVM有足够的内存来容纳所有应用程序的bean,而不仅仅是启动期间初始化的bean. 由于这些原因,默认情况下不会启用延迟初始化,因此建议在启用延迟初始化之前先对JVM的堆大小进行微调.
可以使用 SpringApplicationBuilder
上的 lazyInitialization
方法或 SpringApplication
上的 setLazyInitialization
方法以编程方式启用延迟初始化. 另外,可以使用 spring.main.lazy-initialization
属性启用它,如以下示例所示:
spring.main.lazy-initialization=true
1.3. 自定义 banner
可以通过在 classpath 下添加一个 banner.txt
文件,或者将 spring.banner.location
属性指向该文件的位置来更改启动时打印的 banner. 如果文件采用了非 UTF-8 编码,您可以设置 spring.banner.charset
来解决. 除了文本文件,
您还可以将 banner.gif
、banner.jpg
或者 banner.png
图片文件添加到 classpath 下,或者设置 spring.banner.image.location
属性. 指定的图片将会被转换成 ASCII 形式并打印在 banner 文本上方.
您可以在 banner.txt
文件中使用以下占位符:
Table 1. Banner 变量
${application.version}
您的应用版本号,声明在 MANIFEST.MF
中. 例如,Implementation-Version: 1.0
将被打印为 1.0
.
${application.formatted-version}
您的应用版本号,声明在 MANIFEST.MF
中,格式化之后打印 (用括号括起来,以 v
为前缀) ,例如 (v1.0
).
${spring-boot.version}
您使用的 Spring Boot 版本. 例如 2.2.5.RELEASE
.
${spring-boot.formatted-version}
您使用的 Spring Boot 版本格式化之后显示 (用括号括起来,以 v
为前缀) . 例如 (v2.2.5.RELEASE)
.
${Ansi.NAME}
(or ${AnsiColor.NAME}
, ${AnsiBackground.NAME}
, ${AnsiStyle.NAME}
)
其中 NAME
是 ANSI 转义码的名称. 有关详细信息,请参阅 AnsiPropertySource
.
${application.title}
您的应用标题,声明在 MANIFEST.MF
中,例如 Implementation-Title: MyApp
打印为 MyApp
.
您还可以使用 spring.main.banner-mode
属性来确定是否必须在 System.out
(console
) 上打印 banner,还是使用日志记录器 (log
)或者都不打印(off
).
打印的 banner 被注册名为 springBootBanner
的单例 bean.
1.4. 自定义 SpringApplication
如果 SpringApplication
的默认设置不符合您的想法,您可以创建本地实例进行定制化. 例如,要关闭 banner,您可以这样:
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MySpringConfiguration.class);
app.setBannerMode(Banner.Mode.OFF);
app.run(args);
1.5. Fluent Builder API
如果您需要构建一个有层级关系的 ApplicationContext
(具有父/子关系的多上下文) ,或者偏向使用 fluent (流式) 构建器 API,可以使用 SpringApplicationBuilder
.
SpringApplicationBuilder
允许您链式调用多个方法,包括能创建出具有层次结构的 parent
和 child
方法.
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);
在 ApplicationContext
创建之前,实际上触发了一些事件,因此您不能像 @Bean
一样注册监听器. 您可以通过 SpringApplication.addListeners(…)
或者 SpringApplicationBuilder.listeners(…)
方法注册它们.
如果您希望无论应用使用何种创建方式都能自动注册这些监听器,您都可以将 META-INF/spring.factories
文件添加到项目中,并使用 org.springframework.context.ApplicationListener
属性键指向您的监听器.
比如: org.springframework.context.ApplicationListener=com.example.project.MyListener
org.springframework.context.ApplicationListener=com.example.project.MyListener
准备 ApplicationContext
并调用 ApplicationContextInitializers
之后但在加载任何bean定义之前,将发送 ApplicationContextInitializedEvent
.
开始刷新之前,bean 定义被加载之后发送 ApplicationPreparedEvent
.
在上下文刷新之后且所有的应用和命令行运行器 (command-line runner) 被调用之前发送 ApplicationStartedEvent
.
在应用程序和命令行运行器 (command-line runner) 被调用之后,将发出 ApplicationReadyEvent
,该事件用于通知应用已经准备处理请求.
如果启动时发生异常,将发送 ApplicationFailedEvent
.
应用程序事件发送使用了 Spring Framework 的事件发布机制. 该部分机制确保在子上下文中发布给监听器的事件也会发布给所有祖先上下文中的监听器. 因此,如果您的应用程序使用有层级结构的 SpringApplication
实例,则监听器可能会收到同种类型应用程序事件的多个实例.
为了让监听器能够区分其上下文事件和后代上下文事件,您应该注入其应用程序上下文,然后将注入的上下文与事件的上下文进行比较. 可以通过实现 ApplicationContextAware
来注入上下文,如果监听器是 bean,则使用 @Autowired
注入上下文.
1.7. Web 环境
SpringApplication
试图为您创建正确类型的 ApplicationContext
. 确定 WebApplicationType
的算法非常简单:
如果 Spring MVC 不存在且存在 Spring WebFlux,则使用 AnnotationConfigReactiveWebServerApplicationContext
否则,使用 AnnotationConfigApplicationContext
这意味着如果您在同一个应用程序中使用了 Spring MVC 和 Spring WebFlux 中的新 WebClient
,默认情况下将使用 Spring MVC. 您可以通过调用 setWebApplicationType(WebApplicationType)
修改默认行为.
也可以调用 setApplicationContextClass(…)
来完全控制 ApplicationContext
类型.
import org.springframework.boot.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.stereotype.*;
@Component
public class MyBean {
@Autowired
public MyBean(ApplicationArguments args) {
boolean debug = args.containsOption("debug");
List<String> files = args.getNonOptionArgs();
// if run with "--debug logfile.txt" debug=true, files=["logfile.txt"]
1.9. 使用 ApplicationRunner 或 CommandLineRunner
如果您需要在 SpringApplication
启动时运行一些代码,可以实现 ApplicationRunner
或者 CommandLineRunner
接口. 这两个接口的工作方式是一样的,都提供了一个单独的 run
方法,它将在 SpringApplication.run(…)
完成之前调用.
CommandLineRunner
接口提供了访问应用程序字符串数组形式参数的方法,而 ApplicationRunner
则使用了上述的 ApplicationArguments
接口. 以下示例展示 CommandLineRunner
和 run
方法的使用:
import org.springframework.boot.*;
import org.springframework.stereotype.*;
@Component
public class MyBean implements CommandLineRunner {
public void run(String... args) {
// Do something...
如果您定义了多个 CommandLineRunner
或者 ApplicationRunner
bean,则必须指定调用顺序,您可以实现 org.springframework.core.Ordered
接口,也可以使用 org.springframework.core.annotation.Order
注解解决顺序问题.
1.10. 应用程序退出
每个 SpringApplication
注册了一个 JVM 关闭钩子,以确保 ApplicationContext
在退出时可以优雅关闭. 所有标准的 Spring 生命周期回调 (比如 DisposableBean
接口,或者 @PreDestroy
注解) 都可以使用.
此外,如果希望在调用 SpringApplication.exit()
时返回特定的退出码,则 bean 可以实现 org.springframework.boot.ExitCodeGenerator
接口. 之后退出码将传递给 System.exit()
以将其作为状态码返回,如示例所示:
@SpringBootApplication
public class ExitCodeApplication {
@Bean
public ExitCodeGenerator exitCodeGenerator() {
return () -> 42;
public static void main(String[] args) {
System.exit(SpringApplication.exit(SpringApplication.run(ExitCodeApplication.class, args)));
此外,ExitCodeGenerator
接口可以通过异常实现. 遇到这类异常时,Spring Boot 将返回实现的 getExitCode()
方法提供的退出码.
1.11. 管理功能
可以通过指定 spring.application.admin.enabled
属性来为应用程序启用管理相关的功能. 其将在 MBeanServer
平台上暴露 SpringApplicationAdminMXBean
. 您可以使用此功能来远程管理 Spring Boot 应用. 该功能对服务包装器的实现也是非常有用的.
Spring Boot 可以让您的配置外部化,以便可以在不同环境中使用相同的应用程序代码. 您可以使用 properties 文件、YAML 文件、环境变量或者命令行参数来外部化配置. 可以使用 @Value
注解将属性值直接注入到 bean 中,可通过 Spring 的 Environment
访问,
或者通过 @ConfigurationProperties
绑定到结构化对象.
Spring Boot 使用了一个非常特别的 PropertySource
指令,用于智能覆盖默认值. 属性将按照以下顺序处理:
在 @Configuration
类上的 @PropertySource
注解.
请注意,在刷新应用程序上下文之前,不会将此类属性源添加到环境中. 现在配置某些属性 (如 logging.
和 spring.main.
) 为时已晚,这些属性在刷新开始之前就已读取.
默认属性 (使用 SpringApplication.setDefaultProperties
指定) .
import org.springframework.stereotype.*;
import org.springframework.beans.factory.annotation.*;
@Component
public class MyBean {
@Value("${name}")
private String name;
// ...
在您的应用程序的 classpath 中 (比如在 jar 中) ,您可以有一个 application.properties
,它为 name 提供了一个合适的默认属性值. 当在新环境中运行时,您可以在 jar 外面提供一个 application.properties
来覆盖 name
. 对于一次性测试,您可以使用命令行指定形式启动 (比如 java -jar app.jar --name="Spring"
) .
my.bignumber=${random.long}
my.uuid=${random.uuid}
my.number.less.than.ten=${random.int(10)}
my.number.in.range=${random.int[1024,65536]}
random.int*
语法为 OPEN value (,max) CLOSE
,OPEN,CLOSE
可为任意字符,value,max
为整数. 如果使用了 max
,value
则为最小值,max
为最大值.
2.2. 访问命令行属性
默认情况下,SpringApplication
将所有命令行选项参数 (即以 --
开头的参数,比如 --server.port=9000
) 转换为属性,并将它们添加到 Spring Environment
中. 如之前所述,命令行属性始终优先于其他属性源.
如果您不希望将命令行属性添加到 Environment
,可以使用 SpringApplication.setAddCommandLineProperties(false)
来禁用它们.
2.3. 应用程序属性文件
SpringApplication
从以下位置的 application.properties
文件中加载属性 (properties) ,并将它们添加到 Spring Environment
中:
SpringApplication
loads properties from application.properties
files in the following locations and adds them to the Spring Environment
:
如果您不喜欢 application.properties
作为配置文件名,则可以通过指定 spring.config.name
环境属性来切换到另一个文件名. 您还可以使用 spring.config.location
环境属性来引用一个显式位置 (以逗号分隔的目录位置或文件路径列表) .
以下示例展示了如何指定其他文件名:
$ java -jar myproject.jar --spring.config.name=myproject
以下示例展示了如何指定两个位置:
$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties
如果 spring.config.location
包含目录 (而不是文件) ,则它们应该以 /
结尾 (并且在运行期间,在加载之前追加从 spring.config.name
生成的名称,包括指定 profile 的文件名) .
spring.config.location
中指定的文件按原样使用,不支持指定 profile 形式,并且可被任何指定 profile 的文件的属性所覆盖.
配置位置以相反的顺序搜索. 默认情况下,配置的位置为 classpath:/,classpath:/config/,file:./,file:./config/
. 生成的搜索顺序如下:
2.4. 特定 Profile 的属性文件
除 application.properties
文件外,还可以使用以下命名约定定义特定 profile 的属性文件: application-{profile}.properties. Environment 有一组默认配置文件 (默认情况下为 default
) ,如果未设置激活的 (active) profile,则使用这些配置文件. 换句话说,如果没有显式激活 profile,则会加载 application-default.properties
中的属性.
特定 profile 的属性文件从与标准 application.properties
相同的位置加载,特定 profile 的属性文件无论是否在打包的 jar 内部,都始终覆盖非特定文件.
如果指定了多个配置文件,则应用 last-wins 策略 (优先采取最后一个) . 例如,spring.profiles.active
属性指定的配置文件是在使用 SpringApplication
API 配置的配置文件之后添加的,因此优先应用.
2.6. 加密属性
Spring Boot 没有为加密属性值提供任何内置支持,然而,它提供了修改 Spring Environment
包含的值所必需的钩子. EnvironmentPostProcessor
接口允许您在应用程序启动之前操作 Environment.
有关详细信息,请参见 在启动前自定义 Environment 或 ApplicationContext .
如果您正在寻找一种可用于存储凭据和密码的安全方法, Spring Cloud Vault 项目支持在 HashiCorp Vault 中存储外部化配置.
2.7. 使用 YAML 代替属性文件
YAML 是 JSON 的超集,是一个可用于指定层级配置数据的便捷格式. 只要在 classpath 上有 SnakeYAML 库,SpringApplication
类就会自动支持 YAML 作为属性文件 (properties) 的替代.
2.7.1. 加载 YAML
Spring Framework 提供了两个便捷类,可用于加载 YAML 文档. YamlPropertiesFactoryBean
将 YAML 加载为 Properties
,YamlMapFactoryBean
将 YAML 加载为 Map
.
例如以下 YAML 文档:
environments:
url: https://dev.example.com
name: Developer Setup
prod:
url: https://another.example.com
name: My Cool App
前面的示例将转换为以下属性 (properties) :
environments.dev.url=https://dev.example.com
environments.dev.name=Developer Setup
environments.prod.url=https://another.example.com
environments.prod.name=My Cool App
YAML 列表表示带有 [index]
下标引用的属性键. 例如以下 YAML:
servers:
- dev.example.com
- another.example.com
以上示例将转成以下属性:
my.servers[0]=dev.example.com
my.servers[1]=another.example.com
要使用 Spring Boot 的 Binder 工具来绑定这样配置到属性 (这是 @ConfigurationProperties
所做的) ,你需要在目标 bean 中有一个 java.util.List
(或 Set
) 类型的属性,你需要为其提供一个 setter 或者使用可变值初始化它. 例如,以下示例展示将上述的配置与属性绑定:
@ConfigurationProperties(prefix="my")
public class Config {
private List<String> servers = new ArrayList<String>();
public List<String> getServers() {
return this.servers;
在前面示例中,如果 development
profile 处于激活状态,则 server.address
属性得值为 127.0.0.1
. 同样,如果 production
和 eu-central
profile 处于激活状态,则 server.address
属性的值为 192.168.1.120
.
如果未激活 development
、production
或 eu-central
profile,则该属性的值为 192.168.1.100
.
因此,spring.profiles
可以包含一个简单的 profile 名称 (例如 production
) 或一个 profile 表达式. profile 表达式允许表达更复杂的 profile 逻辑,例如 production & (eu-central | eu-west)
. 有关详细信息,请查阅http://docs.jcohy.com/zh-cn/spring-framework/5.2.4.RELEASE/spring-framework-reference/index.htmlcore.html#beans-definition-profiles-java[reference guide].
2.7.4. YAML 的缺点
无法使用 @PropertySource
注解加载 YAML 文件. 因此,如果您需要以这种方式加载值,请使用属性文件 (properties) .
在特定于配置文件的YAML文件中使用多YAML文档语法可能会导致意外行为. 例如,考虑文件中的以下配置:
application-dev.yml
server:
port: 8000
spring:
profiles: "!test"
security:
user:
password: "secret"
如果使用参数 --spring.profiles.active=dev
运行该应用程序,则可能希望将 security.user.password
设置为 “secret”,但事实并非如此.
嵌套文档将被过滤,因为主文件名为 application-dev.yml
. 它已经被认为是特定于配置文件的,并且嵌套文档将被忽略.
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("acme")
public class AcmeProperties {
private boolean enabled;
private InetAddress remoteAddress;
private final Security security = new Security();
public boolean isEnabled() { ... }
public void setEnabled(boolean enabled) { ... }
public InetAddress getRemoteAddress() { ... }
public void setRemoteAddress(InetAddress remoteAddress) { ... }
public Security getSecurity() { ... }
public static class Security {
private String username;
private String password;
private List<String> roles = new ArrayList<>(Collections.singleton("USER"));
public String getUsername() { ... }
public void setUsername(String username) { ... }
public String getPassword() { ... }
public void setPassword(String password) { ... }
public List<String> getRoles() { ... }
public void setRoles(List<String> roles) { ... }
前面的 POJO 定义了以下属性:
acme.security.username
, 内嵌一个 security
对象,其名称由属性名称决定. 特别是,返回类型根本没有使用,可能是 SecurityProperties
.
acme.security.password
.
acme.security.roles
, String
集合. 默认为 USER
.
Spring Boot自动配置大量使用 @ConfigurationProperties
来轻松配置自动配置的bean. 与自动配置类相似,Spring Boot中可用的 @ConfigurationProperties
类仅供内部使用. 通过属性文件,YAML文件,环境变量等配置的映射到该类的属性是公共API,
但是该类本身的内容并不意味着可以直接使用.
集合和数组可以通过一个索引 (通常使用 YAML) 或使用单个逗号分隔值 (属性) 进行访问. 最后一种情况必须使用 setter. 我们建议始终为此类型添加 setter. 如果初始化集合,请确保它是可变的 (如上例所示) .
如果初始化嵌套的 POJO 属性 (如前面示例中的 Security
字段) ,则不需要 setter. 如果您希望 binder 使用其默认构造函数动态创建实例,则需要一个 setter.
有些人可能会使用 Project Lombok 来自动生成 getter 和 setter. 请确保 Lombok 不为此类型生成任何特定构造函数,因为容器会自动使用它来实例化对象.
最后,考虑到标准 Java Bean 属性,不支持对静态属性的绑定.
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
import org.springframework.boot.context.properties.DefaultValue;
@ConstructorBinding
@ConfigurationProperties("acme")
public class AcmeProperties {
private final boolean enabled;
private final InetAddress remoteAddress;
private final Security security;
public AcmeProperties(boolean enabled, InetAddress remoteAddress, Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
public boolean isEnabled() { ... }
public InetAddress getRemoteAddress() { ... }
public Security getSecurity() { ... }
public static class Security {
private final String username;
private final String password;
private final List<String> roles;
public Security(String username, String password,
@DefaultValue("USER") List<String> roles) {
this.username = username;
this.password = password;
this.roles = roles;
public String getUsername() { ... }
public String getPassword() { ... }
public List<String> getRoles() { ... }
在此设置中,@ConstructorBinding
注解用于指示应使用构造函数绑定. 这意味着绑定器将期望找到带有您希望绑定的参数的构造函数.
@ConstructorBinding
类的嵌套成员 (例如上例中的 Security
) 也将通过其构造函数进行绑定.
可以使用 @DefaultValue
指定默认值,并且将应用相同的转换服务将 String
值强制为缺少属性的目标类型.
2.8.3. 启用 @ConfigurationProperties
注解的类型
Spring Boot提供了绑定 @ConfigurationProperties
类型并将其注册为Bean的基础架构. 您可以逐类启用配置属性,也可以启用与组件扫描类似的方式进行配置属性扫描.
有时,用 @ConfigurationProperties
注解的类可能不适用于扫描,例如,如果您正在开发自己的自动配置,或者想要有条件地启用它们. 在这些情况下,请使用 @EnableConfigurationProperties
注解 指定要处理的类型列表. 可以在任何 @Configuration
类上完成此操作,如以下示例所示:
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(AcmeProperties.class)
public class MyConfiguration {
要使用配置属性扫描,请将 @ConfigurationPropertiesScan
注解 添加到您的应用程序. 通常,它被添加到使用 @SpringBootApplication
注解的主应用程序类中,但可以将其添加到任何 @Configuration
类中.
默认情况下,将从声明注解的类的包中进行扫描. 如果要定义要扫描的特定程序包,可以按照以下示例所示进行操作:
@SpringBootApplication
@ConfigurationPropertiesScan({ "com.example.app", "org.acme.another" })
public class MyApplication {
当以这种方式注册 @ConfigurationProperties
bean 时,bean 具有一个固定格式的名称: <prefix>-<fqn>
,其中 <prefix> 是 @ConfigurationProperties
注解中指定的环境 key 前缀,<fqn>
是 bean 的完全限定类名. 如果注解未提供任何前缀,则仅使用 bean 的完全限定类名.
上面示例中的 bean 名称为 acme-com.example.AcmeProperties
.
即使前面的配置为 AcmeProperties
创建了一个 bean,我们也建议 @ConfigurationProperties
只处理环境 (environment) ,特别是不要从上下文中注入其他 bean.
对于极端情况,可以使用setter注入或框架提供的任何 *Aware
接口 (例如,需要访问 Environment
的 EnvironmentAware
) . 如果仍然想使用构造函数注入其他bean,则必须使用 @Component
注解配置属性bean,并使用基于JavaBean的属性绑定.
2.8.4. 使用 @ConfigurationProperties
注解类型
这种配置样式与 SpringApplication
外部YAML配置特别有效,如以下示例所示:
# application.yml
acme:
remote-address: 192.168.1.1
security:
username: admin
roles:
- USER
- ADMIN
# additional configuration as required
要使用 @ConfigurationProperties
bean,您可以使用与其他 bean 相同的方式注入它们,如下所示:
@Service
public class MyService {
private final AcmeProperties properties;
@Autowired
public MyService(AcmeProperties properties) {
this.properties = properties;
//...
@PostConstruct
public void openConnection() {
Server server = new Server(this.properties.getRemoteAddress());
// ...
2.8.5. 第三方配置
@ConfigurationProperties
除了可以使用来注解类之外,您还可以在公共的 @Bean
方法上使用. 当您想要将属性绑定到您掌控之外的第三方组件时,这样做特别有用.
要使用 Environment
属性配置 bean,请将 @ConfigurationProperties
添加到 bean 注册上,如下所示:
@ConfigurationProperties(prefix = "another")
@Bean
public AnotherComponent anotherComponent() {
使用 another
前缀定义的所有属性都使用与前面的 AcmeProperties
示例类似的方式映射到 AnotherComponent
bean.
2.8.6. 宽松绑定
Spring Boot 使用一些宽松的规则将 Environment
属性绑定到 @ConfigurationProperties
bean,因此 Environment
属性名不需要和 bean 属性名精确匹配.
常见的示例包括使用了 -
符号分割的环境属性 (例如,context-path
绑定到 contextPath
) 和大写环境属性 (例如,PORT
绑定到 port
) .
如下 @ConfigurationProperties
类:
@ConfigurationProperties(prefix="acme.my-project.person")
public class OwnerProperties {
private String firstName;
public String getFirstName() {
return this.firstName;
public void setFirstName(String firstName) {
this.firstName = firstName;
在上述示例中,同样可以使用以下属性名称:
Table 2. 宽松绑定
如果 dev
配置文件未激活,则 AcmeProperties.list
只包含一条 MyPojo
条目,如之前所述. 但是,如果激活了 dev
配置文件,列表集合仍然只包含一个条目 (name 属性值为 my another name
,description 为 null
) .
此配置不会向列表集合中添加第二个 MyPojo
实例,也不会合并条目.
在多个配置文件中指定一个 List
时,最高优先级 (并且只有一个) 的列表集合将被使用. 可做如下配置:
acme:
list:
- name: my name
description: my description
- name: another name
description: another description
spring:
profiles: dev
acme:
list:
- name: my another name
在前面示例中,如果 dev
配置文件处于 active 状态,则 AcmeProperties.list
包含一个 MyPojo
条目 (name 为 my another name
,description 为 null
) . 对于 YAML 而言,逗号分隔的列表和YAML 列表同样会完全覆盖列表集合的内容.
对于 Map 属性,您可以绑定来自多个源中提取的属性值. 但是,对于多个源中的相同属性,则使用高优先级最高的属性. 以下示例从 AcmeProperties
暴露了一个 Map<String, MyPojo>
:
@ConfigurationProperties("acme")
public class AcmeProperties {
private final Map<String, MyPojo> map = new HashMap<>();
public Map<String, MyPojo> getMap() {
return this.map;
可以考虑以下配置:
acme:
key1:
name: my name 1
description: my description 1
spring:
profiles: dev
acme:
key1:
name: dev name 1
key2:
name: dev name 2
description: dev description 2
如果 dev
配置文件未激活,则 AcmeProperties.map
只包含一个带 key1
key 的条目 (name 为 my name 1
,description 为 my description 1
) .
如果激活了 dev
配置文件,则 map 将包含两个条目, key 分别为 key1
(name 为 dev name 1
和 description 为 my description 1
) 和 key2
(name 为 dev name 2
和 description 为 dev description 2
) .
@DurationUnit(ChronoUnit.SECONDS)
private Duration sessionTimeout = Duration.ofSeconds(30);
private Duration readTimeout = Duration.ofMillis(1000);
public Duration getSessionTimeout() {
return this.sessionTimeout;
public void setSessionTimeout(Duration sessionTimeout) {
this.sessionTimeout = sessionTimeout;
public Duration getReadTimeout() {
return this.readTimeout;
public void setReadTimeout(Duration readTimeout) {
this.readTimeout = readTimeout;
指定一个会话超时时间为 30
秒,使用 30
、PT30S
和 30s
等形式都是可以的. 读取超时时间设置为 500ms
,可以采用以下任何一种形式: 500
、PT0.5S
和 500ms
.
您也可以使用任何支持的单位来标识:
private DataSize bufferSize = DataSize.ofMegabytes(2);
private DataSize sizeThreshold = DataSize.ofBytes(512);
public DataSize getBufferSize() {
return this.bufferSize;
public void setBufferSize(DataSize bufferSize) {
this.bufferSize = bufferSize;
public DataSize getSizeThreshold() {
return this.sizeThreshold;
public void setSizeThreshold(DataSize sizeThreshold) {
this.sizeThreshold = sizeThreshold;
要指定 10
兆字节的缓冲大小,使用 10
和 10MB
是等效的. 256
字节的大小可以指定为 256
或 256B
.
您也可以使用任何支持的单位:
您还可以通过创建一个名为 configurationPropertiesValidator
的 bean 定义来添加自定义 Spring Validator
. 应该将 @Bean 方法声明为 static
.
配置属性验证器在应用程序生命周期的早期创建,将 @Bean
方法声明为 static
可以无需实例化 @Configuration
类来创建 bean. 这样做可以避免早期实例化可能导致的意外问题. 这里有一个属性验证示例,讲解了如何设置.
如果您要为自己的组件定义一组配置 key,我们建议您将它们分组到使用 @ConfigurationProperties
注解的 POJO 中. 您应该知道,由于 @Value
不支持宽松绑定,因此如果您需要通过环境变量来提供值,它并不是一个好的选择.
最后,虽然您可以在 @Value
中编写 SpEL 表达式,但来自应用程序属性文件的此类表达式并不会被处理.
@Configuration(proxyBeanMethods = false)
@Profile("production")
public class ProductionConfiguration {
// ...
如果 @ConfigurationProperties
Bean是通过 @EnableConfigurationProperties
而非自动扫描注册的,则需要在 @EnableConfigurationProperties
注解的 @Configuration
类上指定 @Profile
注解.
在扫描 @ConfigurationProperties
的情况下,可以在 @ConfigurationProperties
类本身上指定 @Profile
.
3.1. 添加激活 Profile
spring.profiles.active
属性遵循与其他属性相同的排序规则: 应用优先级最高的 PropertySource
. 这意味着您可以在 application.properties
中指定激活配置文件,然后使用命令行开关替换它们.
有时,将特定 profile 的属性添加到激活配置文件而不是替换它们,这种方式也是很有用的. spring.profiles.include
属性可无条件地添加激活配置文件. SpringApplication
入口还有一个 Java API,用于设置其他 profile (即,在 spring.profiles.active
属性激活的 profile 之上) . 请参阅 SpringApplication 中的 setAdditionalProfiles()
方法.
例如,当使用开关 --spring.profiles.active=prod
运行有以下属性的应用程序时,proddb
和 prodmq
配置文件也会被激活:
my.property: fromyamlfile
spring.profiles: prod
spring.profiles.include:
- proddb
- prodmq
Spring Boot 使用 Commons Logging 记录所有内部日志,但开放日志的底层实现. 其为 Java Util Logging, Log4J2 和 Logback 提供了默认配置. 在每种情况下,日志记录器都预先配置为使用控制台输出,并且还提供可选的文件输出.
默认情况下,如果您使用了 Starter
,则使用 Logback 进行日志记录. 还包括合适的 Logback 路由,以确保在使用 Java Util Logging、Commons Logging、Log4J 或 SLF4J 的依赖库都能正常工作.
2019-03-05 10:57:51.112 INFO 45469 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/7.0.52
2019-03-05 10:57:51.253 INFO 45469 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-03-05 10:57:51.253 INFO 45469 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1358 ms
2019-03-05 10:57:51.698 INFO 45469 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2019-03-05 10:57:51.702 INFO 45469 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
输出以下项:
启用调试模式后,核心日志记录器 (内嵌容器、Hibernate 和 Spring Boot) 将被配置为输出更多日志信息. 启用调试模式不会将应用程序配置为使用 DEBUG
级别记录所有日志内容.
或者,您可以通过使用 --trace
标志 (或在 application.properties
中的设置 trace=true
) 启动应用程序来启用跟踪模式. 这样做可以为选择的核心日志记录器 (内嵌容器、Hibernate 模式生成和整个 Spring 组合) 启用日志追踪.
4.2.1. 着色输出
如果您的终端支持 ANSI,则可以使用颜色输出来提高可读性. 您可以将 spring.output.ansi.enabled
设置为 受支持的值 以覆盖自动检测.
可使用 %clr
转换字配置颜色编码. 最简单形式是,转换器根据日志级别对输出进行着色,如下所示:
%clr(%5p)
下表描述日志级别与颜色的映射关系:
4.3. 文件输出
默认情况下,Spring Boot 仅记录到控制台,不会写入日志文件. 想除了控制台输出之外还要写入日志文件,则需要设置 logging.file
或 logging.path
属性 (例如,在 application.properties
中) .
下表展示了如何与 logging.*
属性一起使用:
Table 4. Logging 属性
日志文件在达到 10MB
时会轮转,并且与控制台输出一样,默认情况下会记录 ERROR
、WARN
和 INFO
级别的内容. 可以使用 logging.file.max-size
属性更改大小限制.
除非已设置 logging.file.max-history
属性,否则默认情况下将保留最近7天的轮转日志文件.
可以使用 logging.file.total-size-cap
限制日志归档文件的总大小. 当日志归档的总大小超过该阈值时,将删除备份. 要在应用程序启动时强制清除日志归档文件,请使用 logging.file.clean-history-on-start
属性.
4.4. 日志等级
所有受支持的日志记录系统都可以使用 logging.level.<logger-name>=<level>
来设置 Spring Environment
中的记录器等级 (例如,在 application.properties
中) . 其中 level 是 TRACE
、DEBUG
、INFO
、WARN
、ERROR
、FATAL
和 OFF
其中之一. 可以使用 logging.level.root
配置 root
记录器.
以下示例展示了 application.properties
中默认的日志记录设置:
logging.level.root=warn
logging.level.org.springframework.web=debug
logging.level.org.hibernate=error
也可以使用环境变量设置日志记录级别. 例如, LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_WEB=DEBUG
会将 org.springframework.web
设置为 DEBUG
.
org.springframework.core.codec
, org.springframework.http
, org.springframework.web
, org.springframework.boot.actuate.endpoint.web
, org.springframework.boot.web.servlet.ServletContextInitializerBeans
org.springframework.jdbc.core
, org.hibernate.SQL
, org.jooq.tools.LoggerListener
4.6. 自定义日志配置
可以通过在 classpath 中引入适合的库来激活各种日志记录系统,并且可以通过在 classpath 的根目录中或在以下 Spring Environment 属性指定的位置提供合适的配置文件来进一步自定义: logging.config.
您可以使用 org.springframework.boot.logging.LoggingSystem
系统属性强制 Spring Boot 使用特定的日志记录系统. 该值应该是一个实现了 LoggingSystem
的类的完全限定类名. 您还可以使用 none
值完全禁用 Spring Boot 的日志记录配置.
logging.file.clean-history-on-start
LOG_FILE_CLEAN_HISTORY_ON_START
是否在启动时清除存档日志文件 (如果启用了LOG_FILE) . (仅默认的Logback设置受支持. )
logging.file.name
LOG_FILE
如果已定义,则在默认日志配置中使用它.
logging.file.max-size
LOG_FILE_MAX_SIZE
最大日志文件大小 (如果启用了 LOG_FILE) . (仅支持默认的 Logback 设置. )
logging.file.max-history
LOG_FILE_MAX_HISTORY
要保留的归档日志文件最大数量 (如果启用了 LOG_FILE) . (仅支持默认的 Logback 设置. )
logging.file.path
LOG_PATH
如果已定义,则在默认日志配置中使用它.
logging.file.total-size-cap
LOG_FILE_TOTAL_SIZE_CAP
要保留的日志备份的总大小 (如果启用了LOG_FILE) . (仅默认的Logback设置受支持. )
logging.pattern.console
CONSOLE_LOG_PATTERN
要在控制台上使用的日志模式 (stdout) . (仅支持默认的 Logback 设置. )
logging.pattern.dateformat
LOG_DATEFORMAT_PATTERN
日志日期格式的 Appender 模式. (仅支持默认的 Logback 设置. )
logging.pattern.file
FILE_LOG_PATTERN
要在文件中使用的日志模式 (如果启用了 LOG_FILE
) . (仅支持默认的 Logback 设置. )
logging.pattern.level
LOG_LEVEL_PATTERN
渲染日志级别时使用的格式 (默认值为 %5p
) . (仅支持默认的 Logback 设置. )
logging.pattern.rolling-file-name
ROLLING_FILE_NAME_PATTERN
过渡日志文件名的模式(默认 ${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz
).
当前进程 ID (如果可能,则在未定义为 OS 环境变量时发现) .
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.7.1. 特定 Profile 配置
<springProfile>
标签允许您根据激活的 Spring profile 选择性地包含或排除配置部分. 在 <configuration>
元素中的任何位置都支持配置 profile. 使用 name
属性指定哪个 proifle 接受配置. <springProfile>
标记可以包含简单的 proifle 名称 (例如 staging
) 或 profile 表达式. profile 表达式允许表达更复杂的 profile 逻辑,
例如 production & (eu-central | eu-west)
. 有关详细信息,请查阅 参考指南 . 以下清单展示了三个示例 profile:
<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.7.2. 环境属性
使用 <springProperty>
标签可以让您暴露 Spring 环境 (Environment
) 中的属性,以便在 Logback 中使用. 如果在 Logback 配置中访问来自 application.properties
文件的值,这样做很有用. 标签的工作方式与 Logback 的标准 <property>
标签类似. 但是,您可以指定属性 (来自 Environment
) 的 source
,而不是指定直接的 value
. 如果需要将属性存储在 local
作用域以外的其他位置,则可以使用 scope
属性.
如果需要回退值 (如果未在 Environment
中设置该属性) ,则可以使用 defaultValue
属性. 以下示例展示了如何暴露属性以便在 Logback 中使用:
<springProperty scope="context" name="fluentHost" source="myapp.fluentd.host"
defaultValue="localhost"/>
<appender name="FLUENT" class="ch.qos.logback.more.appenders.DataFluentAppender">
<remoteHost>${fluentHost}</remoteHost>
</appender>
Spring Boot 非常适合用于开发 web 应用程序. 您可以使用嵌入式 Tomcat、Jetty 或者 Undertow 来创建一个独立 (self-contained) 的 HTTP 服务器. 大多数 web 应用程序使用 spring-boot-starter-web
模块来快速搭建和运行,您也可以选择使用 spring-boot-starter-webflux
模块来构建响应式 (reactive) web 应用程序.
如果您尚未开发过 Spring Boot web 应用程序,则可以按照 入门 章节中的 "Hello World!" 示例进行操作.
7.1. Spring Web MVC 框架
Spring Web MVC 框架 (通常简称 "Spring MVC") 是一个富模型-视图-控制器的 web 框架. Spring MVC 允许您创建 @Controller
或者 @RestController
bean 来处理传入的 HTTP 请求. 控制器中的方法通过 @RequestMapping
注解映射到 HTTP.
以下是一个使用了 @RestController
来响应 JSON 数据的典型示例:
@RestController
@RequestMapping(value="/users")
public class MyRestController {
@RequestMapping(value="/{user}", method=RequestMethod.GET)
public User getUser(@PathVariable Long user) {
// ...
@RequestMapping(value="/{user}/customers", method=RequestMethod.GET)
List<Customer> getUserCustomers(@PathVariable Long user) {
// ...
@RequestMapping(value="/{user}", method=RequestMethod.DELETE)
public User deleteUser(@PathVariable Long user) {
// ...
Spring MVC 是 Spring Framework 核心的一部分,详细介绍可参考其 参考文档. spring.io/guides 还提供了几个 Spring MVC 相关的指南.
7.1.1. Spring MVC 自动配置
Spring Boot 提供了适用于大多数 Spring MVC 应用的自动配置 (auto-configuration) .
自动配置在 Spring 默认功能上添加了以下功能:
如果您想保留 Spring Boot MVC 的功能,并且需要添加其他 MVC configuration (interceptor、formatter 和视图控制器等) ,可以添加自己的 WebMvcConfigurerAdapter
类型的 @Configuration
类,但不能带 @EnableWebMvc
注解.
如果您想自定义 RequestMappingHandlerMapping
、RequestMappingHandlerAdapter
或者 ExceptionHandlerExceptionResolver
实例,可以声明一个 WebMvcRegistrationsAdapter
实例来提供这些组件.
如果您想完全掌控 Spring MVC,可以添加自定义注解了 @EnableWebMvc
的 @Configuration
配置类. 或者添加自己的 @Configuration
注解的 DelegatingWebMvcConfiguration
,如Java文档中的 @EnableWebMvc
所述. .
7.1.2. HttpMessageConverters
Spring MVC 使用 HttpMessageConverter
接口来转换 HTTP 的请求和响应. 开箱即用功能包含了合适的默认值,比如对象可以自动转换为 JSON (使用 Jackson 库) 或者 XML (优先使用 Jackson XML 扩展,其次为 JAXB) . 字符串默认使用 UTF-8
编码.
如果您需要添加或者自定义转换器 (converter) ,可以使用 Spring Boot 的 HttpMessageConverters
类:
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.*;
import org.springframework.http.converter.*;
@Configuration(proxyBeanMethods = false)
public class MyConfiguration {
@Bean
public HttpMessageConverters customConverters() {
HttpMessageConverter<?> additional = ...
HttpMessageConverter<?> another = ...
return new HttpMessageConverters(additional, another);
上下文中的所有 HttpMessageConverter
bean 都将被添加到转换器列表中. 您也可以用这种方式来覆盖默认转换器.
7.1.3. 自定义 JSON Serializer 和 Deserializer
如果您使用 Jackson 序列化和反序列化 JSON 数据,可能需要自己编写 JsonSerializer
和 JsonDeserializer
类.
自定义序列化器 (serializer) 的做法通常是 通过一个模块来注册 Jackson, 然而 Spring Boot 提供了一个备选的 @JsonComponent
注解,它可以更加容易地直接注册 Spring Bean.
您可以直接在 JsonSerializer
或者 JsonDeserializer
实现上使用 @JsonComponent
注解. 您也可以在将序列化器/反序列化器 (deserializer) 作为内部类的类上使用. 例如:
import java.io.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import org.springframework.boot.jackson.*;
@JsonComponent
public class Example {
public static class Serializer extends JsonSerializer<SomeObject> {
// ...
public static class Deserializer extends JsonDeserializer<SomeObject> {
// ...
ApplicationContext
中所有的 @JsonComponent
bean 将被自动注册到 Jackson 中,由于 @JsonComponent
使用 @Component
注解标记,因此组件扫描 (component-scanning) 规则将对其生效.
Spring Boot 还提供了 JsonObjectSerializer
和 JsonObjectDeserializer
基类,
它们在序列化对象时为标准的 Jackson 版本提供了有用的替代方案. 有关详细信息,请参阅 Javadoc 中的 JsonObjectSerializer
和 JsonObjectDeserializer
.
7.1.4. MessageCodesResolver
Spring MVC 有一个从绑定错误中生成错误码的策略,用于渲染错误信息: MessageCodesResolver
. 如果您设置了 spring.mvc.message-codes-resolver.format
属性值为 PREFIX_ERROR_CODE
或 POSTFIX_ERROR_CODE
,
Spring Boot 将为你创建该策略 (请参阅 DefaultMessageCodesResolver.Format
中的枚举) .
7.1.5. 静态内容
默认情况下,Spring Boot 将在 classpath 或者 ServletContext
根目录下从名为 /static
(/public
、/resources
或 /META-INF/resources
) 目录中服务静态内容. 它使用了 Spring MVC 的 ResourceHttpRequestHandler
,因此您可以通过添加自己的 WebMvcConfigurerAdapter
并重写 addResourceHandlers
方法来修改此行为.
在一个独立的 (stand-alone) web 应用程序中,来自容器的默认 servlet 也是被启用的,并充当一个回退支援,Spring 决定不处理 ServletContext
根目录下的静态资源,容器的默认 servlet 也将会处理. 大多情况下,这是不会发生的 (除非您修改了默认的 MVC 配置) ,因为 Spring 始终能通过 DispatcherServlet
来处理请求.
默认情况下,资源被映射到 /
,但可以通过 spring.mvc.static-path-pattern 属性调整. 比如,将所有资源重定位到 /resources/
:
spring.mvc.static-path-pattern=/resources/**
您还可以使用 spring.resources.static-locations
属性来自定义静态资源的位置 (使用一个目录位置列表替换默认值) . 根 Servlet context path /
自动作为一个 location 添加进来.
除了上述提到的标准静态资源位置之外,还有一种特殊情况是用于 Webjars content. 如果以 Webjar 格式打包,则所有符合 /webjars/**
的资源都将从 jar 文件中服务.
Spring Boot 还支持 Spring MVC 提供的高级资源处理功能,允许使用例如静态资源缓存清除 (cache busting) 或者 Webjar 版本无关 URL.
要使用 Webjar 版本无关 URL 功能,只需要添加 webjars-locator-core
依赖. 然后声明您的 Webjar,以 jQuery 为例,添加的 "/webjars/jquery/dist/jquery.min.js"
将变成 "/webjars/jquery/x.y.z/dist/jquery.min.js"
,其中 x.y.z
是 Webjar 的版本.
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
spring.resources.chain.strategy.fixed.enabled=true
spring.resources.chain.strategy.fixed.paths=/js/lib/
spring.resources.chain.strategy.fixed.version=v12
使用此配置,JavaScript 模块定位在 "/js/lib/"
下使用固定版本策略 ("/v12/js/lib/mymodule.js"
) ,而其他资源仍使用内容策略 (<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>
) .
有关更多支持选项,请参阅 ResourceProperties
.
7.1.8. 路径匹配与内容协商
Spring MVC 可以通过查看请求路径并将其与应用程序中定义的映射相匹配,将传入的 HTTP 请求映射到处理程序 (例如 Controller 方法上的 @GetMapping
注解) .
Spring Boot 默认选择禁用后缀模式匹配,这意味着像 "GET /projects/spring-boot.json"
这样的请求将不会与 @GetMapping("/projects/spring-boot")
映射匹配. 这被视为是 Spring MVC 应用程序的最佳实践 . 此功能在过去对于 HTTP 客户端没有发送正确的 Accept 请求头的情况还是很有用的,我们需要确保将正确的内容类型发送给客户端. 如今,内容协商 (Content Negotiation) 更加可靠.
还有其他方法可以处理 HTTP 客户端发送不一致 Accept 请求头问题. 我们可以使用查询参数来确保像 "GET /projects/spring-boot?format=json"
这样的请求映射到 @GetMapping("/projects/spring-boot")
,而不是使用后缀匹配:
spring.mvc.contentnegotiation.favor-parameter=true
# We can change the parameter name, which is "format" by default:
# spring.mvc.contentnegotiation.parameter-name=myparam
# We can also register additional file extensions/media types with:
spring.mvc.contentnegotiation.media-types.markdown=text/markdown
如果您了解相关注意事项并仍希望应用程序使用后缀模式匹配,则需要以下配置:
spring.mvc.contentnegotiation.favor-path-extension=true
spring.mvc.pathmatch.use-suffix-pattern=true
或者,不打开所有后缀模式,仅打开支持已注册的后缀模式更加安全:
spring.mvc.contentnegotiation.favor-path-extension=true
spring.mvc.pathmatch.use-registered-suffix-pattern=true
# You can also register additional file extensions/media types with:
# spring.mvc.contentnegotiation.media-types.adoc=text/asciidoc
7.1.10. 模板引擎
除了 REST web 服务之外,您还可以使用 Spring MVC 来服务动态 HTML 内容. Spring MVC 支持多种模板技术,包括 Thymeleaf、FreeMarker 和 JSP. 当然,许多其他模板引擎也有自己的 Spring MVC 集成.
Spring Boot 包含了以下的模板引擎的自动配置支持:
7.1.11. 错误处理
默认情况下,Spring Boot 提供了一个使用了比较合理的方式来处理所有错误的 /error
映射,其在 servlet 容器中注册了一个全局错误页面. 对于机器客户端而言,它将产生一个包含错误、HTTP 状态和异常消息的 JSON 响应. 对于浏览器客户端而言,将以 HTML 格式呈现相同数据的 whitelabel 错误视图 (可添加一个解析到 error
的 View
进行自定义) .
要完全替换默认行为,您可以实现 ErrorController
并注册该类型的 bean,或者简单地添加一个类型为 ErrorAttributes
的 bean 来替换内容,但继续使用现用机制.
@ControllerAdvice(basePackageClasses = AcmeController.class)
public class AcmeControllerAdvice extends ResponseEntityExceptionHandler {
@ExceptionHandler(YourException.class)
@ResponseBody
ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {
HttpStatus status = getStatus(request);
return new ResponseEntity<>(new CustomErrorType(status.value(), ex.getMessage()), status);
private HttpStatus getStatus(HttpServletRequest request) {
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
if (statusCode == null) {
return HttpStatus.INTERNAL_SERVER_ERROR;
return HttpStatus.valueOf(statusCode);
以上示例中,如果同包下定义的控制器 AcmeController
抛出了 YourException
,则将使用 CustomerErrorType
类型的 POJO 来代替 ErrorAttributes
做 JSON 呈现.
自定义错误页面
如果您想在自定义的 HTML 错误页面上显示给定的状态码,请将文件添加到 /error
文件夹中. 错误页面可以是静态 HTML (添加在任意静态资源文件夹下) 或者使用模板构建. 文件的名称应该是确切的状态码或者一个序列掩码.
例如,要将 404 映射到一个静态 HTML 文件,文件夹结构可以如下:
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
+- <other public assets>
使用 FreeMarker 模板来映射所有 5xx
错误,文件夹的结构如下:
+- main/
+- java/
| + <source code>
+- resources/
+- templates/
+- error/
| +- 5xx.ftlh
+- <other templates>
对于更复杂的映射,您还通过可以添加实现了 ErrorViewResolver
接口的 bean 来处理:
public class MyErrorViewResolver implements ErrorViewResolver {
@Override
public ModelAndView resolveErrorView(HttpServletRequest request,
HttpStatus status, Map<String, Object> model) {
// Use the request or status to optionally return a ModelAndView
return ...
您还可以使用常规的 Spring MVC 功能,比如 @ExceptionHandler
methods 方法和 @ControllerAdvice
. 之后,ErrorController
将能接收任何未处理的异常.
映射到 Spring MVC 之外的错误页面
对于不使用 Spring MVC 的应用程序,您可以使用 ErrorPageRegistrar
接口来直接注册 ErrorPages
. 抽象部分直接与底层的内嵌 servlet 容器一起工作,即使您没有 Spring MVC DispatcherServlet
也能使用.
@Bean
public ErrorPageRegistrar errorPageRegistrar(){
return new MyErrorPageRegistrar();
// ...
private static class MyErrorPageRegistrar implements ErrorPageRegistrar {
@Override
public void registerErrorPages(ErrorPageRegistry registry) {
registry.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400"));
@Bean
public FilterRegistrationBean myFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new MyFilter());
registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
return registration;
请注意,默认的 FilterRegistrationBean
不包含 ERROR
调度器 (dispatcher) 类型.
当心: 当部署到 servlet 容器时,Spring Boot 使用其错误页面过滤器会将有错误状态的请求转发到相应的错误页面. 如果尚未提交响应,则只能将请求转发到正确的错误页面.
默认情况下,WebSphere Application Server 8.0 及更高版本在成功完成 servlet 的 service 方法后提交响应. 您应该将 com.ibm.ws.webcontainer.invokeFlushAfterService
设置为 false
来禁用此行为.
7.1.12. Spring HATEOAS
如果您想开发一个使用超媒体 (hypermedia) 的 RESTful API,Spring Boot 提供的 Spring HATEOAS 自动配置在大多数应用程序都工作得非常好. 自动配置取代了 @EnableHypermediaSupport
的需要,
并注册了一些 bean,以便能轻松构建基于超媒体的应用程序,其包括了一个 LinkDiscoverers
(用于客户端支持) 和一个用于配置将响应正确呈现的 ObjectMapper. ObjectMapper 可以通过设置 spring.jackson.*
属性或者 Jackson2ObjectMapperBuilder
bean (如果存在) 自定义.
您可以使用 @EnableHypermediaSupport
来控制 Spring HATEOAS 的配置. 请注意,这使得上述的自定义 ObjectMapper
被禁用.
7.1.13. CORS 支持
Cross-origin resource sharing 跨域资源共享 (Cross-origin resource sharing,CORS) 是 most browsers实现的一个 W3C specification ,其可允许您以灵活的方式指定何种跨域请求可以被授权,而不是使用一些不太安全和不太强大的方式 (比如 IFRAME 或者 JSONP) .
Spring MVC 从 4.2 版本起开始 支持 CORS. 您可在 Spring Boot 应用程序中使用 @CrossOrigin
注解 配置控制器方法启用 CORS.
还可以通过注册一个 WebMvcConfigurer
bean 并自定义 addCorsMappings(CorsRegistry)
方法来定义 全局 CORS 配置 :
@Configuration(proxyBeanMethods = false)
public class MyConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**");
@GetMapping("/{user}/customers")
public Flux<Customer> getUserCustomers(@PathVariable Long user) {
// ...
@DeleteMapping("/{user}")
public Mono<User> deleteUser(@PathVariable Long user) {
// ...
“WebFlux.fn” 为函数式调用方式,它将路由配置与请求处理分开,如下所示:
@Configuration(proxyBeanMethods = false)
public class RoutingConfiguration {
@Bean
public RouterFunction<ServerResponse> monoRouterFunction(UserHandler userHandler) {
return route(GET("/{user}").and(accept(APPLICATION_JSON)), userHandler::getUser)
.andRoute(GET("/{user}/customers").and(accept(APPLICATION_JSON)), userHandler::getUserCustomers)
.andRoute(DELETE("/{user}").and(accept(APPLICATION_JSON)), userHandler::deleteUser);
@Component
public class UserHandler {
public Mono<ServerResponse> getUser(ServerRequest request) {
// ...
public Mono<ServerResponse> getUserCustomers(ServerRequest request) {
// ...
public Mono<ServerResponse> deleteUser(ServerRequest request) {
// ...
WebFlux 是 Spring Framework 的一部分,详细信息可查看其 参考文档.
在应用程序中同时添加 spring-boot-starter-web
和 spring-boot-starter-webflux
模块会导致Spring Boot 自动配置 Spring MVC,而不是使用 WebFlux
. 这样做的原因是因为许多 Spring 开发人员将 spring-boot-starter-webflux
添加到他们的 Spring MVC 应用程序中只是为了使用响应式 WebClient
.
您仍然可以通过设置 SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE)
来强制执行您选择的应用程序类型.
如果你要保留 Spring Boot WebFlux 功能并且想要添加其他 WebFlux
配置,可以添加自己的 @Configuration
类,类型为 WebFluxConfigurer
,但不包含 @EnableWebFlux
.
如果您想完全控制 Spring WebFlux,可以将 @EnableWebFlux
注解到自己的 @Configuration
.
7.2.2. 使用 HttpMessageReader 和 HttpMessageWriter 作为 HTTP 编解码器
Spring WebFlux 使用 HttpMessageReader
和 HttpMessageWriter
接口来转换 HTTP 的请求和响应. 它们通过检测 classpath 中可用的类库,配置了 CodecConfigurer
生成合适的默认值.
Spring Boot 通过使用 CodecCustomizer
实例加强定制. 例如,spring.jackson.*
配置 key 应用于 Jackson 编解码器.
如果需要添加或自定义编解码器,您可以创建一个自定义的 CodecCustomizer
组件,如下所示:
import org.springframework.boot.web.codec.CodecCustomizer;
@Configuration(proxyBeanMethods = false)
public class MyConfiguration {
@Bean
public CodecCustomizer myCodecCustomizer() {
return codecConfigurer -> {
// ...
您还可以利用 Boot 自定义 JSON 序列化器和反序列化器.
7.2.3. 静态内容
默认情况下,Spring Boot 将在 classpath 或者 ServletContext
根目录下从名为 /static
(/public
、/resources
或 /META-INF/resources
) 目录中服务静态内容. 它使用了 Spring WebFlux 的 ResourceWebHandler
,因此您可以通过添加自己的 WebFluxConfigurer
并重写 addResourceHandlers
方法来修改此行为.
默认情况下,资源被映射到 /
,但可以通过 spring.webflux.static-path-pattern
属性调整. 比如,将所有资源重定位到 /resources/
:
spring.webflux.static-path-pattern=/resources/**
您还可以使用 spring.resources.static-locations
属性来自定义静态资源的位置 (使用一个目录位置列表替换默认值) ,如果这样做,默认的欢迎页面检测会切换到您自定义的位置. 因此,如果启动时有任何其中一个位置存在 index.html
,那么它将是应用程序的主页.
除了上述提到的标准静态资源位置之外,还有一种特殊情况是用于 Webjars 内容 . 如果以 Webjar 格式打包,则所有符合 /webjars/**
的资源都将从 jar 文件中服务.
7.2.4. 模板引擎
除了 REST web 服务之外,您还可以使用 Spring WebFlux 来服务动态 HTML 内容. Spring WebFlux 支持多种模板技术,包括 Thymeleaf、FreeMarker 和 Mustache.
Spring Boot 包含了以下的模板引擎的自动配置支持:
7.2.5. Error Handling
Spring Boot 提供了一个 WebExceptionHandler
,它以合理的方式处理所有错误. 它在处理顺序中的位置紧接在 WebFlux 提供的处理程序之前,这些处理器排序是最后的. 对于机器客户端,它会生成一个 JSON 响应,其中包含错误详情、HTTP 状态和异常消息. 对于浏览器客户端,有一个 whitelabel 错误处理程序,它以 HTML 格式呈现同样的数据. 您还可以提供自己的 HTML 模板来显示错误 (请参阅下一节) .
自定义此功能的第一步通常会沿用现有机制,但替换或扩充了错误内容. 为此,您可以添加 ErrorAttributes
类型的 bean.
想要更改错误处理行为,可以实现 ErrorWebExceptionHandler
并注册该类型的 bean. 因为 WebExceptionHandler
是一个非常底层的异常处理器,所以 Spring Boot 还提供了一个方便的 AbstractErrorWebExceptionHandler
来让你以 WebFlux 的方式处理错误,如下所示:
public class CustomErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
// Define constructor here
@Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions
.route(aPredicate, aHandler)
.andRoute(anotherPredicate, anotherHandler);
要获得更完整的功能,您还可以直接继承 DefaultErrorWebExceptionHandler
并覆盖相关方法.
自定义错误页面
如果您想在自定义的 HTML 错误页面上显示给定的状态码,请将文件添加到 /error
文件夹中. 错误页面可以是静态 HTML (添加在任意静态资源文件夹下) 或者使用模板构建. 文件的名称应该是确切的状态码或者一个序列掩码.
例如,要将 404 映射到一个静态 HTML 文件,文件夹结构可以如下:
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
+- <other public assets>
使用 Mustache 模板来映射所有 5xx
错误,文件夹的结构如下:
+- main/
+- java/
| + <source code>
+- resources/
+- templates/
+- error/
| +- 5xx.mustache
+- <other templates>
7.2.6. Web 过滤器
Spring WebFlux 提供了一个 WebFilter
接口,可以通过实现该接口来过滤 HTTP 请求/响应消息交换. 在应用程序上下文中找到的 WebFilter
bean 将自动用于过滤每个消息交换.
如果过滤器的执行顺序很重要,则可以实现 Ordered
接口或使用 @Order
注解来指定顺序. Spring Boot 自动配置可能为您配置了几个 Web 过滤器. 执行此操作时,将使用下表中的顺序:
7.3. JAX-RS 与 Jersey
如果您喜欢 JAX-RS 编程模型的 REST 端点,则可以使用一个实现来替代 Spring MVC. Jersey 和 Apache CXF 都能开箱即用. CXF 要求在应用程序上下文中以 @Bean
的方式将它注册为一个 Servlet
或者 Filter
. Jersey 有部分原生 Spring 支持,所以我们也在 starter 中提供了与 Spring Boot 整合的自动配置支持.
要使用 Jersey,只需要将 spring-boot-starter-jersey
作为依赖引入,然后您需要一个 ResourceConfig
类型的 @Bean
,您可以在其中注册所有端点:
@Component
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(Endpoint.class);
由于 Endpoint 是一个 Spring @Component
,它的生命周期由 Spring 管理,您可以使用 @Autowired
注入依赖并使用 @Value
注入外部配置. 默认情况下,Jersey servlet 将被注册并映射到 /*
. 您可以通过将 @ApplicationPath
添加到 ResourceConfig
来改变此行为.
默认情况下,Jersey 在 ServletRegistrationBean
类型的 @Bean 中被设置为一个名为 jerseyServletRegistration
的 Servlet. 默认情况下,该 servlet 将被延迟初始化,您可以使用 spring.jersey.servlet.load-on-startup
自定义.
您可以禁用或通过创建一个自己的同名 bean 来覆盖该 bean. 您还可以通过设置 spring.jersey.type=filter
使用过滤器替代 servlet (该情况下, 替代或覆盖 @Bean
的为 jerseyFilterRegistration
) .
该过滤器有一个 @Order
,您可以使用 spring.jersey.filter.order
设置. 可以使用 spring.jersey.init.*
指定一个 map 类型的 property 以给定 servlet 和过滤器的初始化参数.
这里有一个 Jersey 示例,您可以解如何设置.
7.4. 内嵌 Servlet 容器支持
Spring Boot 包含了对内嵌 Tomcat, Jetty, 和 Undertow 服务器的支持. 大部分开发人员只需简单地使用对应的 Starter 来获取完整的配置实例. 默认情况下,内嵌服务器将监听 8080
上的 HTTP 请求.
7.4.1. Servlets, Filters, 与 listeners
使用内嵌 servlet 容器时,您可以使用 Spring bean 或者扫描方式来注册 Servlet 规范中的 Servlet、Filter 和所有监听器 (比如 HttpSessionListener
) .
将 Servlet、Filter 和 Listener 注册为 Spring
任何 Servlet
、Filter
或 *Listener
的 Spring bean 实例都将被注册到内嵌容器中. 如果您想引用 application.properties
中的某个值,这可能会特别方便.
默认情况下,如果上下文只包含单个 Servlet,它将映射到 /
. 在多个 Servlet bean 的情况下,bean 的名称将用作路径的前缀. Filter 将映射到 /*
.
如果基于约定配置的映射不够灵活,您可以使用 ServletRegistrationBean
、FilterRegistrationBean
和 ServletListenerRegistrationBean
类来完全控制.
通常把过滤器 bean 无序是安全的. 如果需要特定的顺序,则应使用 @Order
注解 Filter
或使其实现 Ordered
. 您不能通过使用 @Order
注解 Filter
的bean方法来配置 Filter
的顺序.
如果您不能更改 Filter
类以添加 @Order
或实现 Ordered
,则必须为 Filter
定义一个 FilterRegistrationBean
并使用 setOrder(int)
方法设置注册bean的顺序.
则应避免在 Ordered.HIGHEST_PRECEDENCE
顺序点配置读取请求体的过滤器,因为它的字符编码可能与应用程序的字符编码配置不一致. 如果一个 Servlet 过滤器包装了请求,则应使用小于或等于 OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER
的顺序点对其进行配置.
7.4.2. Servlet 上下文初始化
内嵌 servlet 容器不会直接执行 Servlet 3.0+ 的 javax.servlet.ServletContainerInitializer
接口或 Spring 的 org.springframework.web.WebApplicationInitializer
接口. 这是一个有意的设计决策,旨在降低在 war 内运行时第三方类库产生的风险,防止破坏 Sring Boot 应用程序.
如果您需要在 Spring Boot 应用程序中执行 servlet 上下文初始化,则应注册一个实现了 org.springframework.boot.context.embedded.ServletContextInitializer
接口的 bean. onStartup
方法提供了针对 ServletContext
的访问入口,如果需要,它可以容易作为现有 WebApplicationInitializer
的适配器.
扫描 Servlet、Filter 和 Listener
使用内嵌容器时,可以使用 @ServletComponentScan
启用带 @WebServlet
、@WebFilter
和 @WebListener
注解的类自动注册.
7.4.4. 自定义内嵌 Servlet 容器
可以使用 Spring Environment
属性来配置通用的 servlet 容器设置. 通常,您可以在 application.properties
文件中定义这些属性.
常用服务器设置包括:
会话设置: 是否持久会话 (server.session.persistence
) 、session 超时 (server.session.timeout
) 、会话数据存放位置 (server.session.store-dir
) 和 session-cookie 配置 (server.session.cookie.*
) .
错误管理: 错误页面位置 (server.error.path
) 等.
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.stereotype.Component;
@Component
public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
@Override
public void customize(ConfigurableServletWebServerFactory server) {
server.setPort(9000);
@Bean
public ConfigurableServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.setPort(9000);
factory.setSessionTimeout(10, TimeUnit.MINUTES);
factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notfound.html"));
return factory;
Setter 方法提供了许多配置选项. 还有几个 hook 保护方法供您深入定制. 有关详细信息,请参阅 源码文档.
如果您使用 war 打包,在 Jetty 和 Tomcat 中可以正常工作,使用 java -jar
启动时,可执行的 war 可正常使用,并且还可以部署到任何标准容器. 使用可执行 jar 时不支持 JSP.
Undertow 不支持 JSP.
创建自定义的 error.jsp
页面不会覆盖默认错误处理视图,应该使用自定义错误页面来代替. .
7.6. 响应式服务器资源配置
在自动配置 Reactor Netty 或 Jetty 服务器时,Spring Boot 将创建特定的 bean 为服务器实例提供 HTTP 资源: ReactorResourceFactory
或 JettyResourceFactory
.
默认情况下,这些资源也将与 Reactor Netty 和 Jetty 客户端共享以获得最佳性能,具体如下:
开发人员可以通过提供自定义的 ReactorResourceFactory
或 JettyResourceFactory
bean 来重写 Jetty 和 Reactor Netty 的资源配置 —— 将应用于客户端和服务器.
您可以在 WebClient Runtime 章节中了解有关客户端资源配置的更多内容.
Spring框架的 spring-messaging
模块在客户端和服务器端都支持RSocket请求者和响应者. 有关更多详细信息,请参见Spring Framework参考中的 RSocket 部分,其中包括RSocket协议的概述.
8.1. RSocket策略自动配置
Spring Boot自动配置一个 RSocketStrategies
bean,该bean提供了编码和解码RSocket有效负载所需的所有基础结构. 默认情况下,自动配置将尝试 (按顺序) 配置以下内容:
8.2. RSocket服务器自动配置
Spring Boot提供了RSocket服务器自动配置. 所需的依赖关系由 spring-boot-starter-rsocket
提供.
Spring Boot允许从WebFlux服务器通过WebSocket暴露RSocket,或支持独立的RSocket服务器. 这取决于应用程序的类型及其配置.
对于WebFlux应用程序 (即 WebApplicationType.REACTIVE
类型) ,仅当以下属性匹配时,RSocket服务器才会插入Web服务器:
spring.rsocket.server.mapping-path=/rsocket # a mapping path is defined
spring.rsocket.server.transport=websocket # websocket is chosen as a transport
#spring.rsocket.server.port= # no port is defined
作为服务器,您可以在RSocket @Controller
的任何处理程序方法上注入 RSocketRequester
实例. 作为客户端,您需要首先配置和建立RSocket连接. 在这种情况下,Spring Boot会使用预期的编解码器自动配置 RSocketRequester.Builder
.
RSocketRequester.Builder
实例是一个原型bean,这意味着每个注入点将为您提供一个新实例. 这样做是有目的的,因为此构建器是有状态的,因此您不应使用同一实例创建具有不同设置的请求者.
以下代码显示了一个典型示例:
@Service
public class MyService {
private final Mono<RSocketRequester> rsocketRequester;
public MyService(RSocketRequester.Builder rsocketRequesterBuilder) {
this.rsocketRequester = rsocketRequesterBuilder
.connectTcp("example.org", 9898).cache();
public Mono<User> someRSocketCall(String name) {
return this.rsocketRequester.flatMap(req ->
req.route("user").data(name).retrieveMono(User.class));
默认情况下,如果 Spring Security 在 classpath 上,则 Web 应用程序是受保护的. Spring Boot 依赖 Spring Security 的内容协商策略来确定是使用 httpBasic
还是 formLogin
.
要给 Web 应用程序添加方法级别的安全保护,可以使用 @EnableGlobalMethodSecurity
注解设置. 有关更多其他信息,您可以在 Spring Security 参考指南中找到.
默认的 UserDetailsService
只有一个用户. 用户名为 user
,密码是随机的,在应用程序启动时会以 INFO 级别打印出来,如下所示:
Using generated security password: 78fa095d-3f4c-48b1-ad50-e24c31d5cf35
一个 UserDetailsService
(或 WebFlux 应用程序中的 ReactiveUserDetailsService
) bean,采用内存存储形式,有一个自动生成密码的用户 (有关用户属性,请参阅 SecurityProperties.User
) .
用于整个应用程序 (如果 actuator 在 classpath 上,则包括 actuator 端点) 基于表单登录或 HTTP Basic 认证 (取决于 Content-Type) .
一个用于发布身份验证事件的 DefaultAuthenticationEventPublisher
.
9.1. MVC 安全
默认的安全配置在 SecurityAutoConfiguration
和 UserDetailsServiceAutoConfiguration
中实现. SecurityAutoConfiguration
导入用于 Web 安全的 SpringBootWebSecurityConfiguration
,UserDetailsServiceAutoConfiguration
配置身份验证,这同样适用于非 Web 应用程序. 要完全关闭默认的 Web 应用程序安全配置,可以添加 WebSecurityConfigurerAdapter
类型的 bean (这样做不会禁用 UserDetailsService
配置或 Actuator
的安全保护) .
要同时关闭 UserDetailsService
配置,您可以添加 UserDetailsService
、AuthenticationProvider
或 AuthenticationManager
类型的 bean. Spring Boot 示例中有几个使用了安全保护的应用程序,他们或许可以帮助到您.
可以通过添加自定义 WebSecurityConfigurerAdapter
来重写访问规则. Spring Boot 提供了便捷方法,可用于重写 actuator
端点和静态资源的访问规则. EndpointRequest
可用于创建一个基于 management.endpoints.web.base-path
属性的 RequestMatcher
. PathRequest
可用于为常用位置中的资源创建一个 RequestMatcher
.
9.2. WebFlux 安全
与 Spring MVC 应用程序类似,您可以通过添加 spring-boot-starter-security
依赖来保护 WebFlux 应用程序. 默认的安全配置在 ReactiveSecurityAutoConfiguration
和 UserDetailsServiceAutoConfiguration
中实现. ReactiveSecurityAutoConfiguration
导入用于 Web 安全的 WebFluxSecurityConfiguration
,UserDetailsServiceAutoConfiguration
配置身份验证,这同样适用于非 Web 应用程序. 要完全关闭默认的 Web 应用程序安全配置,可以添加 WebFilterChainProxy
类型的 bean (这样做不会禁用 UserDetailsService
配置或 Actuator
的安全保护) .
要同时关闭 UserDetailsService
配置,您可以添加 ReactiveUserDetailsService
或 ReactiveAuthenticationManager
类型的 bean.
可以通过添加自定义 SecurityWebFilterChain
来重写访问规则. Spring Boot 提供了便捷方法,可用于重写 actuator
端点和静态资源的访问规则. EndpointRequest
可用于创建一个基于 management.endpoints.web.base-path
属性的 ServerWebExchangeMatcher
.
PathRequest
可用于为常用位置中的资源创建一个 ServerWebExchangeMatcher
.
例如,您可以通过添加以下内容来自定义安全配置:
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
return http
.authorizeExchange()
.matchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.pathMatchers("/foo", "/bar")
.authenticated().and()
.formLogin().and()
.build();
9.3.1. 客户端
如果您的 classpath 上有 spring-security-oauth2-client
,则可以利用一些自动配置来轻松设置 OAuth2/Open ID Connect 客户端. 该配置使用 OAuth2ClientProperties
的属性. 相同的属性适用于 servlet 和响应式应用程序.
您可以在 spring.security.oauth2.client
前缀下注册多个 OAuth2 客户端和提供者 (provider) ,如下所示:
spring.security.oauth2.client.registration.my-client-1.client-id=abcd
spring.security.oauth2.client.registration.my-client-1.client-secret=password
spring.security.oauth2.client.registration.my-client-1.client-name=Client for user scope
spring.security.oauth2.client.registration.my-client-1.provider=my-oauth-provider
spring.security.oauth2.client.registration.my-client-1.scope=user
spring.security.oauth2.client.registration.my-client-1.redirect-uri=https://my-redirect-uri.com
spring.security.oauth2.client.registration.my-client-1.client-authentication-method=basic
spring.security.oauth2.client.registration.my-client-1.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.my-client-2.client-id=abcd
spring.security.oauth2.client.registration.my-client-2.client-secret=password
spring.security.oauth2.client.registration.my-client-2.client-name=Client for email scope
spring.security.oauth2.client.registration.my-client-2.provider=my-oauth-provider
spring.security.oauth2.client.registration.my-client-2.scope=email
spring.security.oauth2.client.registration.my-client-2.redirect-uri=https://my-redirect-uri.com
spring.security.oauth2.client.registration.my-client-2.client-authentication-method=basic
spring.security.oauth2.client.registration.my-client-2.authorization-grant-type=authorization_code
spring.security.oauth2.client.provider.my-oauth-provider.authorization-uri=https://my-auth-server/oauth/authorize
spring.security.oauth2.client.provider.my-oauth-provider.token-uri=https://my-auth-server/oauth/token
spring.security.oauth2.client.provider.my-oauth-provider.user-info-uri=https://my-auth-server/userinfo
spring.security.oauth2.client.provider.my-oauth-provider.user-info-authentication-method=header
spring.security.oauth2.client.provider.my-oauth-provider.jwk-set-uri=https://my-auth-server/token_keys
spring.security.oauth2.client.provider.my-oauth-provider.user-name-attribute=name
对于支持 OpenID Connect discovery 的 OpenID Connect 提供者,可以进一步简化配置. 需要使用 issuer-uri
配置提供者,issuer-uri
是其 Issuer Identifier 的 URI.
例如,如果提供的 issuer-uri 是 "https://example.com", 则将对 "https://example.com/.well-known/openid-configuration" 发起一个 OpenID Provider Configuration Request
. 期望结果是一个 OpenID Provider Configuration Response
. 以下示例展示了如何使用 issuer-uri
配置一个 OpenID Connect Provider:
spring.security.oauth2.client.provider.oidc-provider.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/
默认情况下,Spring Security 的 OAuth2LoginAuthenticationFilter
仅处理与 /login/oauth2/code/*
相匹配的 URL. 如果要自定义 redirect-uri
以使用其他匹配模式,则需要提供配置以处理该自定义模式. 例如,对于 servlet 应用程序,您可以添加类似于以下 WebSecurityConfigurerAdapter
:
public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login()
.redirectionEndpoint()
.baseUri("/custom-callback");
OAuth2 客户端注册常见的提供者
对于常见的 OAuth2 和 OpenID 提供者 (provider) ,包括 Google、Github、Facebook 和 Okta,我们提供了一组提供者默认设置 (分别是 google、github、facebook 和 okta) .
如果您不需要自定义这些提供者,则可以将 provider
属性设置为您需要推断默认值的属性. 此外,如果客户端注册的 key 与默认支持的提供者匹配,则 Spring Boot 也会推断出来.
换而言之,以下示例中的两个配置使用了 Google 提供者:
spring.security.oauth2.client.registration.my-client.client-id=abcd
spring.security.oauth2.client.registration.my-client.client-secret=password
spring.security.oauth2.client.registration.my-client.provider=google
spring.security.oauth2.client.registration.google.client-id=abcd
spring.security.oauth2.client.registration.google.client-secret=password
spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://example.com/check-token
spring.security.oauth2.resourceserver.opaquetoken.client-id=my-client-id
spring.security.oauth2.resourceserver.opaquetoken.client-secret=my-client-secret
同样,相同的属性适用于servlet和反应式应用程序.
另外,您可以为Servlet应用程序定义自己的 OpaqueTokenIntrospector
Bean,或者为反应性应用程序定义 ReactiveOpaqueTokenIntrospector
.
9.3.3. 授权服务器
目前,Spring Security 没有提供 OAuth 2.0 授权服务器实现. 但此功能可从 Spring Security OAuth 项目获得,该项目最终会被 Spring Security 所取代. 在此之前,您可以使用 spring-security-oauth2-autoconfigure
模块轻松设置 OAuth 2.0 授权服务器,请参阅 其文档以获取详细信息.
9.4.1. 依赖方
如果您在类路径中具有 spring-security-saml2-service-provider
,则可以利用一些自动配置功能来轻松设置SAML 2.0依赖方. 此配置利用 Saml2RelyingPartyProperties
下的属性.
依赖方注册代表身份提供商IDP和服务提供商SP之间的配对配置. 您可以在 spring.security.saml2.relyingparty
前缀下注册多个依赖方,如以下示例所示:
spring.security.saml2.relyingparty.registration.my-relying-party1.signing.credentials[0].private-key-location=path-to-private-key
spring.security.saml2.relyingparty.registration.my-relying-party1.signing.credentials[0].certificate-location=path-to-certificate
spring.security.saml2.relyingparty.registration.my-relying-party1.identityprovider.verification.credentials[0].certificate-location=path-to-verification-cert
spring.security.saml2.relyingparty.registration.my-relying-party1.identityprovider.entity-id=remote-idp-entity-id1
spring.security.saml2.relyingparty.registration.my-relying-party1.identityprovider.sso-url=https://remoteidp1.sso.url
spring.security.saml2.relyingparty.registration.my-relying-party2.signing.credentials[0].private-key-location=path-to-private-key
spring.security.saml2.relyingparty.registration.my-relying-party2.signing.credentials[0].certificate-location=path-to-certificate
spring.security.saml2.relyingparty.registration.my-relying-party2.identityprovider.verification.credentials[0].certificate-location=path-to-other-verification-cert
spring.security.saml2.relyingparty.registration.my-relying-party2.identityprovider.entity-id=remote-idp-entity-id2
spring.security.saml2.relyingparty.registration.my-relying-party2.identityprovider.sso-url=https://remoteidp2.sso.url
9.5. Actuator 安全
出于安全考虑,默认情况下禁用除 /health
和 /info
之外的所有 actuator. 可用 management.endpoints.web.exposure.include
属性启用 actuator.
如果 Spring Security 位于 classpath 上且没有其他 WebSecurityConfigurerAdapter,则除了 /health
和 /info
之外的所有 actuator 都由 Spring Boot 自动配置保护. 如果您定义了自定义 WebSecurityConfigurerAdapter
,则 Spring Boot 自动配置将不再生效,您可以完全控制 actuator 的访问规则.
Spring Framework 为 SQL 数据库提供了广泛的支持. 从直接使用 JdbcTemplate
进行 JDBC 访问到完全的对象关系映射 (object relational mapping) 技术,比如 Hibernate. Spring Data提供了更多级别的功能,直接从接口创建的 Repository
实现,并使用了约定从方法名生成查询.
10.1. 配置数据源
Java 的 javax.sql.DataSource
接口提供了一个使用数据库连接的标准方法. 通常,数据源使用 URL 和一些凭据信息来建立数据库连接.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>runtime</scope>
</dependency>
spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
有关更多支持选项,请参阅 DataSourceProperties
.
这些都是标准选项,与实际的实现无关. 还可以使用各自的前缀 (spring.datasource.hikari.
、spring.datasource.tomcat.
和 spring.datasource.dbcp2.*
) 微调实现特定的设置. 请参考您现在使用的连接池实现的文档来获取更多信息.
例如,如果你使用 Tomcat connection pool,则可以自定义许多其他设置,如下:
# Number of ms to wait before throwing an exception if no connection is available.
spring.datasource.tomcat.max-wait=10000
# Maximum number of active connections that can be allocated from this pool at the same time.
spring.datasource.tomcat.max-active=50
# Validate the connection before borrowing it from the pool.
spring.datasource.tomcat.test-on-borrow=true
10.1.3. 连接 JNDI 数据源
如果要将 Spring Boot 应用程序部署到应用服务器 (Application Server) 上,您可能想使用应用服务器的内置功能和 JNDI 访问方式来配置和管理数据源.
spring.datasource.jndi-name
属性可作为 spring.datasource.url
、spring.datasource.username
和 spring.datasource.password
属性的替代方法,用于从特定的 JNDI 位置访问 DataSource
. 例如,application.properties
中的以下部分展示了如何访问 JBoss AS 定义的 DataSource
:
spring.datasource.jndi-name=java:jboss/datasources/customers
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
private final JdbcTemplate jdbcTemplate;
@Autowired
public MyBean(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
// ...
您可以使用 spring.jdbc.template.*
属性来自定义一些 template 的属性,如下:
spring.jdbc.template.max-rows=500
10.3.1. 实体类
通常,JPA Entity (实体) 类是在 persistence.xml
文件中指定的. 使用了 Spring Boot,该文件将不是必需的,可以使用 Entity Scanning (实体扫描) 来代替. 默认情况下,将搜索主配置类 (使用了 @EnableAutoConfiguration
或 @SpringBootApplication
注解) 下面的所有包.
任何用了 @Entity
、@Embeddable
或者 @MappedSuperclass
注解的类将被考虑. 一个典型的实体类如下:
package com.example.myapp.domain;
import java.io.Serializable;
import javax.persistence.*;
@Entity
public class City implements Serializable {
@GeneratedValue
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String state;
// ... additional members, often include @OneToMany mappings
protected City() {
// no-args constructor required by JPA spec
// this one is protected since it shouldn't be used directly
public City(String name, String state) {
this.name = name;
this.state = state;
public String getName() {
return this.name;
public String getState() {
return this.state;
// ... etc
10.3.2. Spring Data JPA 资源库
Spring Data JPA 资源库 (repository) 是接口,您可以定义用于访问数据. JAP 查询是根据您的方法名自动创建. 例如,CityRepository
接口可以声明 findAllByState(String state)
方法来查找指定状态下的所有城市.
对于更加复杂的查询,您可以使用 Spring Data 的 Query
注解
Spring Data 资源库通常继承自 Repository
或者 CrudRepository
接口. 如果您使用了自动配置,则将从包含主配置类 (使用了 @EnableAutoConfiguration
或 @SpringBootApplication
注解) 的包中搜索资源库:
以下是一个典型的 Spring Data 资源库接口定义:
package com.example.myapp.domain;
import org.springframework.data.domain.*;
import org.springframework.data.repository.*;
public interface CityRepository extends Repository<City, Long> {
Page<City> findAll(Pageable pageable);
City findByNameAndStateAllIgnoringCase(String name, String state);
Spring Data JPA 资源库支持三种不同的引导模式: default
、deferred
和 lazy
. 要启用延迟或懒惰引导,请将 spring.data.jpa.repositories.bootstrap-mode
分别设置为 deferred
或 lazy
. 使用延迟或延迟引导时,自动配置的 EntityManagerFactoryBuilder
将使用上下文的 AsyncTaskExecutor
(如果有) 作为 applicationTaskExecutor
.
10.4. Spring Data JDBC
Spring Data 包含了对 JDBC 资源库的支持,并将自动为 CrudRepository
上的方法生成 SQL. 对于更高级的查询,它提供了 @Query
注解.
当 classpath 下存在必要的依赖时,Spring Boot 将自动配置 Spring Data 的 JDBC 资源库. 可以通过添加单个 spring-boot-starter-data-jdbc
依赖引入到项目中. 如有必要,可通过在应用程序中添加 @EnableJdbcRepositories
注解或 JdbcConfiguration
子类来控制 Spring Data JDBC 的配置.
10.6. 使用 jOOQ
Java 面向对象查询 (Java Object Oriented Querying, jOOQ) 是一款广受欢迎的产品,出自 Data Geekery,它可以通过数据库生成 Java 代码,并允许您使用流式 API 来构建类型安全的 SQL 查询. 商业版和开源版都可以与 Spring Boot 一起使用.
10.6.1. 代码生成
要使用 jOOQ 的类型安全查询,您需要从数据库模式生成 Java 类. 您可以按照 jOOQ 用户手册中的说明进行操作. 如果您使用了 jooq-codegen-maven
插件,并且还使用了 spring-boot-starter-parent
父 POM,则可以安全地省略掉插件的 <version>
标签.
您还可以使用 Spring Boot 定义的版本变量 (例如 h2.version
) 来声明插件的数据库依赖. 以下是一个示例:
<plugin>
<groupId>org.jooq</groupId>
<artifactId>jooq-codegen-maven</artifactId>
<executions>
</executions>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
</dependency>
</dependencies>
<configuration>
<driver>org.h2.Driver</driver>
<url>jdbc:h2:~/yourdatabase</url>
</jdbc>
<generator>
</generator>
</configuration>
</plugin>
public List<GregorianCalendar> authorsBornAfter1980() {
return this.create.selectFrom(AUTHOR)
.where(AUTHOR.DATE_OF_BIRTH.greaterThan(new GregorianCalendar(1980, 0, 1)))
.fetch(AUTHOR.DATE_OF_BIRTH);
Spring Boot为Redis,MongoDB,Neo4j,Elasticsearch,Solr Cassandra,Couchbase和LDAP提供自动配置. 您可以使用其他项目,但必须自己进行配置. 请参阅 spring.io/projects/spring-data 中的相应参考文档.
11.1. Redis
Redis 是一个集缓存、消息代理和键值存储等丰富功能的数据库. Spring Boot 为 Lettuce 和 Jedis 客户端类库提供了基本自动配置, Spring Data Redis 为他们提供了上层抽象.
使用 spring-boot-starter-data-redis
starter 可方便地引入相关依赖. 默认情况下,它使用 Lettuce. 该 starter 可处理传统应用程序和响应式应用程序.
11.2. MongoDB
MongoDB 是一个开源的 NoSQL 文档数据库,其使用了类似 JSON 的模式 (schema) 来替代传统基于表的关系数据. Spring Boot 为 MongoDB 提供了几种便利的使用方式,包括 spring-boot-starter-data-mongodb
和 spring-boot-starter-data-mongodb-reactive
starter.
11.2.1. 连接 MongoDB 数据库
您可以注入一个自动配置的 org.springframework.data.mongodb.MongoDbFactory
来访问 Mongo 数据库. 默认情况下,该实例将尝试在 mongodb://localhost/test
上连接 MongoDB 服务器,以下示例展示了如何连接到 MongoDB 数据库:
import org.springframework.data.mongodb.MongoDbFactory;
import com.mongodb.DB;
@Component
public class MyBean {
private final MongoDbFactory mongo;
@Autowired
public MyBean(MongoDbFactory mongo) {
this.mongo = mongo;
// ...
public void example() {
DB db = mongo.getDb();
// ...
您可以通过设置 spring.data.mongodb.uri
属性来更改 URL 和配置其他设置,如副本集 (replica set) :
spring.data.mongodb.uri=mongodb://user:[email protected]:12345,mongo2.example.com:23456/test
另外,只要您使用了 Mongo 2.x,请指定 host/port
. 比如,您可能要在 application.properties
中声明以下内容:
spring.data.mongodb.host=mongoserver
spring.data.mongodb.port=27017
如果您已经定义了自己的 MongoClient
,它将被用于自动配置合适的 MongoDbFactory
. 支持 com.mongodb.MongoClient
和 com.mongodb.client.MongoClient
.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
private final MongoTemplate mongoTemplate;
@Autowired
public MyBean(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
// ...
更多详细信息,参照 MongoOperations
Javadoc .
11.2.3. Spring Data MongoDB Repositories
Spring Data 包含了对 MongoDB 资源库 (repository) 的支持. 与之前讨论的 JPA 资源库一样,基本原理是根据方法名称自动构建查询.
事实上,Spring Data JPA 和 Spring Data MongoDB 共享通用的底层代码,因此你可以拿之前提到的 JPA 示例作为基础,假设 City
现在是一个 Mongo 数据类,而不是一个 JPA @Entity
,他们方式工作相同:
package com.example.myapp.domain;
import org.springframework.data.domain.*;
import org.springframework.data.repository.*;
public interface CityRepository extends Repository<City, Long> {
Page<City> findAll(Pageable pageable);
City findByNameAndStateAllIgnoringCase(String name, String state);
11.2.4. 内嵌 Mongo
Spring Boot 提供了 内嵌 Mongo的自动配置. 要在 Spring Boot 应用程序中使用它,请添加依赖 de.flapdoodle.embed:de.flapdoodle.embed.mongo
.
可以使用 spring.data.mongodb.port
属性来配置 Mongo 的监听端口. 如果想随机分配空闲端口,请把值设置为 0. MongoAutoConfiguration
创建的 MongoClient
将自动配置随机分配的端口.
如果您的 classpath 上有 SLF4J,Mongo 产生的输出将自动路由到名为 org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongo
的 logger.
您可以声明自己的 IMongodConfig
和 IRuntimeConfig
bean 来控制 Mongo 实例的配置和日志路由.
可以通过声明 DownloadConfigBuilderCustomizer
bean来定制下载配置.
11.3. Neo4j
Neo4j 是一个开源的 NoSQL 图形数据库,它使用了一个节点由关系连接的富数据模型,比传统 RDBMS 的方式更适合连接大数据. Spring Boot 为 Neo4j 提供了便捷引入方式,包括 spring-boot-starter-data-neo4j
starter.
11.3.1. 连接 Neo4j 数据库
您可以像任何 Spring Bean 一样注入一个自动配置的 org.neo4j.ogm.session.Session
. 默认情况下, 该实例将尝试使用在 localhost:7687
上使用 Bolt 协议连接到 Neo4j 服务器,以下示例展示了如何注入 一个 Neo4j Session
:
@Component
public class MyBean {
private final Session session;
@Autowired
public MyBean(Session session) {
this.session = session;
// ...
您可以通过配置 spring.data.neo4j.*
属性来设置 uri 和凭据:
spring.data.neo4j.uri=bolt://my-server:7687
spring.data.neo4j.username=neo4j
spring.data.neo4j.password=secret
您可以通过添加自己的 org.neo4j.ogm.config.Configuration
Bean 来完全控制 session 创建. 此外,添加 SessionFactory
类型的 Bean 会禁用自动配置,因此您可以掌控所有.
11.3.2. 使用内嵌模式
如果您将 org.neo4j:neo4j-ogm-embedded-driver
添加到应用程序的依赖中,Spring Boot 将自动配置一个进程内内嵌的 Neo4j 实例,当您的应用程序关闭时,该实例将不会保留任何数据.
import org.springframework.data.neo4j.repository.*;
public interface CityRepository extends Neo4jRepository<City, Long> {
Optional<City> findOneByNameAndState(String name, String state);
spring-boot-starter-data-neo4j
starter 支持资源库和事务管理. 您可以在 @Configuration
bean 上分别使用 @EnableNeo4jRepositories
和 @EntityScan
来自定义位置以查找资源库和实体.
11.4. Solr
Apache Solr 是一个搜素引擎. Spring Boot 为 Solr 5 客户端类库提供了基本的自动配置,并且 Spring Data Solr 为其提供给了顶层抽象. 相关的依赖包含在了 spring-boot-starter-data-solr
starter 中.
11.4.1. 连接 Solr
您可以像其他 Spring Bean 一样注入一个自动配置的 SolrClient
实例. 默认情况下,该实例将尝试通过 localhost:8983/solr
连接到服务器,以下示例展示了如何注入一个 Solr bean:
@Component
public class MyBean {
private SolrClient solr;
@Autowired
public MyBean(SolrClient solr) {
this.solr = solr;
// ...
如果您添加了自己的 SolrClient
类型的 @Bean
,它将替换掉默认配置.
11.4.2. Spring Data Solr 资源库
Spring Data 包含了对 Apache Solr 资源库的支持. 与之前讨论的 JPA 资源库一样,基本原理是根据方法名称自动构造查询.
事实上,Spring Data JPA 和 Spring Data Solr 共享了相同的通用底层代码,因此您可以使用之前的 JPA 示例作为基础,假设 City
现在是一个 @SolrDocument
类,而不是一个 JPA @Entity
,它的工作方式相同.
11.5. Elasticsearch
Elasticsearch 是一个开源、分布式、RESTful 的实时搜索分析引擎. Spring Boot 为 Elasticsearch 提供了基本的自动配置.
Spring Boot 支持以下 HTTP 客户端:
Spring Boot 支持以下 HTTP 客户端:
Spring Data Elasticsearch 依旧使用传输客户端,但是Spring Data Elasticsearch和Elasticsearch本身已弃用了它的支持. 它将在将来的版本中删除. 您可以使用 spring-boot-starter-data-elasticsearch starter 引入使用它.
由于Elasticsearch和Spring Data Elasticsearch为REST客户端提供了官方支持,因此 Jest 客户端也已被弃用.
11.5.1. 使用 REST 客户端连接 Elasticsearch
Elasticsearch 提供了 两个可用于查询集群的 REST 客户端 : Low Level (低级) 和 High Level (高级) .
如果您的 classpath 上存在 org.elasticsearch.client:elasticsearch-rest-client
依赖,则 Spring Boot 将自动配置并注册默认目标为 localhost:9200
的 RestClient
bean. 您可以进一步调整 RestClient
的配置,如下所示:
spring.elasticsearch.rest.uris=https://search.example.com:9200
spring.elasticsearch.rest.read-timeout=10s
spring.elasticsearch.rest.username=user
spring.elasticsearch.rest.password=secret
您还可以注册实现任意数量的 RestClientBuilderCustomizer
bean,以进行更高级的自定义. 要完全控制注册流程,请定义 RestClient bean.
如果你 classpath 上有 org.elasticsearch.client:elasticsearch-rest-high-level-client
依赖,Spring Boot 将自动配置一个 RestHighLevelClient
,它包装了所有现有的 RestClient
bean,重用其 HTTP 配置.
11.5.2. 使用 Reactive REST 客户端连接
Spring Data Elasticsearch 提供了 ReactiveElasticsearchClient
,用于以响应式查询 Elasticsearch
实例. 它基于 WebFlux的WebClient
构建,因此 spring-boot-starter-elasticsearch
和 spring-boot-starter-webflux
依赖.
默认情况下,Spring Boot将自动配置并注册一个针对 localhost:9200
的 ReactiveElasticsearchClient
bean. 您可以进一步调整其配置,如以下示例所示:
spring.data.elasticsearch.client.reactive.endpoints=search.example.com:9200
spring.data.elasticsearch.client.reactive.use-ssl=true
spring.data.elasticsearch.client.reactive.socket-timeout=10s
spring.data.elasticsearch.client.reactive.username=user
spring.data.elasticsearch.client.reactive.password=secret
如果配置属性不够,并且您想完全控制客户端配置,则可以注册自定义 ClientConfiguration
bean.
11.5.3. 使用 Jest 连接 Elasticsearch
现在,Spring Boot支持官方的 RestHighLevelClient
,不再支持 Jest
.
如果您的 classpath 上存在 Jest
,则可以注入一个默认目标为
localhost:9200
. 的自动配置 JestClient
. 您还可以进一步调整客户端配置:
spring.elasticsearch.jest.uris=https://search.example.com:9200
spring.elasticsearch.jest.read-timeout=10000
spring.elasticsearch.jest.username=user
spring.elasticsearch.jest.password=secret
您还可以注册任何数量实现了 HttpClientConfigBuilderCustomizer
的 bean,以进行更加高级的自定义. 以下示例调整了其他 HTTP 设置:
static class HttpSettingsCustomizer implements HttpClientConfigBuilderCustomizer {
@Override
public void customize(HttpClientConfig.Builder builder) {
builder.maxTotalConnection(100).defaultMaxTotalConnectionPerRoute(5);
要完全控制注册流程,请定义一个 JestClient
bean.
11.5.4. 使用 Spring Data 连接 Elasticsearch
要连接 Elasticsearch,必须定义由Spring Boot自动配置或由应用程序手动提供的 RestHighLevelClient
bean (请参阅前面的部分) . 有了此配置后,可以像其他任何Spring bean一样注入 ElasticsearchRestTemplate
,如以下示例所示:
@Component
public class MyBean {
private final ElasticsearchRestTemplate template;
public MyBean(ElasticsearchRestTemplate template) {
this.template = template;
// ...
如果存在 spring-data-elasticsearch
和使用 WebClient
所需的依赖关系 (通常是 spring-boot-starter-webflux
) 的情况下,Spring Boot还可以将 ReactiveElasticsearchClient 和 ReactiveElasticsearchTemplate
自动配置为bean. 它们与其他REST客户端是等效的.
11.5.5. Spring Data Elasticsearch 资源库
Spring Data 包含了对 Elasticsearch 资源库的支持,与之前讨论的 JPA 资源库一样,其原理是根据方法名称自动构造查询.
事实上,Spring Data JPA 与 Spring Data Elasticsearch 共享了相同的通用底层代码,因此您可以使用之前的 JPA 示例作为基础,假设 City
此时是一个 Elasticsearch @Document
类,而不是一个 JPA @Entity
,它以相同的方式工作.
Spring Boot使用 ElasticsearchRestTemplate
或 ReactiveElasticsearchTemplate
bean支持经典和响应式式 Elasticsearch 资源库. 给定所需的依赖,最有可能由Spring Boot自动配置这些bean.
如果您希望使用自己的模板来支持Elasticsearch存储库,则可以添加自己的 ElasticsearchRestTemplate
或 ElasticsearchOperations
@Bean,只要它名为 "elasticsearchTemplate" 即可. 同样适用于 ReactiveElasticsearchTemplate
和 ReactiveElasticsearchOperations
,其bean名称为 "reactiveElasticsearchTemplate".
您可以选择使用以下属性禁用存储库支持:
spring.data.elasticsearch.repositories.enabled=false
11.6. Cassandra
Cassandra 是一个开源的分布式数据库管理系统,旨在处理商用服务器上的大量数据. Spring Boot 为 Cassandra 提供了自动配置,且 Spring Data Cassandra 为其提供了顶层抽象. 相关依赖包含在 spring-boot-starter-data-cassandra starter 中.
11.6.1. 连接 Cassandra
您可以像其他 Spring Bean 一样注入一个自动配置的 CassandraTemplate
或 Cassandra Session
实例. spring.data.cassandra.* 属性可用于自定义连接. 通常,您会提供 keyspace-name
和 contact-points
属性:
spring.data.cassandra.keyspace-name=mykeyspace
spring.data.cassandra.contact-points=cassandrahost1,cassandrahost2
您还可以注册任意数量实现了 ClusterBuilderCustomizer
的 bean,以进行更高级的自定义.
以下代码展示了如何注入一个 Cassandra bean:
@Component
public class MyBean {
private CassandraTemplate template;
public MyBean(CassandraTemplate template) {
this.template = template;
// ...
如果您添加了自己的类的为 @CassandraTemplate
的 @Bean
,则其将替代默认值.
11.6.2. Spring Data Cassandra 资源库
Spring Data 包含了基本的 Cassandra 资源库支持. 目前,其限制要比之前讨论的 JPA 资源库要多,并且需要在 finder 方法上使用 @Query
注解.
11.7. Couchbase
Couchbase 是一个开源、分布式多模型的 NoSQL 面向文档数据库,其针对交互式应用程序做了优化. Spring Boot 为 Couchbase 提供了自动配置,
且 Spring Data Couchbase 为其提供了顶层抽象. 相关的依赖包含在了 spring-boot-starter-data-couchbase starter 中.
11.7.1. 连接 Couchbase
您可以通过添加 Couchbase SDK 和一些配置来轻松获取 Bucket
和 Cluster
. spring.couchbase.*
属性可用于自定义连接. 通常您会配置 bootstrap host、bucket name 和 password:
spring.couchbase.bootstrap-hosts=my-host-1,192.168.1.123
spring.couchbase.bucket.name=my-bucket
spring.couchbase.bucket.password=secret
spring.couchbase.env.timeouts.connect=3000
spring.couchbase.env.ssl.key-store=/location/of/keystore.jks
spring.couchbase.env.ssl.key-store-password=secret
查看 spring.couchbase.env.*
获取更多详细内容.
11.7.2. Spring Data Couchbase 资源库
Spring Data 包含了 Couchbase 资源库支持. 有关 Spring Data Couchbase 的完整详细信息,请参阅其 参考文档.
您可以像使用其他 Spring Bean 一样注入自动配置的 CouchbaseTemplate
实例,前提是有一个默认的 CouchbaseConfigurer
(当您启用 Couchbase 支持时会发生这种情况,如之前所述) .
以下示例展示了如何注入一个 Couchbase bean:
@Component
public class MyBean {
private final CouchbaseTemplate template;
@Autowired
public MyBean(CouchbaseTemplate template) {
this.template = template;
// ...
您可以在自己的配置中定义以下几个 bean,以覆盖自动配置提供的配置:
@Bean(BeanNames.COUCHBASE_CUSTOM_CONVERSIONS)
public CustomConversions myCustomConversions() {
return new CustomConversions(...);
// ...
11.8. LDAP
LDAP (Lightweight Directory Access Protocol,轻量级目录访问协议) 是一个开放、厂商中立的行业标准应用协议,其通过 IP 网络访问和维护分布式目录信息服务.
Spring Boot 为兼容 LDAP 服务器提供了自动配置,以及支持从 UnboundID 内嵌内存式 LDAP 服务器.
Spring Data LDAP 提供了 LDAP 抽象. 相关依赖包含在了 spring-boot-starter-data-ldap
starter 中.
11.8.1. 连接 LDAP 服务器
要连接 LDAP 服务器,请确保您已经声明了 spring-boot-starter-data-ldap
starter 或者 spring-ldap-core
依赖,然后在 application.properties
声明服务器的 URL:
spring.ldap.urls=ldap://myserver:1235
spring.ldap.username=admin
spring.ldap.password=secret
如果需要自定义连接设置,您可以使用 spring.ldap.base
和 spring.ldap.base-environment
属性.
LdapContextSource
将根据这些设置自动配置. 如果您需要自定义它,例如使用一个 PooledContextSource
,则仍然可以注入自动配置的 LdapContextSource
. 确保将自定义的 ContextSource
标记为 @Primary
,以便自动配置的 LdapTemplate
能使用它.
11.8.2. Spring Data LDAP 资源库
Spring Data 包含了 LDAP 资源库支持. 有关 Spring Data LDAP 的完整详细信息,请参阅其 参考文档.
您还可以像其他 Spring Bean 一样注入一个自动配置的 LdapTemplate
实例:
@Component
public class MyBean {
private final LdapTemplate template;
@Autowired
public MyBean(LdapTemplate template) {
this.template = template;
// ...
如果您的 classpath 上存在一个 schema.ldif
文件,其将用于初始化服务器. 如果您想从不同的资源中加载脚本,可以使用 spring.ldap.embedded.ldif
属性.
默认情况下,将使用一个标准模式 (schema) 来校验 LDIF
文件. 您可以使用 spring.ldap.embedded.validation.enabled
属性来关闭所有校验. 如果您有自定义的属性,则可以使用 spring.ldap.embedded.validation.schema
来定义自定义属性类型或者对象类.
11.9. InfluxDB
InfluxDB 是一个开源时列数据库,其针对运营监控、应用程序指标、物联网传感器数据和实时分析等领域中的时间序列数据在速度、高可用存储和检索方面进行了优化.
11.9.1. 连接 InfluxDB
Spring Boot 自动配置 InfluxDB
实例,前提是 Influxdb-java
客户端在 classpath 上并且设置了数据库的 URL,如下所示:
spring.influx.url=https://172.0.0.1:8086
如果与 InfluxDB 的连接需要用户和密码,则可以相应地设置 spring.influx.user
和 spring.influx.password
属性.
InfluxDB
依赖于 OkHttp. 如果你需要调整 InfluxDB 在底层使用的 http 客户端,则可以注册一个 InfluxDbOkHttpClientBuilderProvider
bean.
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
@Component
public class MathService {
@Cacheable("piDecimals")
public int computePiDecimal(int i) {
// ...
此示例展示了如何在代价可能高昂的操作上使用缓存. 在调用 computePiDecimal
之前,缓存支持会在 piDecimals
缓存中查找与 i
参数匹配的项. 如果找到,则缓存中的内容会立即返回给调用者,并不会调用该方法. 否则,将调用该方法,并在返回值之前更新缓存.
如果您不添加任何指定的缓存库,Spring Boot 会自动配置一个使用并发 map 的 simple provider . 当需要缓存时 (例如前面示例中的 piDecimals
) ,该 simple provider 会为您创建缓存. 不推荐将 simple provider 用于生产环境,但它非常适合入门并帮助您了解这些功能.
当您决定使用缓存提供者时,请务必阅读其文档以了解如何配置应用程序. 几乎所有提供者都要求您显式配置应用程序中使用的每个缓存. 有些提供了自定义 spring.cache.cache-names
属性以定义默认缓存.
12.1. 支持的缓存提供者
缓存抽象不提供存储实现,其依赖于 org.springframework.cache.Cache
和 org.springframework.cache.CacheManager
接口实现的抽象.
如果您未定义 CacheManager
类型的 bean 或名为 cacheResolver
的 CacheResolver
(请参阅 CachingConfigurer
) ,则 Spring Boot 会尝试检测以下提供者 (按序号顺序) :
@Bean
public CacheManagerCustomizer<ConcurrentMapCacheManager> cacheManagerCustomizer() {
return new CacheManagerCustomizer<ConcurrentMapCacheManager>() {
@Override
public void customize(ConcurrentMapCacheManager cacheManager) {
cacheManager.setAllowNullValues(false);
12.1.2. JCache (JSR-107)
JCache 通过 classpath 上的 javax.cache.spi.CachingProvider
(即 classpath 上存在符合 JSR-107 的缓存库) 来引导,jCacheCacheManager
由 spring-boot-starter-cache
starter 提供. 您可以使用各种兼容库,Spring Boot 为 Ehcache 3、Hazelcast 和 Infinispan 提供依赖管理. 您还可以添加任何其他兼容库.
可能存在多个提供者,在这种情况下必须明确指定提供者. 即使 JSR-107 标准没有强制规定一个定义配置文件位置的标准化方法,Spring Boot 也会尽其所能设置一个包含实现细节的缓存,如下所示:
# Only necessary if more than one provider is present
spring.cache.jcache.provider=com.acme.MyCachingProvider
spring.cache.jcache.config=classpath:acme.xml
可以通过设置 spring.cache.cache-names
属性在启动时创建缓存. 如果定义了自定义 javax.cache.configuration.Configuration
bean,则会使用它来自定义.
使用 CacheManager
的引用调用 org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer
bean 以进行完全自定义.
12.1.6. Couchbase
如果 Couchbase Java 客户端和 couchbase-spring-cache
实现可用且已经配置了 Couchbase
,则应用程序会自动配置一个 CouchbaseCacheManager
. 也可以通过设置 spring.cache.cache-names
属性在启动时创建其他缓存. 这些缓存在自动配置的 Bucket
上操作.
您还可以使用 customizer 在其他 Bucket
上创建缓存. 假设您需要在 main Bucket
上有两个缓存 (cache1
和 cache2
) ,并且 “another” Bucket
有一个过期时间为 2 秒的缓存 (cache3
) . 您可以通过配置创建这两个缓存,如下所示:
spring.cache.cache-names=cache1,cache2
然后,您可以定义一个 @Configuration
类来配置其他 Bucket
和 cache3
缓存,如下所示:
@Configuration(proxyBeanMethods = false)
public class CouchbaseCacheConfiguration {
private final Cluster cluster;
public CouchbaseCacheConfiguration(Cluster cluster) {
this.cluster = cluster;
@Bean
public Bucket anotherBucket() {
return this.cluster.openBucket("another", "secret");
@Bean
public CacheManagerCustomizer<CouchbaseCacheManager> cacheManagerCustomizer() {
return c -> {
c.prepareCache("cache3", CacheBuilder.newInstance(anotherBucket())
.withExpiration(2));
此示例配置复用了通过自动配置创建的 Cluster
.
12.1.7. Redis
如果 Redis 可用并已经配置,则应用程序会自动配置一个 RedisCacheManager
. 通过设置 spring.cache.cache-names
属性可以在启动时创建其他缓存,并且可以使用 spring.cache.redis.*
属性配置缓存默认值. 例如,以下配置创建 cache1
和 cache2
缓存,他们的有效时间为 10 分钟:
spring.cache.cache-names=cache1,cache2
spring.cache.redis.time-to-live=600000
如果您需要控制更多的配置,请考虑注册 RedisCacheManagerBuilderCustomizer
bean.
以下示例显示了一个自定义的配置,该定制器配置了 cache1
和 cache2
的特定生存时间
The following example shows a customizer that configures a specific time to live for cache1
and cache2
:
@Bean
public RedisCacheManagerBuilderCustomizer myRedisCacheManagerBuilderCustomizer() {
return (builder) -> builder
.withCacheConfiguration("cache1",
RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(10)))
.withCacheConfiguration("cache2",
RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(1)));
12.1.8. Caffeine
Caffeine 是一个使用了 Java 8 重写 Guava 缓存,用于取代 Guava 支持的缓存库. 如果 Caffeine 存在,则应用程序会自动配置一个 CaffeineCacheManager
(由 spring-boot-starter-cache
starter 提供) .
可以通过设置 spring.cache.cache-names
属性在启动时创建缓存,并且可以通过以下方式之一 (按序号顺序) 自定义缓存:
Spring Framework 为消息传递系统集成提供了广泛的支持,从使用 JmsTemplate
简化 JMS API 的使用到异步接收消息的完整基础设施. Spring AMQP 为高级消息队列协议 (Advanced Message Queuing Protocol,AMQP) 提供了类似的功能集合. Spring Boot 还为 RabbitTemplate
和 RabbitMQ 提供自动配置选项. Spring WebSocket 本身包含了对 STOMP 消息传递的支持,Spring Boot 通过 starter 和少量自动配置即可支持它. Spring Boot 同样支持 Apache Kafka.
13.1. JMS
javax.jms.ConnectionFactory
接口提供了一种创建 javax.jms.Connection
的标准方法,可与 JMS broker (代理) 进行交互. 虽然 Spring 需要一个 ConnectionFactory
来与 JMS 一同工作,但是您通常不需要自己直接使用它,而是可以依赖更高级别的消息传递抽象. (有关详细信息,请参阅 Spring Framework 参考文档的相关部分. ) Spring Boot 还会自动配置发送和接收消息所需的基础设施.
13.1.1. ActiveMQ 支持
当 ActiveMQ 在 classpath 上可用时,Spring Boot 也可以配置一个 ConnectionFactory
. 如果 broker 存在,则会自动启动并配置一个内嵌式 broker (前提是未通过配置指定 broder URL) .
13.1.2. Artemis 支持
Spring Boot 可以在检测到 Artemis 在 classpath 上可用时自动配置一个 ConnectionFactory
. 如果存在 broker,则会自动启动并配置一个内嵌 broker (除非已明确设置 mode 属性) .
支持的 mode 为 embedded
(明确表示需要一个内嵌 broker,如果 broker 在 classpath 上不可用则发生错误) 和 native
(使用 netty
传输协议连接到 broker) . 配置后者后,Spring Boot 会使用默认设置配置一个 ConnectionFactory
,该 ConnectionFactory
连接到在本地计算机上运行的 broker.
内嵌 broker 时,您可以选择是否要启用持久化并列出应该可用的 destination. 可以将这些指定为以逗号分隔的列表,以使用默认选项创建它们,也可以定义类型为 org.apache.activemq.artemis.jms.server.config.JMSQueueConfiguration
或 org.apache.activemq.artemis.jms.server.config.TopicConfiguration
的 bean,分别用于高级队列和 topic (主题) 配置.
默认情况下,CachingConnectionFactory
将原生的 ConnectionFactory
使用可由 spring.jms.*
中的外部配置属性控制的合理设置包装起来:
spring.jms.cache.session-cache-size=5
如果您更愿意使用原生池,则可以通过向 org.messaginghub:pooled-jms
添加一个依赖并相应地配置 JmsPoolConnectionFactory
来实现,如下所示:
spring.artemis.pool.enabled=true
spring.artemis.pool.max-connections=50
有关更多支持的选项,请参阅 ArtemisProperties
.
不涉及 JNDI 查找,使用 Artemis 配置中的 name
属性或通过配置提供的名称来解析目标 (destination) 名称.
13.1.3. 使用 JNDI ConnectionFactory
如果您在应用程序服务器中运行应用程序,Spring Boot 会尝试使用 JNDI 找到 JMS ConnectionFactory
. 默认情况下,将检查 java:/JmsXA
和 java:/XAConnectionFactory
这两个位置. 如果需要指定其他位置,可以使用 spring.jms.jndi-name
属性,如下所示:
spring.jms.jndi-name=java:/MyConnectionFactory
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
private final JmsTemplate jmsTemplate;
@Autowired
public MyBean(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
// ...
13.1.5. 接收消息
当存在 JMS 基础设施时,可以使用 @JmsListener
对任何 bean 进行注解以创建监听器 (listener) 端点. 如果未定义 JmsListenerContainerFactory
,则会自动配置一个默认的 (factory) . 如果定义了 DestinationResolver
或 MessageConverter
bean,它将自动关联到默认的 factory.
默认情况下,默认 factory 是具有事务特性的. 如果您在存在有 JtaTransactionManager
的基础设施中运行,则默认情况下它与监听器容器相关联. 如果不是,则 sessionTransacted
flag 将为启用 (enabled) . 在后一种情况下,您可以通过在监听器方法 (或其委托) 上添加 @Transactional
,将本地数据存储事务与传入消息的处理相关联. 这确保了在本地事务完成后传入消息能被告知. 这还包括了发送已在同一 JMS 会话上执行的响应消息.
以下组件在 someQueue
destination 上创建一个监听器端点:
@Component
public class MyBean {
@JmsListener(destination = "someQueue")
public void processMessage(String content) {
// ...
如果需要创建更多 JmsListenerContainerFactory
实例或覆盖默认值,Spring Boot 会提供一个 DefaultJmsListenerContainerFactoryConfigurer
,您可以使用它来初始化 DefaultJmsListenerContainerFactory
,其设置与自动配置的 factory 设置相同.
例如,以下示例暴露了另一个使用特定 MessageConverter
的 factory:
@Configuration(proxyBeanMethods = false)
static class JmsConfiguration {
@Bean
public DefaultJmsListenerContainerFactory myFactory(
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory =
new DefaultJmsListenerContainerFactory();
configurer.configure(factory, connectionFactory());
factory.setMessageConverter(myMessageConverter());
return factory;
然后,您可以在任何 @JmsListener
注解的方法中使用该 factory,如下所示:
@Component
public class MyBean {
@JmsListener(destination = "someQueue", containerFactory="myFactory")
public void processMessage(String content) {
// ...
13.2. AMQP
高级消息队列协议 (Advanced Message Queuing Protocol,AMQP) 是一个平台无关,面向消息中间件的连接级协议. Spring AMQP 项目将核心 Spring 概念应用于基于 AMQP 消息传递解决方案的开发. Spring Boot 为通过 RabbitMQ 使用 AMQP 提供了一些快捷方法,包括 spring-boot-starter-amqp
starter.
13.2.1. RabbitMQ 支持
RabbitMQ 是一个基于 AMQP 协议的轻量级、可靠、可扩展且可移植的消息代理. Spring 使用 RabbitMQ 通过 AMQP 协议进行通信.
RabbitMQ 配置由 spring.rabbitmq.*
中的外部配置属性控制. 例如,您可以在 application.properties
中声明以下部分:
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=secret
另外,您可以配置相同 addresses
属性的连接:
spring.rabbitmq.addresses=amqp://admin:secret@localhost
如果上下文中存在 ConnectionNameStrategy
bean,它将自动用于命名由自动配置的 ConnectionFactory
所创建的连接. 有关更多支持的选项,请参阅 RabbitProperties
.
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
private final AmqpAdmin amqpAdmin;
private final AmqpTemplate amqpTemplate;
@Autowired
public MyBean(AmqpAdmin amqpAdmin, AmqpTemplate amqpTemplate) {
this.amqpAdmin = amqpAdmin;
this.amqpTemplate = amqpTemplate;
// ...
13.2.3. 接收消息
当 Rabbit 基础设施存在时,可以使用 @RabbitListener
注解任何 bean 以创建监听器端点. 如果未定义 RabbitListenerContainerFactory
,则会自动配置一个默认的 SimpleRabbitListenerContainerFactory
,您可以使用 spring.rabbitmq.listener.type
属性切换到一个直接容器. 如果定义了 MessageConverter
或 MessageRecoverer
bean,它将自动与默认 factory 关联.
以下示例组件在 someQueue
队列上创建一个监听监听器端点:
@Component
public class MyBean {
@RabbitListener(queues = "someQueue")
public void processMessage(String content) {
// ...
@Bean
public SimpleRabbitListenerContainerFactory myFactory(
SimpleRabbitListenerContainerFactoryConfigurer configurer) {
SimpleRabbitListenerContainerFactory factory =
new SimpleRabbitListenerContainerFactory();
configurer.configure(factory, connectionFactory);
factory.setMessageConverter(myMessageConverter());
return factory;
然后,您可以在任何 @RabbitListener
注解的方法中使用该 factory,如下所示:
@Component
public class MyBean {
@RabbitListener(queues = "someQueue", containerFactory="myFactory")
public void processMessage(String content) {
// ...
您可以启用重试机制来处理监听器的异常抛出情况. 默认情况下使用 RejectAndDontRequeueRecoverer
,但您可以定义自己的 MessageRecoverer
. 如果 broker 配置了重试机制,当重试次数耗尽时,则拒绝消息并将其丢弃或路由到死信 (dead-letter) exchange 中.
默认情况下重试机制为禁用. 您还可以通过声明 RabbitRetryTemplateCustomizer
bean 以编程方式自定义 RetryTemplate
.
@Autowired
public MyBean(KafkaTemplate kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate;
// ...
13.3.2. 接收消息
当存在 Apache Kafka 基础设施时,可以使用 @KafkaListener
注解任何 bean 以创监听器端点. 如果未定义 KafkaListenerContainerFactory
,则会使用 spring.kafka.listener.*
中定义的 key 自动配置一个默认的 factory.
以下组件在 someTopic
topic 上创建一个监听器端点:
@Component
public class MyBean {
@KafkaListener(topics = "someTopic")
public void processMessage(String content) {
// ...
如果定义了 KafkaTransactionManager
bean,它将自动关联到容器 factory. 同样,如果定义了 RecordMessageConverter
、ErrorHandler
或 AfterRollbackProcessor
bean,它将自动关联到默认的 factory.
根据监听器类型,将 RecordMessageConverter
或 BatchMessageConverter
bean与默认工厂关联. 如果对于批处理监听器仅存在一个 RecordMessageConverter
bean,则将其包装在 BatchMessageConverter
中.
13.3.3. Kafka Streams
Spring for Apache Kafka 提供了一个工厂 bean 来创建 StreamsBuilder
对象并管理其 stream (流) 的生命周期. 只要 kafka-streams
在 classpath 上并且通过 @EnableKafkaStreams
注解启用了 Kafka Stream,Spring Boot 就会自动配置所需的 KafkaStreamsConfiguration
bean.
启用 Kafka Stream 意味着必须设置应用程序 id 和引导服务器 (bootstrap server) . 可以使用 spring.kafka.streams.application-id
配置前者,如果未设置则默认为 spring.application.name
. 后者可以全局设置或专门为 stream 而重写.
使用专用 properties 可以设置多个其他属性,可以使用 spring.kafka.streams.properties
命名空间设置其他任意 Kafka 属性. 有关更多信息,另请参见 Kafka 属性 .
要使用 factory bean,只需将 StreamsBuilder
装配到您的 @Bean
中,如下所示:
@Configuration(proxyBeanMethods = false)
@EnableKafkaStreams
public static class KafkaStreamsExampleConfiguration {
@Bean
public KStream<Integer, String> kStream(StreamsBuilder streamsBuilder) {
KStream<Integer, String> stream = streamsBuilder.stream("ks1In");
stream.map((k, v) -> new KeyValue<>(k, v.toUpperCase())).to("ks1Out",
Produced.with(Serdes.Integer(), new JsonSerde<>()));
return stream;
默认情况下,由其创建的 StreamBuilder
对象管理的流会自动启动. 您可以使用 spring.kafka.streams.auto-startup
属性自定义此行为.
13.3.4. 其他 Kafka 属性
自动配置支持的属性可在常见应用程序属性常见应用程序属性中找到. 请注意,在大多数情况下,这些属性 (连接符或驼峰命名) 直接映射到 Apache Kafka 点连形式属性. 有关详细信息,请参阅 Apache Kafka 文档.
这些属性中的前几个适用于所有组件 (生产者 [producer] 、使用者 [consumer] 、管理者 [admin] 和流 [stream] ) ,但如果您希望使用不同的值,则可以在组件级别指定. Apache Kafka 重要性 (优先级) 属性设定为 HIGH、MEDIUM 或 LOW. Spring Boot 自动配置支持所有 HIGH 重要性属性,一些选择的 MEDIUM 和 LOW 属性,以及所有没有默认值的属性.
只有 Kafka 支持的属性的子集可以直接通过 KafkaProperties
类获得. 如果您希望使用不受支持的其他属性配置生产者或消费者,请使用以下属性:
spring.kafka.properties.prop.one=first
spring.kafka.admin.properties.prop.two=second
spring.kafka.consumer.properties.prop.three=third
spring.kafka.producer.properties.prop.four=fourth
spring.kafka.streams.properties.prop.five=fifth
这将常见的 prop.one
Kafka 属性设置为 first
(适用于生产者、消费者和管理者) ,prop.two
管理者属性为 second
,prop.three
消费者属性为 third
,prop.four
生产者属性为 fourth
,prop.five
流属性为 fifth
.
您还可以按如下方式配置 Spring Kafka JsonDeserializer
:
spring.kafka.consumer.value-deserializer=org.springframework.kafka.support.serializer.JsonDeserializer
spring.kafka.consumer.properties.spring.json.value.default.type=com.example.Invoice
spring.kafka.consumer.properties.spring.json.trusted.packages=com.example,org.acme
同样,您可以禁用 JsonSerializer
在 header 中发送类型信息的默认行为:
spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer
spring.kafka.producer.properties.spring.json.add.type.headers=false
13.3.5. 使用嵌入式 Kafka 进行测试
Spring 为 Apache Kafka 提供了一种使用嵌入式Apache Kafka代理测试项目的便捷方法. 要使用此功能,请在 spring-kafka-test
模块中使用 @EmbeddedKafka
注解测试类. 有关更多信息,请参阅Spring for Apache Kafka 参考手册.
要使Spring Boot自动配置与上述嵌入式Apache Kafka代理一起使用,您需要将嵌入式代理地址 (由 EmbeddedKafkaBroker
填充) 的系统属性重新映射到Apache Kafka的Spring Boot配置属性中. 有几种方法可以做到这一点:
static {
System.setProperty(EmbeddedKafkaBroker.BROKER_LIST_PROPERTY, "spring.kafka.bootstrap-servers");
如果您的应用程序需要调用远程 REST 服务,这可以使用 Spring Framework 的 RestTemplate 类. 由于 RestTemplate
实例在使用之前通常需要进行自定义,因此 Spring Boot 不提供任何自动配置的 RestTemplate
bean. 但是,
它会自动配置 RestTemplateBuilder
,可在需要时创建 RestTemplate
实例. 自动配置的 RestTemplateBuilder
确保将合适的 HttpMessageConverters
应用于 RestTemplate
实例.
以下代码展示了一个典型示例:
@Service
public class MyService {
private final RestTemplate restTemplate;
public MyService(RestTemplateBuilder restTemplateBuilder) {
this.restTemplate = restTemplateBuilder.build();
public Details someRestCall(String name) {
return this.restTemplate.getForObject("/{name}/details", Details.class, name);
要想自定义的作用域尽可能地窄,请注入自动配置的 RestTemplateBuilder
,然后根据需要调用其方法. 每个方法调用都返回一个新的 RestTemplateBuilder
实例,因此自定义只会影响当前构建器.
要在应用程序作用域内添加自定义配置,请使用 RestTemplateCustomizer
bean. 所有这些 bean 都会自动注册到自动配置的 RestTemplateBuilder
,并应用于使用它构建的所有模板.
以下示例展示了一个 customizer,它为除 192.168.0.5
之外的所有主机配置代理:
static class ProxyCustomizer implements RestTemplateCustomizer {
@Override
public void customize(RestTemplate restTemplate) {
HttpHost proxy = new HttpHost("proxy.example.com");
HttpClient httpClient = HttpClientBuilder.create().setRoutePlanner(new DefaultProxyRoutePlanner(proxy) {
@Override
public HttpHost determineProxy(HttpHost target, HttpRequest request, HttpContext context)
throws HttpException {
if (target.getHostName().equals("192.168.0.5")) {
return null;
return super.determineProxy(target, request, context);
}).build();
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
最后,最极端 (也很少使用) 的选择是创建自己的 RestTemplateBuilder
bean. 这样做会关闭 RestTemplateBuilder
的自动配置,并阻止使用任何 RestTemplateCustomizer
bean.
如果在 classpath 上存在 Spring WebFlux,则还可以选择使用 WebClient
来调用远程 REST 服务. 与 RestTemplate
相比,该客户端更具函数式风格并且完全响应式. 您可以在 Spring Framework 文档的相关部分中了解有关 WebClient
的更多信息.
Spring Boot 为您创建并预配置了一个 WebClient.Builder
. 强烈建议将其注入您的组件中并使用它来创建 WebClient
实例. Spring Boot 配置该构建器以共享 HTTP 资源,以与服务器相同的方式反射编解码器设置 (请参阅 WebFlux HTTP 编解码器自动配置) 等.
以下代码是一个典型示例:
@Service
public class MyService {
private final WebClient webClient;
public MyService(WebClient.Builder webClientBuilder) {
this.webClient = webClientBuilder.baseUrl("https://example.org").build();
public Mono<Details> someRestCall(String name) {
return this.webClient.get().uri("/{name}/details", name)
.retrieve().bodyToMono(Details.class);
15.1. WebClient 运行时
Spring Boot 将自动检测用于驱动 WebClient
的 ClientHttpConnector
,具体取决于应用程序 classpath 上可用的类库. 目前支持 Reactor Netty 和 Jetty RS 客户端.
默认情况下 spring-boot-starter-webflux
starter 依赖于 io.projectreactor.netty:reactor-netty
,它包含了服务器和客户端的实现. 如果您选择将 Jetty 用作响应式服务器,则应添加 Jetty Reactive HTTP 客户端库依赖 org.eclipse.jetty:jetty-reactive-httpclient
. 服务器和客户端使用相同的技术具有一定优势,因为它会自动在客户端和服务器之间共享 HTTP 资源.
开发人员可以通过提供自定义的 ReactorResourceFactory
或 JettyResourceFactory
bean 来覆盖 Jetty 和 Reactor Netty 的资源配置 —— 这将同时应用于客户端和服务器.
如果您只希望覆盖客户端选项,则可以定义自己的 ClientHttpConnector
bean 并完全控制客户端配置.
您可以在 Spring Framework 参考文档中了解有关 WebClient
配置选项的更多信息.
15.2. 自定义 WebClient
WebClient
自定义有三种主要方法,具体取决于您希望自定义的程度.
要想自定义的作用域尽可能地窄,请注入自动配置的 WebClient.Builder
,然后根据需要调用其方法. WebClient.Builder
实例是有状态的: 构建器上的任何更改都会影响到之后所有使用它创建的客户端. 如果要使用相同的构建器创建多个客户端,可以考虑使用 WebClient.Builder other = builder.clone()
; 的方式克隆构建器.
要在应用程序作用域内对所有 WebClient.Builder
实例添加自定义,可以声明 WebClientCustomizer
bean 并在注入点局部更改 WebClient.Builder
.
最后,您可以回退到原始 API 并使用 WebClient.create(). 在这种情况下,不会应用自动配置或 WebClientCustomizer.
只要 classpath 上存在 JSR-303 实现 (例如 Hibernate 验证器) ,就会自动启用 Bean Validation 1.1 支持的方法验证功能. 这允许 bean 方法在其参数和/或返回值上使用 javax.validation
约束进行注解. 带有此类注解方法的目标类需要在类级别上使用 @Validated
进行注解,以便搜索其内联约束注解的方法.
例如,以下服务触发第一个参数的验证,确保其大小在 8 到 10 之间:
@Service
@Validated
public class MyBean {
public Archive findByCodeAndAuthor(@Size(min = 8, max = 10) String code,
Author author) {
如果 spring.mail.host
和相关库 (由 spring-boot-starter-mail
定义) 可用,则创建默认的 JavaMailSender
(如果不存在) . 可以通过 spring.mail
命名空间中的配置项进一步自定义发件人. 有关更多详细信息,请参阅 MailProperties
.
特别是,某些默认超时时间的值是无限的,您可能想更改它以避免线程被无响应的邮件服务器阻塞,如下示例所示:
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=3000
spring.mail.properties.mail.smtp.writetimeout=5000
也可以使用 JNDI 中的现有 Session
配置一个 JavaMailSender
:
spring.mail.jndi-name=mail/Session
设置 jndi-name
时,它优先于所有其他与 Session 相关的设置.
Spring Boot 通过使用 Atomikos 或 Bitronix 嵌入式事务管理器来支持跨多个 XA 资源的分布式 JTA 事务. 部署在某些 Java EE 应用服务器 (Application Server) 上也支持 JTA 事务.
当检测到 JTA 环境时,Spring 的 JtaTransactionManager
将用于管理事务. 自动配置的 JMS、DataSource 和 JPA bean 已升级为支持 XA 事务. 您可以使用标准的 Spring 方式 (例如 @Transactional
) 来使用分布式事务. 如果您处于 JTA 环境中并且仍想使用本地事务,则可以将 spring.jta.enabled
属性设置为 false
以禁用 JTA 自动配置.
18.1. 使用 Atomikos 事务管理器
Atomikos 是一个流行的开源事务管理器,可以嵌入到 Spring Boot 应用程序中. 您可以使用 spring-boot-starter-jta-atomikos
starter 来获取相应的 Atomikos 库. Spring Boot 自动配置 Atomikos 并确保将合适的依赖设置应用于 Spring bean,以确保启动和关闭顺序正确.
默认情况下,Atomikos 事务日志将写入应用程序主目录 (应用程序 jar 文件所在的目录) 中的 transaction-logs
目录. 您可以通过在 application.properties
文件中设置 spring.jta.log-dir
属性来自定义此目录的位置. 也可用 spring.jta.atomikos.properties
开头的属性来自定义 Atomikos UserTransactionServiceImp
. 有关完整的详细信息,请参阅 AtomikosProperties
Javadoc.
18.2. 使用 Bitronix 事务管理器
Bitronix 是一个流行的开源 JTA 事务管理器实现. 您可以使用 spring-boot-starter-jta-bitronix
starter 为您的项目添加合适的 Bitronix 依赖. 与 Atomikos 一样,Spring Boot 会自动配置 Bitronix 并对 bean 进行后处理 (post-processes) ,以确保启动和关闭顺序正确.
默认情况下,Bitronix 事务日志文件 (part1.btm
和 part2.btm
) 将写入应用程序主目录中的 transaction-logs
目录. 您可以通过设置 spring.jta.log-dir
属性来自定义此目录的位置. 以 spring.jta.bitronix.properties
开头的属性绑定到了 bitronix.tm.Configuration
bean,允许完全自定义. 有关详细信息,请参阅 Bitronix 文档.
18.3. 使用 Java EE 管理的事务管理器
如果将 Spring Boot 应用程序打包为 war
或 ear
文件并将其部署到 Java EE 应用程序服务器,则可以使用应用程序服务器的内置事务管理器. Spring Boot 尝试通过查找常见的 JNDI 位置 (java:comp/UserTransaction
、java:comp/TransactionManager
等) 来自动配置事务管理器. 如果使用应用程序服务器提供的事务服务,
通常还需要确保所有资源都由服务器管理并通过 JNDI 暴露. Spring Boot 尝试通过在 JNDI 路径 (java:/JmsXA
或 java:/JmsXA
) 中查找 ConnectionFactory
来自动配置 JMS,并且可以使用 spring.datasource.jndi-name
属性 属性来配置 DataSource
.
18.4. 混合使用 XA 与非 XA JMS 连接
使用 JTA 时,主 JMS ConnectionFactory
bean 可识别 XA 并参与分布式事务. 在某些情况下,您可能希望使用非 XA ConnectionFactory
处理某些 JMS 消息. 例如,您的 JMS 处理逻辑可能需要比 XA 超时时间更长的时间.
如果要使用非 XA ConnectionFactory
,可以注入 nonXaJmsConnectionFactory
bean 而不是 @Primary
jmsConnectionFactory
bean. 为了保持一致性,提供的 jmsConnectionFactory
bean 还需要使用 xaJmsConnectionFactory
别名.
以下示例展示了如何注入 ConnectionFactory
实例:
// Inject the primary (XA aware) ConnectionFactory
@Autowired
private ConnectionFactory defaultConnectionFactory;
// Inject the XA aware ConnectionFactory (uses the alias and injects the same as above)
@Autowired
@Qualifier("xaJmsConnectionFactory")
private ConnectionFactory xaConnectionFactory;
// Inject the non-XA aware ConnectionFactory
@Autowired
@Qualifier("nonXaJmsConnectionFactory")
private ConnectionFactory nonXaConnectionFactory;
18.5. 支持嵌入式事务管理器
XAConnectionFactoryWrapper
和 XADataSourceWrapper
接口可用于支持其他嵌入式事务管理器. 接口负责包装 XAConnectionFactory
和 XADataSource
bean,并将它们暴露为普通的 ConnectionFactory
和 DataSource
bean,它们透明地加入分布式事务. DataSource
和 JMS 自动配置使用 JTA 变体,前提是您需要有一个 JtaTransactionManager
bean 和在 ApplicationContext
中注册有的相应 XA 包装器 (wrapper) bean.
BitronixXAConnectionFactoryWrapper 和 BitronixXADataSourceWrapper 为如何编写 XA 包装器提供了很好示例.
如果定义了 com.hazelcast.config.Config
bean,则 Spring Boot 会使用它. 如果您的配置定义了实例名称,Spring Boot 会尝试查找现有的实例,而不是创建新实例.
您还可以指定通过配置使用的 Hazelcast 配置文件,如以下示例所示:
spring.hazelcast.config=classpath:config/my-hazelcast.xml
否则,Spring Boot 会尝试从默认位置查找 Hazelcast 配置: 工作目录或 classpath 根目录中的 hazelcast.xml
,或相同位置中的 .yaml
文件. 我们还检查是否设置了 hazelcast.config
系统属性. 有关更多详细信息,请参见 Hazelcast documentation.
如果 classpath 中存在 hazelcast-client
,则 Spring Boot 会首先尝试通过检查以下配置项来创建客户端:
Spring Boot 提供了几种使用 Quartz 调度器的便捷方式,它们来自 spring-boot-starter-quartz
starter. 如果 Quartz 可用,则 Spring Boot 将自动配置 Scheduler
(通过 SchedulerFactoryBean
抽象) .
自动选取以下类型的 Bean 并将其与 Scheduler
关联起来:
要让 Quartz 使用除应用程序主 DataSource
之外的 DataSource
,请声明一个 DataSource
bean,使用 @QuartzDataSource
注解其 @Bean
方法. 这样做可确保 SchedulerFactoryBean
和 schema 初始化都使用 Quartz 指定的 DataSource
.
默认情况下,配置创建的 job 不会覆盖已从持久 job 存储读取的已注册的 job. 要启用覆盖现有的 job 定义,请设置 spring.quartz.overwrite-existing-jobs
属性.
Quartz 调取器配置可以使用 spring.quartz
属性和 SchedulerFactoryBeanCustomizer
bean 进行自定义,它们允许以编程方式的 SchedulerFactoryBean
自定义. 可以使用 spring.quartz.properties.*
自定义高级 Quartz 配置属性.
public void setMyService(MyService myService) { ... }
// Inject the "name" job data property
public void setName(String name) { ... }
@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
如果您在上下文中定义了自定义 Executor
,则常规任务执行 (即 @EnableAsync
) 将透明地使用它,但不会配置 Spring MVC 支持,因为它需要 AsyncTaskExecutor
实现 (名为 applicationTaskExecutor
) . 根据您的目标安排,您可以将 Executor
更改为 ThreadPoolTaskExecutor
,或者定义 Executor
的 ThreadPoolTaskExecutor
和 AsyncConfigurer
来包装自定义的 Executor
.
您可以使用自动配置的 TaskExecutorBuilder
来轻松创建实例,以复制默认的自动配置.
这会将线程池更改为使用有界队列,在队列满 (100 个任务) 时,线程池将增加到最多 16 个线程. 当线程在闲置10 秒 (而不是默认的 60 秒) 时回收线程,池的收缩更为明显.
如果需要与调度任务执行 (@EnableScheduling
) 相关联,可以自动配置一个 ThreadPoolTaskScheduler
. 默认情况下,线程池使用一个线程,可以使用 spring.task.scheduling
命名空间对这些设置进行微调.
如果需要创建自定义 Actuator 或调度器,则在上下文中可以使用 TaskExecutorBuilder
bean 和 TaskSchedulerBuilder
bean.
Spring Boot 为 Spring Integration 提供了一些便捷的使用方式,它们包含在 spring-boot-starter-integration
starter 中. Spring Integration 为消息传递以及其他传输 (如 HTTP、TCP 等) 提供了抽象.
如果 classpath 上存在 Spring Integration,则 Spring Boot 会通过 @EnableIntegration
注解对其进行初始化.
Spring Boot 还配置了一些由其他 Spring Integration 模块触发的功能. 如果 spring-integration-jmx
也在 classpath 上,则消息处理统计信息将通过 JMX 发布. 如果 spring-integration-jdbc
可用,则可以在启动时创建默认数据库模式,如下所示:
spring.integration.jdbc.initialize-schema=always
有关更多详细信息,请参阅 IntegrationAutoConfiguration
和 IntegrationProperties
类.
默认情况下,如果存在 Micrometer meterRegistry
bean,则 Micrometer 将管理 Spring Integration 的指标. 如果您希望使用旧版 Spring Integration 指标,请将 DefaultMetricsFactory
bean 添加到应用程序上下文中.
Java Management Extensions (JMX,Java 管理扩展) 提供了一种监视和管理应用程序的标准机制. 默认情况下,Spring Boot 会创建一个 ID 为 mbeanServer
的 MBeanServer
bean,并暴露使用 Spring JMX 注解 (@ManagedResource
、@ManagedAttribute
或 @ManagedOperation
) 的 bean.
有关更多详细信息,请参阅 JmxAutoConfiguration
类.
Spring Boot提供了许多工具类和注解,可以在测试应用程序时提供帮助. 主要由两个模块提供: spring-boot-test
包含核心项,spring-boot-test-autoconfigure
支持测试的自动配置.
大多数开发人员都使用 spring-boot-starter-test
“Starter”,它会导入Spring Boot 测试模块以及 JUnit Jupiter,AssertJ,Hamcrest和许多其他有用的库.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
25.2. 测试 Spring 应用程序
依赖注入的主要优点之一是,它应该使您的代码更易于进行单元测试. 您可以使用 new
运算符实例化对象,甚至无需使用 Spring. 您还可以使用模拟对象而不是实际的依赖.
通常,您需要超越单元测试并开始集成测试 (使用Spring ApplicationContext
) . 能够进行集成测试而无需部署应用程序或连接到其他基础结构是很有用的.
Spring框架包括用于此类集成测试的专用测试模块. 您可以直接向 org.springframework: spring-test
声明依赖,也可以使用 spring-boot-starter-test
“Starter” 将其传递.
如果您以前没有使用过 spring-test
模块,则应先阅读 Spring Framework参考文档的相关部分 .
25.3. 测试 Spring Boot 应用程序
Spring Boot应用程序是Spring ApplicationContext
,因此除了对普通Spring上下文进行常规测试以外,无需执行任何其他特殊操作即可对其进行测试.
Spring Boot提供了 @SpringBootTest
注解,当您需要Spring Boot功能时,可以将其用作标准 spring-test
@ContextConfiguration
注解的替代方法. 注解通过创建 SpringApplication
在测试中使用的 ApplicationContext
来起作用.
除了 @SpringBootTest
之外,还提供了许多其他注解来测试应用程序的特定的部分.
MOCK
(默认) : 加载Web ApplicationContext 并提供模拟Web环境. 使用此注解时,不会启动嵌入式服务器.
如果您的类路径上没有Web环境,则此模式将透明地退回到创建常规的非Web ApplicationContext
. 它可以与 @AutoConfigureMockMvc
或 @AutoConfigureWebTestClient
结合使用,以对Web应用程序进行基于模拟的测试.
RANDOM_PORT
: 加载 WebServerApplicationContext
并提供真实的Web环境. 在随机的端口启动并监听嵌入式服务器.
DEFINED_PORT
: 加载 WebServerApplicationContext
并提供真实的Web环境. 在定义的端口(来自 application.properties
) 或 8080
端口启动并监听嵌入式服务器
NONE
: 使用 SpringApplication
加载 ApplicationContext
,但不提供任何Web环境 (模拟或其他方式) .
25.3.1. 检测 Web 应用程序类型
如果Spring MVC可用,则配置基于常规MVC的应用程序上下文. 如果您只有Spring WebFlux,我们将检测到该情况并配置基于WebFlux的应用程序上下文.
如果两者都存在,则Spring MVC优先. 如果要在这种情况下测试反应式Web应用程序,则必须设置 spring.main.web-application-type
属性:
@SpringBootTest(properties = "spring.main.web-application-type=reactive")
class MyWebFluxTests { ... }
25.3.2. 检测测试配置
如果您熟悉Spring Test Framework,则可能习惯于使用 @ContextConfiguration(classes=…)
以指定要加载哪个Spring @Configuration
. 另外,您可能经常在测试中使用嵌套的 @Configuration
类.
在测试Spring Boot应用程序时,通常不需要这样做. 只要您没有明确定义,Spring Boot的 @*Test
注解就会自动搜索您的主要配置.
搜索算法从包含测试的程序包开始工作,直到找到带有 @SpringBootApplication
或 @SpringBootConfiguration
注解的类. 只要您以合理的方式对代码进行结构化 ,通常就可以找到您的主要配置.
25.3.3. 排除测试配置
如果您的应用程序使用组件扫描 (例如,如果使用 @SpringBootApplication
或 @ComponentScan
) ,则可能会发现偶然为各地创建的仅为特定测试创建的顶级配置类.
如前所述,@TestConfiguration
可以用于测试的内部类以自定义主要配置. 当放置在顶级类上时, @TestConfiguration
指示不应通过扫描选择 src/test/java
中的类. 然后,可以在需要的位置显式导入该类,如以下示例所示:
@SpringBootTest
@Import(MyTestsConfiguration.class)
class MyTests {
@Test
void exampleTest() {
@Test
void applicationArgumentsPopulated(@Autowired ApplicationArguments args) {
assertThat(args.getOptionNames()).containsOnly("app.test");
assertThat(args.getOptionValues("app.test")).containsOnly("one");
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest
@AutoConfigureMockMvc
class MockMvcExampleTests {
@Test
void exampleTest(@Autowired MockMvc mvc) throws Exception {
mvc.perform(get("/")).andExpect(status().isOk()).andExpect(content().string("Hello World"));
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.reactive.server.WebTestClient;
@SpringBootTest
@AutoConfigureWebTestClient
class MockWebTestClientExampleTests {
@Test
void exampleTest(@Autowired WebTestClient webClient) {
webClient.get().uri("/").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo("Hello World");
在模拟环境中进行测试通常比在完整的Servlet容器中运行更快. 但是,由于模拟发生在Spring MVC层,因此无法使用MockMvc直接测试依赖于较低级别Servlet容器行为的代码.
例如,Spring Boot的错误处理基于Servlet容器提供的 “error page” 支持. 这意味着,尽管您可以按预期测试MVC层引发并处理异常,但是您无法直接测试是否呈现了特定的自定义错误页面. 如果需要测试这些较低级别的问题,则可以按照下一节中的描述启动一个完全运行的服务器.
25.3.6. 使用正在运行的服务器进行测试
如果需要启动完全运行的服务器,建议您使用随机端口. 如果使用 @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
,则每次运行测试时都会随机选择一个可用端口.
@LocalServerPort
注解可用于将 将实际使用的端口注入 测试中. 为了方便起见,需要对已启动的服务器进行REST调用的测试可以 @Autowire
附加地使用 WebTestClient
,
该 WebTestClient
解析到正在运行的服务器的相对链接,并带有用于验证响应的专用API,如以下示例所示:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.web.reactive.server.WebTestClient;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class RandomPortWebTestClientExampleTests {
@Test
void exampleTest(@Autowired WebTestClient webClient) {
webClient.get().uri("/").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo("Hello World");
这种设置需要在类路径上使用 spring-webflux
. 如果您无法或不会添加webflux,则Spring Boot还提供了 TestRestTemplate
工具:
If you can’t or won’t add webflux, Spring Boot also provides a TestRestTemplate
facility:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class RandomPortTestRestTemplateExampleTests {
@Test
void exampleTest(@Autowired TestRestTemplate restTemplate) {
String body = restTemplate.getForObject("/", String.class);
assertThat(body).isEqualTo("Hello World");
@ExtendWith(SpringExtension.class)
@SpringBootTest(properties = "spring.jmx.enabled=true")
@DirtiesContext
class SampleJmxTests {
@Autowired
private MBeanServer mBeanServer;
@Test
void exampleTest() {
// ...
25.3.9. 模拟和检测 Bean
运行测试时,有时有必要在应用程序上下文中模拟某些组件. 例如,您可能在开发过程中无法使用某些远程服务的外观. 当您要模拟在实际环境中可能难以触发的故障时,模拟也很有用.
Spring Boot包含一个 @MockBean
注解,可用于为 ApplicationContext
中的bean定义 Mockito
模拟. 您可以使用注解添加新bean或替换单个现有bean定义. 注解可以直接用于测试类,测试中的字段或 @Configuration
类和字段.
在字段上使用时,还将注入创建的模拟的实例. 每种测试方法后,模拟 Bean 都会自动重置.
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.*;
import org.springframework.boot.test.context.*;
import org.springframework.boot.test.mock.mockito.*;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.BDDMockito.*;
@SpringBootTest
class MyTests {
@MockBean
private RemoteService remoteService;
@Autowired
private Reverser reverser;
@Test
void exampleTest() {
// RemoteService has been injected into the reverser bean
given(this.remoteService.someCall()).willReturn("mock");
String reverse = reverser.reverseSomeCall();
assertThat(reverse).isEqualTo("kcom");
25.3.10. 自动配置测试
Spring Boot的自动配置系统适用于应用程序,但有时对测试来说可能有点过多. 它通常仅有助于加载测试应用程序 "切片" 所需的配置部分. 例如,您可能想要测试Spring MVC控制器是否正确映射了URL,并且您不想在这些测试中涉及数据库调用,或者您想要测试JPA实体,并且对那些JPA实体不感兴趣. 测试运行.
spring-boot-test-autoconfigure
模块包括许多注解,可用于自动配置此类 "切片". 它们中的每一个都以相似的方式工作,提供了一个 @…Test
注解 (该注解加载了 ApplicationContext
) 以及一个或多个 @AutoConfigure…
(可用于自定义自动配置设置的注解) .
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.*;
import org.springframework.boot.test.autoconfigure.json.*;
import org.springframework.boot.test.context.*;
import org.springframework.boot.test.json.*;
import static org.assertj.core.api.Assertions.*;
@JsonTest
class MyJsonTests {
@Autowired
private JacksonTester<VehicleDetails> json;
@Test
void testSerialize() throws Exception {
VehicleDetails details = new VehicleDetails("Honda", "Civic");
// Assert against a `.json` file in the same package as the test
assertThat(this.json.write(details)).isEqualToJson("expected.json");
// Or use JSON path based assertions
assertThat(this.json.write(details)).hasJsonPathStringValue("@.make");
assertThat(this.json.write(details)).extractingJsonPathStringValue("@.make")
.isEqualTo("Honda");
@Test
void testDeserialize() throws Exception {
String content = "{\"make\":\"Ford\",\"model\":\"Focus\"}";
assertThat(this.json.parse(content))
.isEqualTo(new VehicleDetails("Ford", "Focus"));
assertThat(this.json.parseObject(content).getMake()).isEqualTo("Ford");
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.boot.test.autoconfigure.web.servlet.*;
import org.springframework.boot.test.mock.mockito.*;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.BDDMockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@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"));
import com.gargoylesoftware.htmlunit.*;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.boot.test.autoconfigure.web.servlet.*;
import org.springframework.boot.test.mock.mockito.*;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.BDDMockito.*;
@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");
25.3.13. 自动配置的 Spring WebFlux 测试
要测试 Spring WebFlux 控制器是否按预期工作,可以使用 @WebFluxTest
注解. @WebFluxTest
自动配置Spring WebFlux基础结构,
并将扫描的bean限制为 @Controller
, @ControllerAdvice
, @JsonComponent
, Converter
, GenericConverter
, WebFilter
和 WebFluxConfigurer
. 使用 @WebFluxTest
注解时,不扫描常规 @Component
bean.
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;
@WebFluxTest(UserVehicleController.class)
class MyControllerTests {
@Autowired
private WebTestClient webClient;
@MockBean
private UserVehicleService userVehicleService;
@Test
void testExample() throws Exception {
given(this.userVehicleService.getVehicleDetails("sboot"))
.willReturn(new VehicleDetails("Honda", "Civic"));
this.webClient.get().uri("/sboot/vehicle").accept(MediaType.TEXT_PLAIN)
.exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("Honda Civic");
@WebFluxTest
无法检测通过 SecurityWebFilterChain
类型的 @Bean
注册的自定义安全配置. 要将其包括在测试中,您将需要通过 @Import
导入或使用 @SpringBootTest
导入用于注册bean的配置.
To include that in your test, you will need to import the configuration that registers the bean via @Import
or use @SpringBootTest
.
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@DataJpaTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class ExampleNonTransactionalTests {
数据JPA测试也可以注入 TestEntityManager
bean,它为专门为测试设计的标准JPA EntityManager
提供了替代方法. 如果要在 @DataJpaTest
实例之外使用 TestEntityManager
,也可以使用 @AutoConfigureTestEntityManager
注解.
如果需要,还可以使用 JdbcTemplate
. 以下示例显示了正在使用的 @DataJpaTest
注解:
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.autoconfigure.orm.jpa.*;
import static org.assertj.core.api.Assertions.*;
@DataJpaTest
class ExampleRepositoryTests {
@Autowired
private TestEntityManager entityManager;
@Autowired
private UserRepository repository;
@Test
void testExample() throws Exception {
this.entityManager.persist(new User("sboot", "1234"));
User user = this.repository.findByUsername("sboot");
assertThat(user.getUsername()).isEqualTo("sboot");
assertThat(user.getVin()).isEqualTo("1234");
内存嵌入式数据库通常运行良好,不需要任何安装,因此通常可以很好地进行测试. 但是,如果您希望对真实数据库运行测试,则可以使用 @AutoConfigureTestDatabase
注解,如以下示例所示:
@DataJpaTest
@AutoConfigureTestDatabase(replace=Replace.NONE)
class ExampleRepositoryTests {
// ...
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@JdbcTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class ExampleNonTransactionalTests {
如果您希望测试针对真实数据库运行,则可以使用 @AutoConfigureTestDatabase
注解,其方式与DataJpaTest相同. (请参阅自动配置的 Data JPA 测试. )
25.3.16. 自动配置的 Data JDBC 测试
@DataJdbcTest
与 @JdbcTest
相似,但适用于使用Spring Data JDBC存储库的测试. 默认情况下,它配置一个内存嵌入式数据库,一个 JdbcTemplate
和Spring Data JDBC存储库. 常规 @Component
bean未加载到 ApplicationContext
中.
默认情况下,Data JDBC测试是事务性的,并在每个测试结束时回滚. 有关更多详细信息,请参见《 Spring Framework参考文档》中的 相关部分. 如果这不是您想要的,则可以禁用测试或整个测试类的事务管理,如JDBC示例所示.
如果您希望测试针对真实数据库运行,则可以使用 @AutoConfigureTestDatabase
注解,其方式与 DataJpaTest
相同. (请参阅自动配置的 Data JPA测试. )
25.3.17. 自动配置的 jOOQ Tests
您可以以与 @JdbcTest
类似的方式使用 @JooqTest
,但可以用于与jOOQ相关的测试. 由于jOOQ严重依赖与数据库模式相对应的基于Java的模式,因此将使用现有的 DataSource
.
如果要将其替换为内存数据库,则可以使用 @AutoConfigureTestDatabase
覆盖这些设置. (有关在Spring Boot中使用jOOQ的更多信息,请参阅本章前面的 "使用 jOOQ". ) 常规 @Component
Bean未加载到 ApplicationContext
中.
import org.jooq.DSLContext;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.autoconfigure.jooq.JooqTest;
@JooqTest
class ExampleJooqTests {
@Autowired
private DSLContext dslContext;
JOOQ测试是事务性的,默认情况下会在每个测试结束时回滚. 如果这不是您想要的,则可以禁用测试或整个测试类的事务管理,如JDBC示例所示.
25.3.18. 自动配置的 Data MongoDB 测试
您可以使用 @DataMongoTest
测试MongoDB应用程序. 默认情况下,它配置内存嵌入式MongoDB (如果可用) ,配置 MongoTemplate
,扫描 @Document
类,并配置Spring Data MongoDB存储库. 常规 @Component
bean未加载到 ApplicationContext
中.
(有关将MongoDB与Spring Boot结合使用的更多信息,请参阅本章前面的 "MongoDB")
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import org.springframework.data.mongodb.core.MongoTemplate;
@DataMongoTest
class ExampleDataMongoTests {
@Autowired
private MongoTemplate mongoTemplate;
内存嵌入式MongoDB通常运行良好,并且不需要任何开发人员安装,因此通常可以很好地用于测试. 但是,如果您希望对真实的MongoDB服务器运行测试,则应排除嵌入式MongoDB自动配置,如以下示例所示:
import org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
@DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class)
class ExampleDataMongoNonEmbeddedTests {
25.3.19. 自动配置的 Data Neo4j 测试
您可以使用 @DataNeo4jTest
来测试Neo4j应用程序. 默认情况下,它使用内存中嵌入式Neo4j (如果有嵌入式驱动程序可用) ,扫描 @NodeEntity
类,并配置Spring Data Neo4j存储库.
常规 @Component
bean未加载到 ApplicationContext
中. (有关将Neo4J与Spring Boot结合使用的更多信息,请参阅本章前面的 "Neo4j". )
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest;
@DataNeo4jTest
class ExampleDataNeo4jTests {
@Autowired
private YourRepository repository;
默认情况下,Data Neo4j测试是事务性的,并在每次测试结束时回滚. 有关更多详细信息,请参见《 Spring Framework参考文档》中的http://docs.jcohy.com/zh-cn/spring-framework/5.2.4.RELEASE/spring-framework-reference/index.htmltesting.html#testcontext-tx-enabling-transactions[相关部分] . 如果这不是您想要的,则可以为测试或整个类禁用事务管理,如下所示:
import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@DataNeo4jTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class ExampleNonTransactionalTests {
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest;
@DataRedisTest
class ExampleDataRedisTests {
@Autowired
private YourRepository repository;
25.3.21. 自动配置的 Data LDAP 测试
您可以使用 @DataLdapTest
来测试LDAP应用程序. 默认情况下,它配置内存嵌入式LDAP (如果可用) ,配置 LdapTemplate
,扫描 @Entry
类,并配置Spring Data LDAP存储库.
常规 @Component
bean未加载到 ApplicationContext
中. (有关将LDAP与Spring Boot结合使用的更多信息,请参阅本章前面的 "LDAP". )
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest;
import org.springframework.ldap.core.LdapTemplate;
@DataLdapTest
class ExampleDataLdapTests {
@Autowired
private LdapTemplate ldapTemplate;
内存嵌入式LDAP通常非常适合测试,因为它速度快并且不需要安装任何开发人员. 但是,如果您希望针对真实的LDAP服务器运行测试,则应排除嵌入式LDAP自动配置,如以下示例所示:
import org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration;
import org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest;
@DataLdapTest(excludeAutoConfiguration = EmbeddedLdapAutoConfiguration.class)
class ExampleDataLdapNonEmbeddedTests {
void getVehicleDetailsWhenResultIsSuccessShouldReturnDetails()
throws Exception {
this.server.expect(requestTo("/greet/details"))
.andRespond(withSuccess("hello", MediaType.TEXT_PLAIN));
String greeting = this.service.callRestService();
assertThat(greeting).isEqualTo("hello");
25.3.23. 自动配置的 Spring REST Docs 测试
您可以使用 @AutoConfigureRestDocs
注解在Mock MVC,REST Assured或 WebTestClient
的测试中使用 Spring REST Docs. 它消除了Spring REST Docs中对JUnit扩展的需求.
@AutoConfigureRestDocs
可用于覆盖默认输出目录 (如果使用Maven,则为 target/generated-snippets
如果使用Gradle,则为 build/generated-snippets
) . 它也可以用于配置出现在任何记录的URI中的主机,方案和端口.
使用 Mock MVC 自动配置的Spring REST Docs测试
@AutoConfigureRestDocs
自定义 MockMvc
bean以使用Spring REST Docs. 您可以使用 @Autowired
注入它,并像通常使用Mock MVC和Spring REST Docs一样,在测试中使用它,如以下示例所示:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@WebMvcTest(UserController.class)
@AutoConfigureRestDocs
class UserDocumentationTests {
@Autowired
private MockMvc mvc;
@Test
void listUsers() throws Exception {
this.mvc.perform(get("/users").accept(MediaType.TEXT_PLAIN))
.andExpect(status().isOk())
.andDo(document("list-users"));
如果需要对Spring REST Docs配置进行更多控制,而不是 @AutoConfigureRestDocs
属性提供的控制,则可以使用 RestDocsMockMvcConfigurationCustomizer
bean,如以下示例所示:
@TestConfiguration
static class CustomizationConfiguration
implements RestDocsMockMvcConfigurationCustomizer {
@Override
public void customize(MockMvcRestDocumentationConfigurer configurer) {
configurer.snippets().withTemplateFormat(TemplateFormats.markdown());
如果要使用Spring REST Docs对参数化输出目录的支持,可以创建 RestDocumentationResultHandler
bean. 自动配置使用此结果处理程序调用 alwaysDo
,从而使每个 MockMvc
调用自动生成默认片段. 以下示例显示了定义的 RestDocumentationResultHandler
:
@TestConfiguration(proxyBeanMethods = false)
static class ResultHandlerConfiguration {
@Bean
public RestDocumentationResultHandler restDocumentation() {
return MockMvcRestDocumentation.document("{method-name}");
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;
@WebFluxTest
@AutoConfigureRestDocs
class UsersDocumentationTests {
@Autowired
private WebTestClient webTestClient;
@Test
void listUsers() {
this.webTestClient.get().uri("/").exchange().expectStatus().isOk().expectBody()
.consumeWith(document("list-users"));
如果需要对Spring REST Docs配置进行更多控制,而不是 @AutoConfigureRestDocs
属性提供的控制,则可以使用 RestDocsWebTestClientConfigurationCustomizer
bean,如以下示例所示:
@TestConfiguration(proxyBeanMethods = false)
public static class CustomizationConfiguration implements RestDocsWebTestClientConfigurationCustomizer {
@Override
public void customize(WebTestClientRestDocumentationConfigurer configurer) {
configurer.snippets().withEncoding("UTF-8");
import io.restassured.specification.RequestSpecification;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.web.server.LocalServerPort;
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.is;
import static org.springframework.restdocs.restassured3.RestAssuredRestDocumentation.document;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureRestDocs
class UserDocumentationTests {
@Test
void listUsers(@Autowired RequestSpecification documentationSpec, @LocalServerPort int port) {
given(documentationSpec).filter(document("list-users")).when().port(port).get("/").then().assertThat()
.statusCode(is(200));
如果您需要对Spring REST Docs配置进行更多控制,而不是 @AutoConfigureRestDocs
属性所提供的控制,则可以使用 RestDocsRestAssuredConfigurationCustomizer
bean,如以下示例所示:
@TestConfiguration(proxyBeanMethods = false)
public static class CustomizationConfiguration implements RestDocsRestAssuredConfigurationCustomizer {
@Override
public void customize(RestAssuredRestDocumentationConfigurer configurer) {
configurer.snippets().withTemplateFormat(TemplateFormats.markdown());
@JdbcTest
@ImportAutoConfiguration(IntegrationAutoConfiguration.class)
class ExampleJdbcTests {
25.3.26. 使用Spock测试Spring Boot应用程序
如果您希望使用Spock来测试Spring Boot应用程序,则应在应用程序的构建中添加对Spock的 spock-spring
模块的依赖. spock-spring
将Spring的测试框架集成到了Spock中.
建议您使用Spock 1.2或更高版本,以受益于Spock的Spring Framework和Spring Boot集成的许多改进. 有关更多详细信息,请参见 Spock的Spring模块的文档.
void testName(CapturedOutput output) {
System.out.println("Hello World!");
assertThat(output).contains("World");
@Test
public void testRequest() throws Exception {
HttpHeaders headers = this.template.getForEntity(
"https://myhost.example.com/example", String.class).getHeaders();
assertThat(headers.getLocation()).hasHost("other.example.com");
或者,如果将 @SpringBootTest
注解与 WebEnvironment.RANDOM_PORT
或 WebEnvironment.DEFINED_PORT
一起使用,则可以注入完全配置的 TestRestTemplate
并开始使用它.
如有必要,可以通过 RestTemplateBuilder
bean应用其他定制. 未指定主机和端口的所有URL都会自动连接到嵌入式服务器,如以下示例所示:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class SampleWebClientTests {
@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 Config {
@Bean
RestTemplateBuilder restTemplateBuilder() {
return new RestTemplateBuilder().setConnectTimeout(Duration.ofSeconds(1))
.setReadTimeout(Duration.ofSeconds(1));
Spring Boot 为内嵌式 Tomcat、Jetty 和 Undertow 提供了 WebSocket 自动配置. 如果将 war 文件部署到独立容器,则 Spring Boot 假定容器负责配置其 WebSocket 支持.
Spring Framework 为 MVC Web 应用程序提供了 丰富的 WebSocket 支持 ,可以通过 spring-boot-starter-websocket
模块轻松访问.
WebSocket 支持也可用于 响应式 Web 应用程序 ,并且引入 WebSocket API 以及 spring-boot-starter-webflux
:
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
</dependency>
27.1. 使用 WebServiceTemplate
调用 Web Service
如果您需要从应用程序调用远程 Web 服务,则可以使用 WebServiceTemplate
类. 由于 WebServiceTemplate
实例在使用之前通常需要进行自定义,因此 Spring Boot 不提供任何自动配置的 WebServiceTemplate
bean.
但是,它会自动配置 WebServiceTemplateBuilder
,可在需要创建 WebServiceTemplate
实例时使用.
以下代码为一个典型示例:
@Service
public class MyService {
private final WebServiceTemplate webServiceTemplate;
public MyService(WebServiceTemplateBuilder webServiceTemplateBuilder) {
this.webServiceTemplate = webServiceTemplateBuilder.build();
public DetailsResp someWsCall(DetailsReq detailsReq) {
return (DetailsResp) this.webServiceTemplate.marshalSendAndReceive(detailsReq, new SoapActionCallback(ACTION));
默认情况下,WebServiceTemplateBuilder
使用 classpath 上的可用 HTTP 客户端库检测合适的基于 HTTP 的 WebServiceMessageSender
. 您还可以按如下方式自定义读取和连接的超时时间:
@Bean
public WebServiceTemplate webServiceTemplate(WebServiceTemplateBuilder builder) {
return builder.messageSenders(new HttpWebServiceMessageSenderBuilder()
.setConnectTimeout(5000).setReadTimeout(2000).build()).build();
如果您在公司负责开发公共类库,或者如果您在开发一个开源或商业库,您可能希望开发自己的自动配置. 自动配置类可以捆绑在外部 jar 中,他仍然可以被 Spring Boot 获取.
自动配置可以与提供自动配置代码的 starter 以及您将使用的类库库相关联. 我们首先介绍构建自己的自动配置需要了解的内容,然后我们将继续介绍创建 自定义 starter 所需的步骤.
28.1. 理解 自动配置的 Beans
在内部,自动配置使用了标准的 @Configuration
类来实现. @Conditional
注解用于约束何时应用自动配置. 通常,自动配置类使用 @ConditionalOnClass
和 @ConditionalOnMissingBean
注解.
这可确保仅在找到相关类时以及未声明您自己的 @Configuration
时才应用自动配置.
您可以浏览 spring-boot-autoconfigure
的源代码,以查看 Spring 提供的 @Configuration
类 (请参阅 META-INF/spring.factories
文件) .
28.2. 找到候选的自动配置
Spring Boot 会检查已发布 jar 中是否存在 META-INF/spring.factories
文件. 该文件应列出 EnableAutoConfiguration
key 下的配置类,如下所示:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.mycorp.libx.autoconfigure.LibXAutoConfiguration,\
com.mycorp.libx.autoconfigure.LibXWebAutoConfiguration
如果需要按特定顺序应用配置,则可以使用 @AutoConfigureAfter
或 @AutoConfigureBefore
注解. 例如,如果您提供特定于 Web 的配置,则可能需要在 WebMvcAutoConfiguration
之后应用您的类.
如果您想排序某些不应该彼此直接了解的自动配置,您也可以使用 @AutoConfigureOrder
. 该注解与常规 @Order
注解有相同的语义,但它为自动配置类提供了专用顺序.
28.3. 条件注解
您几乎总希望在自动配置类中包含一个或多个 @Conditional
注解. @ConditionalOnMissingBean
是一个常用的注解,其允许开发人员在对您的默认值不满意用于覆盖自动配置.
Spring Boot 包含许多 @Conditional
注解,您可以通过注解 @Configuration
类或单独的 @Bean 方法在您自己的代码中复用它们. 这些注解包括:
28.3.1. 类条件
@ConditionalOnClass
和 @ConditionalOnMissingClass
注解允许根据特定类的是否存在来包含 @Configuration
类. 由于使用 ASM 解析注解元数据,您可以使用 value
属性来引用真实类,即使该类实际上可能不会出现在正在运行的应用程序的 classpath
中.
如果您希望使用 String 值来指定类名,也可以使用 name
属性.
此机制不会以相同的方式应用于返回类型是条件的目标的 @Bean
方法: 在方法上的条件应用之前,JVM 将加载类和可能处理的方法引用,如果找不到类,将发生失败.
要处理这种情况,可以使用单独的 @Configuration
类来隔离条件,如下所示:
@Configuration(proxyBeanMethods = false)
// Some conditions
public class MyAutoConfiguration {
// Auto-configured beans
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(EmbeddedAcmeService.class)
static class EmbeddedConfiguration {
@Bean
@ConditionalOnMissingBean
public EmbeddedAcmeService embeddedAcmeService() { ... }
28.3.2. Bean 条件
@ConditionalOnBean
和 @ConditionalOnMissingBean
注解允许根据特定 bean 是否存在来包含 bean. 您可以使用 value
属性按类型或使用 name
来指定 bean. search
属性允许您限制在搜索 bean 时应考虑的 ApplicationContext
层次结构.
放置在 @Bean
方法上时,目标类型默认为方法的返回类型,如下所示:
@Configuration(proxyBeanMethods = false)
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyService myService() { ... }
在前面的示例中,如果 ApplicationContext
中不包含 MyService
类型的 bean,则将创建 myService
bean.
28.4. 测试自动配置
自动配置可能受许多因素的影响: 用户配置 (@Bean
定义和 Environment
自定义) 、条件评估 (存在特定的类库) 等. 具体而言,每个测试都应该创建一个定义良好的 ApplicationContext
,它表示这些自定义的组合. ApplicationContextRunner
提供了一个好的实现方法.
ApplicationContextRunner
通常被定义为测试类的一个字段,用于收集基本的通用配置. 以下示例确保始终调用 UserServiceAutoConfiguration
:
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(UserServiceAutoConfiguration.class));
@Test
void defaultServiceBacksOff() {
this.contextRunner.withUserConfiguration(UserConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(UserService.class);
assertThat(context).getBean("myUserService").isSameAs(context.getBean(UserService.class));
@Configuration(proxyBeanMethods = false)
static class UserConfiguration {
@Bean
UserService myUserService() {
return new UserService("mine");
也可以轻松自定义 Environment
,如下所示:
@Test
void serviceNameCanBeConfigured() {
this.contextRunner.withPropertyValues("user.name=test123").run((context) -> {
assertThat(context).hasSingleBean(UserService.class);
assertThat(context.getBean(UserService.class).getName()).isEqualTo("test123");
runner 还可用于展示 ConditionEvaluationReport
. 报告可以在 INFO
或 DEBUG
级别下打印. 以下示例展示如何使用 ConditionEvaluationReportLoggingListener
在自动配置测试中打印报表.
@Test
public void autoConfigTest {
ConditionEvaluationReportLoggingListener initializer = new ConditionEvaluationReportLoggingListener(
LogLevel.INFO);
ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withInitializer(initializer).run((context) -> {
// Do something...
28.4.1. 模拟一个 Web 上下文
如果需要测试一个仅在 Servlet 或响应式 Web 应用程序上下文中运行的自动配置,请分别使用 WebApplicationContextRunner
或 ReactiveWebApplicationContextRunner
.
28.4.2. 覆盖 Classpath
还可以测试在运行时不存在特定类和/或包时发生的情况. Spring Boot附带了一个可以由跑步者轻松使用的 FilteredClassLoader
. 在以下示例中,我们声明如果 UserService
不存在,则会正确禁用自动配置:
@Test
void serviceIsIgnoredIfLibraryIsNotPresent() {
this.contextRunner.withClassLoader(new FilteredClassLoader(UserService.class))
.run((context) -> assertThat(context).doesNotHaveBean("userService"));
28.5.1. 命名
您应该确保为您的 starter 提供一个合适的命名空间. 即使您使用其他 Maven groupId,也不要使用 spring-boot
作为模块名称的开头. 我们可能会为您以后自动配置的内容提供官方支持.
根据经验,您应该在 starter 后命名一个组合模块. 例如,假设您正在为 acme 创建一个 starter,并且您将自动配置模块命名为 acme-spring-boot-autoconfigure
,将 starter 命名为 acme-spring-boot-starter
. 如果您只有一个组合这两者的模块,请将其命名为 acme-spring-boot-starter
.
28.5.2. 配置 keys
此外,如果您的 starter 提供配置 key,请为它们使用唯一的命名空间. 尤其是,不要将您的 key 包含在 Spring Boot 使用的命名空间中 (例如 server
、management
、spring
等) . 如果您使用了相同的命名空间,我们将来可能会以破坏您的模块的方式来修改这些命名空间. 根据经验,所有 key 都必须拥有自己的命名空间 (例如 acme
) .
确保触发元数据生成,以便为您的 key 提供 IDE 帮助. 您可能想查看生成的元数据 (META-INF/spring-configuration-metadata.json
) 以确保您的 key 记录是否正确.
通过为每个属性添加字段javadoc来确保记录了配置 keys,如以下示例所示:
@ConfigurationProperties("acme")
public class AcmeProperties {
* Whether to check the location of acme resources.
private boolean checkLocation = true;
* Timeout for establishing a connection to the acme server.
private Duration loginTimeout = Duration.ofSeconds(3);
// getters & setters
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure-processor</artifactId>
<optional>true</optional>
</dependency>
使用 Gradle 4.5 及更早版本时,应在 compileOnly
配置中声明依赖,如下所示:
dependencies {
compileOnly "org.springframework.boot:spring-boot-autoconfigure-processor"
With Gradle 4.6 and later, the dependency should be declared in the annotationProcessor
configuration, as shown in the following example:
dependencies {
annotationProcessor "org.springframework.boot:spring-boot-autoconfigure-processor"
Spring Boot 通过利用其他 Spring 项目 (如 Spring Framework、Spring Data 和 Reactor) 的支持来提供 Kotlin 支持. 有关更多信息,请参阅 Spring Framework Kotlin 支持文档 .
开始学习 Spring Boot 和 Kotlin 最简单方法是遵循这个 全面教程. 您可以通过 start.spring.io 创建新的 Kotlin 项目. 如果您需要支持,请免费加入 Kotlin Slack 的 #spring 频道或使用 Stack Overflow 上的 spring
和 kotlin
标签提问.
29.1. 要求
Spring Boot 支持 Kotlin 1.3.x. 要使用 Kotlin,classpath 下必须存在 org.jetbrains.kotlin:kotlin-stdlib
和 org.jetbrains.kotlin:kotlin-reflect
. 也可以使用 kotlin-stdlib
的变体 kotlin-stdlib-jdk7
和 kotlin-stdlib-jdk8
.
由于 Kotlin 类默认为 final,因此您可能需要配置 kotlin-spring 插件以自动打开 Spring-annotated
类,以便可以代理它们.
在 Kotlin 中序列化/反序列化 JSON 数据需要使用 Jackson 的 Kotlin 模块. 在 classpath 中找到它时会自动注册. 如果 Jackson 和 Kotlin 存在但 Jackson Kotlin 模块不存在,则会记录警告消息.
29.2. Null 安全
Kotlin 的一个关键特性是 null-safety. 它在编译时处理空值,而不是将问题推迟到运行时并遇到 NullPointerException
. 这有助于消除常见的错误来源,而无需支付像 Optional
这样的包装器的成本. Kotlin 还允许使用有可空值的,如 Kotlin null
安全综合指南中所述.
虽然 Java 不允许在其类型系统中表示 null
安全,但 Spring Framework、Spring Data 和 Reactor 现在通过易于使用的工具的注解提供其 API 的安全性. 默认情况下,Kotlin 中使用的 Java API 类型被识别为放宽空检查的 平台类型. Kotlin 对 JSR 305 注解 的支持与可空注解相结合,为 Kotlin 中 Spring API 相关的代码提供了空安全.
可以通过使用以下选项添加 -Xjsr305
编译器标志来配置 JSR 305 检查: -Xjsr305={strict|warn|ignore}
. 默认行为与 -Xjsr305=warn
相同. 在从 Spring API 推断出的 Kotlin 类型中需要考虑 null 安全的 strict
值,但是应该使用 Spring API 可空声明甚至可以在次要版本之间发展并且将来可能添加更多检查的方案.
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class MyApplication
fun main(args: Array<String>) {
runApplication<MyApplication>(*args)
这是 SpringApplication.run(MyApplication::class.java, *args)
的替代方式. 它还允许自定义应用程序,如下所示:
runApplication<MyApplication>(*args) {
setBannerMode(OFF)
29.3.2. 扩展
Kotlin 扩展 提供了使用附加功能扩展现有类的能力. Spring Boot Kotlin API 利用这些扩展为现有 API 添加新的 Kotlin 特定便利.
提供的 TestRestTemplate
扩展类似于 Spring Framework 为 RestOperations
提供的. 除此之外,扩展使得利用 Kotlin reified 类型参数变为可能.
使用Maven,可以通过 kotlin.version
属性自定义Kotlin版本,并且为 kotlin-maven-plugin
提供了插件管理. 使用Gradle,Spring Boot插件会自动将 kotlin.version
与Kotlin插件的版本保一致.
Spring Boot还通过导入Kotlin Coroutines BOM管理Coroutines依赖的版本. 可以通过 kotlin-coroutines.version
属性自定义版本.
29.5. @ConfigurationProperties
@ConfigurationProperties 目前仅适用于 lateinit 或可空的 var 属性 (建议使用前者) ,因为尚不支持由构造函数初始化的不可变类.
与 @ConstructorBinding
结合使用时,@ConfigurationProperties
支持具有不变 val
属性的类,如以下示例所示:
@ConstructorBinding
@ConfigurationProperties("example.kotlin")
data class KotlinExampleProperties(
val name: String,
val description: String,
val myService: MyService) {
data class MyService(
val apiToken: String,
val uri: URI
29.6. 测试
虽然可以使用 JUnit 4 来测试 Kotlin 代码,但建议使用 JUnit 5. JUnit 5 允许测试类实例化一次,并在所有类的测试中复用. 这使得可以在非静态方法上使用 @BeforeAll
和 @AfterAll
注解,这非常适合 Kotlin.
JUnit 5是默认的,并且提供了vintage引擎与JUnit 4向后兼容. 如果不使用它,请排除 org.junit.vintange: junit-vintage-engine
. 您还需要将 测试实例生命周期切换为 "per-class".
要模拟Kotlin类,建议使用MockK. 如果您需要与Mockito特定的@MockBean和@SpyBean注解相对应的Mockk,则可以使用SpringMockK,它提供类似的@MockkBean和@SpykBean注解.
要使用 JUnit 5,请从 spring-boot-starter-test
中排除 junit:junit 依赖,然后添加 JUnit 5 依赖,并相应地配置 Maven 或 Gradle 插件. 有关更多详细信息,请参阅 JUnit 5 文档. 您还需要将测试实例生命周期切换为 per-class.
为了模拟 Kotlin
类,建议使用 Mockk
. 如果需要 MockK 等效的 Mockito 特定的 @MockBean
和 @SpyBean
注解,则可以使用 SpringMockK,它提供类似的 @MockkBean
和 @SpykBean
注解.
29.7. 资源
29.7.1. 进阶阅读
Kotlin Slack (有专用的 #spring 频道)
Stackoverflow 上 spring
和 kotlin
标签
教程: 使用 Spring Boot 和 Kotlin 构建 Web 应用程序
使用 Kotlin、Spring Boot 和 PostgreSQL 开发地理信使