shell本节将深入介绍 Spring Boot 的详情,在这里你能了解到你可以会使用或者自定义的关键特性。如果你还没有准备好,你也许需要去阅读 “getting-started.html” 和 “using-spring-boot.html” 章节来打下好的基础。
SpringApplication
类提供了一种便捷的方法来引导从 main()
方法启动的 Spring 应用。在很多情况下,你能够委托静态的 SpringApplication.run
方法,就像下面的例子一样:
public static void main(String[] args) {
SpringApplication.run(MySpringConfiguration.class, args);
}
当你的应用启动时,你应该会看到类似下面的输出:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: v2.2.7.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
级别的日志消息,包括一些有关启动的详细信息,比如开启应用的用户,你也可以修改日志级别,具体的可以查看 [Log Levels](./Log Levels.md)。应用版本是由具体实现的主程序的类包的版本所决定的。你可以将 spring.main.log.startup-info
设为 false
来关闭日志信息,此操作也会关闭应用中确定模式下的日志消息。
你可以重写
SpringApplication
子类的logStartupInfo(boolean)
来添加额外的启动日志。
如果你的应用启动失败,注册的 FailureAnalyzers
将会提供对应的错误信息和修复这个问题的具体操作。比如,如果你在 8080 端口启动一个 web 应用,但这个端口已经被使用了,你将会看到类似下面的信息:
***************************
APPLICATION FAILED TO START
***************************
Description:
Embedded servlet container failed to start. Port 8080 was already in use.
Action:
Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.
Spring Boot 提供了很多
FailureAnlyzer
实现,并且你可以实现你自己的。
如果没有能够解决问题的错误分析,你也可以显示报告的所有信息来更好地理解该错误。为了达到这一小锅,你需要为 org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
启动 debug 属性或启动 debug 的日志级别。
比如,如果你是用 java -jar
来运行你的应用,你能像下面这样开启 debug 属性:
$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug
SpringApplication
允许应用的初始化进行懒加载,当懒加载开启后,bean 会在它们被需要的时候创建而不是应用一开启就创建。开启懒加载能减少应用的启动时间,在 web 应用中,开启懒加载会导致很多与 web 相关的 bean 不会被初始化,直到接收了 HTTP 请求。
懒加载的一个缺点是它会导致应用中问题的发现杯延迟,如果一个没有被配置的 bean 是懒加载的,这个错误可能在启动的时候不会显示,直到该 bean 被加载才会暴露出来。还必须确保 JVM 有足够的内存使用应用所有的 bean,而不仅仅是启动时的 bean。基于以上原因,懒加载初始化默认情况下没有开启,并且推荐在开启懒加载之前对 JVM 堆大小进行调整。
可以使用编程的方法在 SpringApplicationBuilder
的 lazyInitation
方法或 SpringApplication
的 setLazyInitation
方法开启懒加载,此外,也可以如下使用 spring.main.lazy-initation
属性开启:
spring.main.lazy-initialization=true
如果你禁用应用中一些 bean 的懒加载,而对剩下的开启懒加载,可以使用
@Lazy(false)
注解显式地将它们的懒加载设置为 false。
banner 是在启动时输出的样式,可以通过在类路径下创建 banner.txt 文件或者设置 spring.banner.location
属性的文件路径来修改它,如果文件不是 UTF-8 编码的,你可以设置 spring.banner.charset
。除了文本文件,你也可以在类路径下添加 banner.gif、banner.jpg 或 banner.png 图片文件或者设置 spring.banner.image.location
属性。图片会被转换为 ASCII 形式并打印为文本 banner。
在 banner.txt
中,你能使用下面的占位符:
变量 | 描述 |
---|---|
${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.7.RELEASE 。 |
${spring-boot.formatted-version} |
你使用的 Spring Boot 版本号,格式化输出(用圆括号括起来,并加上前缀 v )。比如 (v2.2.7.RELEASE) 。 |
${Ansi.NAME} (or ${AnsiColor.NAME} , ${AnsiBackground.NAME} , ${AnsiStyle.NAME} ) |
NAME 是 ANSI 转义码的满足,具体查看 AnsiPropertySource。 |
${application.title} |
你应用中的主题,想 MANIFEST.MF 中声明的一样。比如 Implementation-Title: MyApp 输出 MyApp 。 |
如果你想编程式创建一个 banner,可以使用
SpringApplication.setBanner(...)
方法。使用org.springframework.boot.Banner
接口并实现你自己的printBanner()
方法。
你可以使用 spring.main.banner-mode
属性来确认是否将 banner 打印在 System.out
(console
)、发送到指定的日志(log
)、或者不输出(off
)。
banner 被注册为一个名字为 springBanner
的单例 bean。
如果 SpringApplication
默认的构造不符合你的要求,你可以创建一个本地实例并自定义它。比如,你可以通过这样来关闭 banner:
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MySpringConfiguration.class);
app.setBannerMode(Banner.Mode.OFF);
app.run(args);
}
传给
SpringApplication
的参数是 Spring bean 的配置源。在大多数新情况下,它们都是@Configuration
类的引用,不过它们也可以是对 XML 配置的引用或者是被扫描的包的引用。
可以使用 application.properties
文件对 SpringApplication
进行配置,详情可查看 Externalized Configuration。
查看 SpringApplication
Java 文档 获取配置的选项。
如果你想构建一个层级 ApplicationContext
(父/子 关系的多个上下文)或者你想使用链式 API 进行构建,你可以通过 SpringApplicationBuilder
实现。
SpringApplicationBuilder
可以将多个方法链式调用,并且包括 parent
和 child
方法来创建层次结构,正如下面例子所示:
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);
创建层次
ApplicationContext
存在一些限制,比如 web 组件必须被包含在子上下文中,并且父子上下文的Environment
必须一样,具体的可以查看 SpringApplicationbuilder Java 文档 获取信息。
除了常见的 Spring Framework 事件,比如 ContextRefreshedEvent
,SpringApplication
会发送一些附加的应用事件。
有些事件是在
ApplicationContext
被创建前触发的,所以你不能将监听器使用@Bean
进行注册,你可以使用SpringApplication.addLlisterners(...)
方法或SpringApplicationBuilder.listerners(...)
方法进行注册。如果你想要监听器自动注册在应用上,无论应用是否被创建。你可以在你的项目下创建一个
META-INF/spring.factories
文件并使用org.springframework.context.ApplicationListener
键引用你的监听器,如下面所示:org.springframework.context.ApplicationListener=com.example.project.MyListener
当应用运行时,应用事件按以下的顺序派送:
ApplicationStartingEvent
在运行开始时,任何处理之前派送,除了注册监听器和初始化器之外。ApplicationEnvironmentPreparedEvent
在已知 Envirment
之后,未创建上下文之前派送。ApplicationContextInitializedEvent
在 ApplicationContext
准备好,ApplicationContextInitializers 被调用,但是所有 bean 定义没有被加载的时候派送。ApplicationPreparedEvent
在 refresh 之前,bean 定义被加载之后派送。ApplicationStartedEvent
在上下文被刷新之后,调用应用程序和命令行运行之前派送。ApplicationReadyEvent
在调用任意应用程序和命令行运行程序之后派送,它表示应用程序已准备好为请求提供服务。ApplicationFailedEvent
在程序出现异常时派送。上面的列表只包括绑定到 SpringApplication
的 SpringApplicationEvents
。除此之外,还将在 ApplicationPreparedEvent
之后和 ApplicationStartedEvent
之前发布以下事件:
ContextRefreshedEvent
在 ApplicationContext
被刷新的时候派送。WebServerInitializedEvent
在 WebServer
准备好后派送。ServletWebServerInitializedEvent
和 ReactiveWebServerInitializedEvent
分别是 servlet
和 reactive
变体。你通常不需要使用应用事件,但是了解它们对于程序处理很有帮助,在内部,Spring Boot 通过事件来处理各种任务。
应用事件通过使用 Spring Framework 的事件发布机制派送。此机制的一部分确保在子上下文中发布给监听器的事件也在任何父上下文中发布给监听器。因此,如果应用程序使用SpringApplication
实例的层次结构,则监听器可能会接收同一类型应用程序事件的多个实例。
为了让监听器区分其上下文事件和子上下文事件,它应该注入其应用程序上下文,然后将注入的上下文与事件的上下文进行比较。上下文可以通过实现 ApplicationContextAware
注入,如果监听器是 bean,则可以使用 @Autowired
注入。
SpringApplication
根据你的代码尝试创建正确类型的 ApplicationContext
,用于确定 WebApplicationType
的算法很简单:
AnnotationConfigServletWebServerApplicationContext
。AnnotationConfigReactiveWebServerApplicationContext
。AnnotationConfigApplicationContext
。以上意味着如果你在同一个应用中使用了 Spring MVC 并从 Spring WebFlux 创建了 WebClient
,默认使用 Spring MVC。你可以通过调用 setWebApplicationType(WebApplicationType)
来轻松覆盖它。
也可以通过调用 setApplicationContextClass(...)
来完全控制 ApplicationContext
类型。
当在 JUnit 测试中使用
SpringApplication
时,经常需要调用setWebApplicationType(WebApplicationType.NONE)
。
如果你想访问传入 SpringApplication.run(...)
的应用参数,你可以注入 org.springframework.boot.ApplicationArguments
bean,ApplicationArguments
接口提供对访问原始字符串数组 String[]
参数以及解析的 option
和 no-option
参数,如下面所示:
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"]
}
}
Spring Boot 还向 Spring
Envirment
注册了CommandLinePropertySource
。这还允许使用@Value
注解注入单个应用程序参数。
如果你需要在 SpringApplication
启动的时候运行一些代码,你可以实现 ApplicationRunnner
或 CommandLineRunner
接口,这两个接口都以相同的方式工作,并提供一个单独的 run
方法,在 SpringApplication.run(...)
完成前调用。
CommandLineRunner
接口简单的字符串数组形式提供对应用程序参数的访问,而ApplicationRunner
使用前面讨论的 ApplicationArguments
接口。以下示例显示了带有run
方法的 CommandLineRunner
:
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
注解。
每个 SpringApplication
都向 JVM 注册一个关闭钩子函数,以确保 ApplicationContext
在退出时正常关闭。可以使用所有标准的 Spring
生命周期回调(例如 DisposableBean
接口或 @PreDestroy
注释)。
此外,如果 bean 希望在调用 SpringApplication.exit()
时返回特定的退出代码,则可以实现 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()
方法提供的退出代码。
通过指定 spring.application.admin.enable
属性的值可以开启应用汇总有关管理的功能,这将在平台 MBeanServer
上展示 SpringApplicationAdminMXBean。你可以使用这些管理特性来远程管理你的应用,这个特性对于任何服务包装器实现都很有用。
如果你想知道应用运行的端口,可以获取
local.server.port
的值来查看。
Spring Boot 允许在外部进行配置,以便在不同的环境中使用相同的应用程序代码。你可以使用 properties 文件、YAML 文件、环境变量和命令行参数来进行外部配置。属性值可以通过使用 @Value
直接注入到bean中,可以通过 Spring Environment
抽象,也可以通过@ConfigurationProperties
绑定到结构化对象。
Spring Boot 使用一个非常特殊的 PropertySource
顺序,它被设计为允许对值进行合理的重写。属性按以下顺序设置:
@TestPropertySource
注解。@SpringBootTest
和测试注解中提供,用于测试应用程序的特定部分。SPRING_APPLICATION_JSON
(内嵌在环境变量或系统属性中的 JSON)的属性。ServletConfig
初始化参数。ServletContext
初始化参数。java:comp/env
的 JNDI 属性。System.getProperties()
)。RandomValuePropertySource
,其属性仅为 random.*
。application-{Profile}.properties
和 YAML
变量)。application-{Profile}.properties
和 YAML
变量)。application.properties
和 YAML
变体)。application.properties
和 YAML
变体)。@Configuration
类上的 @PropertySource
注释。注意,在刷新应用程序上下文之前,这些属性源不会添加到环境中。此时配置某些属性(如 logging.*
和 spring.main.*
等)太迟了,这些属性在刷新开始之前就会被读取。SpringApplication.setDefaultProperties
指定)。为了提供一个具体的示例,假设你开发了一个使用 name
属性的 @Component
,如下例所示:
import org.springframework.stereotype.*;
import org.springframework.beans.factory.annotation.*;
@Component
public class MyBean {
@Value("${name}")
private String name;
// ...
}
在应用的类路径(例如,在 jar )上,可以有一个 application.properties
文件,该文件为每个 name
提供合理的默认属性值。当运行在一个新环境中,可以在 jar 外部提供 application.properties
文件覆盖原文件。对于一次性的测试,可以使用特定的命令行开关进行启动启动(例如,java-jar app.jar--name="Spring"
)。
SPRING)APPLICATION_JSON
属性的值能在带有环境参数的命令行上提供,比如,你可以在 UN*X shell 上使用以下:$ SPRING_APPLICATION_JSON='{"acme":{"name":"test"}}' java -jar myapp.jar
在前面的例子中,你最后在 Spring Environment 中使用
acme.name=test
。还可以将在系统属性中将 JSON 作为spring.application.json
提供,如下例所示:$ java -Dspring.application.json='{"name":"test"}' -jar myapp.jar
还可以使用命令行参数提供 JSON,如下例所示:
$ java -jar myapp.jar --spring.application.json='{"name":"test"}'
还可以将 JSON 作为 JNDI 变量提供,如下所示:
java:comp/env/spring.application.json
。
RandomValuePropertySource
对于注入随机值(例如,在机密或测试用例中)非常有用。它可以生成整数、long、uuid 或字符串,如下例所示:
my.secret=${random.value}
my.number=${random.int}
my.bignumber=${random.long}
my.uuid=${random.uuid}
my.number.less.than.ten=${random.int(10)}
my.number.in.range=${random.int[1024,65536]}
random.int*
的语法是 OPEN value (,max) CLOSE
,OPEN, CLOSE
是任意字符, value, max
是数字。如果提供了 max
,那么 value
是最小值,max
是最大值(独占)。
默认情况下,SpringApplication
将任意命令行选项参数(以 --
开头的参数,比如 --server.port=9000
)转换为 property
并且将它们添加到 Spring Environment
。如前所述,命令行属性始终优先于其他属性源。
如果你不想让命令行属性添加到 Environment
,你可以使用 SpringApplication.setAddCommandLineProperties(false)
关闭。
SpringApplication
从 application.properties
文件加载属性。属性文件位于以下位置,并将其添加到 Spring Environment
中:
/config
子目录/config
包该列表按优先级排序(在列表中较高位置定义的属性覆盖在较低位置定义的属性)。
你也可以使用 YAML(’.yml’) 文件 代替 ‘.properties’。
如果你不喜欢将 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.name
和spring.config.location
很早就用于确定必须加载哪些文件。它们必须定义为环境属性(通常是 OS 环境变量、系统属性或命令行参数)。
如果 spring.config.location
包含目录(而不是文件),则它们应该以 /
(并且,在运行时,在加载之前,应该附加从 spring.config.name
生成的名称,包括 profile-specific 文件的文件名)。在 spring.config.location
中指定的文件按原样使用,不支持 profile-specific 变量,并且由任何特定于 profile-specific 的属性重写。
配置的位置以相反的顺序搜索。默认情况下,配置的位置是 classpath:/
, classpath:/config/
,file:./
,file:./config/
。搜索结果如下:
file:./config/
file:./
classpath:/config/
classpath:/
当使用 spring.config.location
配置自定义配置位置时,它们将替换默认位置。例如,如果使用值 classpath:/custom config/,file:./custom-config/
配置 spring.config.location
,则搜索顺序如下:
file:./custom-config/
classpath:custom-config/
此外,当使用 spring.config.additional-location
配置自定义配置位置时,除了默认位置之外,还将使用它们。在默认位置之前搜索其他位置。例如,如果配置了classpath:/custom config/、file:./custom-config/
的其他位置,则搜索顺序如下:
file:./custom-config/
classpath:custom-config/
file:./config/
file:./
classpath:/config/
classpath:/
此搜索顺序允许你在一个配置文件中指定默认值,然后有选择地重写另一个配置文件中的这些值。你可以在默认位置之一的 application.properties
(或使用 spring.config.name
选择的任何其他基本名称)中为应用程序提供默认值。然后,可以在运行时使用位于其中一个自定义位置的其他文件覆盖这些默认值。
如果使用环境变量而不是系统属性,大多数操作系统不允许使用句点分隔的键名,但是可以使用下划线(例如,使用
SPRING_CONFIG_NAME
而不是SPRING.CONFIG.NAME
)。有关详细信息,参见 环境变量绑定。
如果应用程序在容器中运行,那么可以使用 JNDI 属性(在
java:comp/env
中)或 servlet 上下文初始化参数来代替环境变量或系统属性,或者也可以使用环境变量或系统属性。
除了 application.properties
文件,profile-specific 属性也能通过命名惯例 application-{profile}.properties
定义。Environment
有个默认 profiles 集合(默认情况为 [default]
),在没有设置激活的 profiles 时会被使用(例如,如果没有明确指定激活的 profiles,application-default.properties
中的属性会被加载)。
Profile-specific 属性加载路径和标准的 application.properties
相同,并且 profile-specific 文件总是会覆盖 non-specific 文件,不管 profile-specific 文件是否被打包到 jar 中。
如果定义多个 profiles,使用的是最后一个。例如,spring.profiles.active
定义的 profiles 被添加到通过 SpringApplication
API 定义的 profiles 后面,因此优先级更高。
如果你已经在
spring.config.location
下定义所有文件(非目录),那些profile-specific
的文件将不被考虑。如果想使用profile-specific
属性,那就在spring.config.location
下使用目录。
application.properties
中的值在使用时通过现有环境进行查找,因此你可以引用以前定义的值(例如,从系统属性)。
app.name=MyApp
app.description=${app.name} is a Spring Boot application
你可以使用此技术创建现有 Spring Boot 属性的 “短” 变体。有关详细信息,参阅 how to.html。
Spring Boot不提供任何内置的对加密属性值的支持,但是,它提供了修改 Spring 环境中包含的值所必需的挂接点。EnvironmentPostProcessor
接口允许在应用程序启动之前操作环境。有关详细信息,参见 howto.html。
如果你正在寻找一种安全的方式来存储凭据和密码,Spring Cloud Vault 项目将为在 HashiCorp Vault 中存储外部化配置提供支持。
YAML 是 JSON 的超集,因此,它是一种用于指定分层配置数据的方便格式。只要类路径上有 SnakeYAML
库,SpringApplication
类就会自动支持 YAML
作为属性的替代。
如果你使用 “Starters”,
spring-boot-starter
将自动提供 SnakeYAML 。
Spring Framework 提供了两个转换类用于加载 YAML 文档,YamlPropertiesFactoryBean
将 YAML 加载为 Properties
,YamlMapFactoryBean
将 YAML 加载为 Map
。
比如,思考以下 YAML 文档:
environments:
dev:
url: https://dev.example.com
name: Developer Setup
prod:
url: https://another.example.com
name: My Cool App
前面的示例将转换为以下属性:
environments.dev.url=https://dev.example.com
environments.dev.name=Developer Setup
environments.prod.url=https://another.example.com
environments.prod.name=My Cool App
YAML 列表用 [index]
解引用程序表示为属性键。例如,考虑以下 YAML:
my:
servers:
- dev.example.com
- another.example.com
The preceding example would be transformed
前面示例转为以下属性:
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;
}
}
YamlPropertySourceLoader
类可用于在 Spring Environment
中将 YAML 暴露为 PropertySource。这样做可以使用 @Value
注释和占位符语法来访问 YAML 属性。
你可以通过 spring.profiles
键指定文档何时应用,可以在单个文件中指定多个特定于配置文件的 YAML 文档,如下例所示:
server:
address: 192.168.1.100
---
spring:
profiles: development
server:
address: 127.0.0.1
---
spring:
profiles: production & eu-central
server:
address: 192.168.1.120
在前面的示例中,如果 development
配置处于启动状态,则 server.address
属性为127.0.0.1
。类似地,如果 production
和 eu-central
配置处于启动状态,则 server.address
属性为 192.168.1.120
。如果未启用 development
、production
和 eu-central
配置,则属性值为 192.168.1.100
。
因此,
spring.profiles
可以包含一个简单的 profile 名(例如production
)或 profile 表达式。profile 表达式允许表达更复杂的 profile 逻辑,例如production&(eu-central | eu west)
。查看 参考指南 了解更多详细信息。
如果应用程序上下文启动时没有显式激活配置,则将激活默认配置。因此,在下面的 YAML 中,我们为 spring.security.user.password
设置了一个仅在 “default” 配置文件中可用的值:
server:
port: 8000
---
spring:
profiles: default
security:
user:
password: weak
但是,在下面的示例中,密码将始终被设置好了,因为它没有附加到任何配置文件,并且必须在所有其他配置文件中根据需要显式重置密码:
server:
port: 8000
spring:
security:
user:
password: weak
使用 spring.profiles
元素指定的 Spring 配置文件可以通过使用 !
字符设置否定配置文件。如果为单个文档同时指定了否定配置文件和非否定配置文件,则必须至少有一个非否定配置文件匹配,并且不能有否定配置文件匹配。
YAML文件不能使用 @PropertySource
注解加载。因此,如果需要以这种方式加载值,则需要使用属性文件。
在 profile-specific 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。它已经被认为是 profile-specific,因此嵌套文档将被忽略。
建议不要混合使用 profile-specific YAML文件和多个 YAML 文档。坚持只使用其中一个。
使用 @Value()${property})
注解注入配置属性有时会很麻烦,特别是在处理多个属性或数据本质上是分层的情况下。Spring Boot 提供了另一种处理属性的方法,这种方法允许强类型 bean 控制和验证应用程序的配置。
参见
@Value和类型安全配置属性之间的区别
。
可以绑定一个标准 JavaBean 属性的 bean,如下面的例子所示:
package com.example;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("acme")
public class AcmeProperties {
private boolean enabled;
private InetAddress remoteAddress;
private final Security security = new Security();
public boolean isEnabled() { ... }
public void setEnabled(boolean enabled) { ... }
public InetAddress getRemoteAddress() { ... }
public void setRemoteAddress(InetAddress remoteAddress) { ... }
public Security getSecurity() { ... }
public static class Security {
private String username;
private String password;
private List<String> roles = new ArrayList<>(Collections.singleton("USER"));
public String getUsername() { ... }
public void setUsername(String username) { ... }
public String getPassword() { ... }
public void setPassword(String password) { ... }
public List<String> getRoles() { ... }
public void setRoles(List<String> roles) { ... }
}
}
前面的 POJO 定义了以下属性:
acme.enabled
,默认值为 false。
acme.remote-address
,其类型可以从字符串强制转换。
acme.security.username
,具有嵌套的 “security” 对象,其名称由属性的名称确定。特别是,返回类型根本没有在那里使用,可能是 SecurityProperties
。
acme.security.password
:密码。
acme.security.roles
,默认为 USER 的字符串集合。
映射到
Spring Boot
中可用的@ConfigurationProperties
类的属性(通过属性文件、YAML文件、环境变量等配置)是公共API,但类本身的访问器(getter/setter)不是直接使用的。
这种安排依赖于默认的空构造函数,getter 和 setter 通常是必需的,因为绑定是通过标准的 Java Bean 属性描述符进行的,就像 Spring MVC 一样。在下列情况下,可省略setter:
Maps,只要被初始化,就需要一个 getter,但不一定是 setter,因为绑定器可以对它们进行修改。
Collections/arrays,可以通过索引(通常使用YAML)或使用单个逗号分隔的值(属性)访问集合和数组。在后一种情况下,setter 是强制性的。我们建议始终为此类类型添加 setter。如果初始化集合,请确保它不是不可变的(如前一个示例所示)。
如果嵌套的 POJO 属性已初始化(与前面示例中的
Security
字段类似),则不需要 setter。如果希望绑定器使用其默认构造函数动态创建实例,则需要一个setter。有些人使用 Project Lombok 自动添加 getter 和 setter。确保 Lombok 不会为此类类型生成任何特定的构造函数,因为容器会自动使用它来实例化对象。
最后,只考虑标准的 Java Bean 属性,不支持对静态属性的绑定。
上一节的例子可以用不可变的方式重写,如下面的例子所示:
package com.example;
import java.net.InetAddress;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
import org.springframework.boot.context.properties.bind.DefaultValue;
@ConstructorBinding
@ConfigurationProperties("acme")
public class AcmeProperties {
private final boolean enabled;
private final InetAddress remoteAddress;
private final Security security;
public AcmeProperties(boolean enabled, InetAddress remoteAddress, Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
public boolean isEnabled() { ... }
public InetAddress getRemoteAddress() { ... }
public Security getSecurity() { ... }
public static class Security {
private final String username;
private final String password;
private final List<String> roles;
public Security(String username, String password,
@DefaultValue("USER") List<String> roles) {
this.username = username;
this.password = password;
this.roles = roles;
}
public String getUsername() { ... }
public String getPassword() { ... }
public List<String> getRoles() { ... }
}
}
在此设置中,@ConstructorBinding
注解用于指示应使用构造函数绑定。这意味着绑定器将期望找到一个具有希望绑定的参数的构造函数。
@ConstructorBinding
类的嵌套成员(如上例中的 Security
)也将通过其构造函数绑定。
可以使用 @DefaultValue
指定默认值,并应用相同的转换服务将字符串值强制为缺少属性的目标类型。默认情况下,如果没有属性绑定到 Security
,那么 AcmeProperties
实例将包含一个空的 Security
实例 。如果希望返回一个非空的 Security
实例,即使没有属性绑定到它,也可以使用空的 @DefaultValue
注解来执行此操作:
package com.example;
import java.net.InetAddress;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
import org.springframework.boot.context.properties.bind.DefaultValue;
@ConstructorBinding
@ConfigurationProperties("acme")
public class AcmeProperties {
private final boolean enabled;
private final InetAddress remoteAddress;
private final Security security;
public AcmeProperties(boolean enabled, InetAddress remoteAddress, @DefaultValue Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
}
要使用构造函数绑定,必须使用
@EnableConfigurationProperties
或配置属性扫描启用类。你不能对由常规 Spring 机制创建的 bean 使用构造函数绑定(例如@Component
bean、通过@Bean
方法创建的 bean 或使用@Import
加载的 Bean)。
如果类有多个构造函数,也可以直接在应该绑定的构造函数上使用
@ConstructorBinding
。
@ConfigurationProperties
-annotated typesSpring Boot
提供了绑定 @ConfigurationProperties
类型并将其注册为 bean 的基础结构。你可以逐个类启用配置属性,也可以启用与组件扫描类似的配置属性扫描。
有时,用 @ConfigurationProperties
注解的类可能不适合扫描,例如,如果你正在开发自己的自动配置或者你希望有条件地启用它们。在这些情况下,使用@EnableConfigurationProperties
注解指定要处理的类型列表。这可以在任何 @Configuration
类上完成,如下例所示:
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(AcmeProperties.class)
public class MyConfiguration {
}
要使用配置属性扫描,需要把 @configurationpropertiescan
注解添加到应用中。通常,它被添加到用 @Springbootsapplication
注解的主应用程序类中,但可以添加到任何 @Configuration
类中。默认情况下,扫描将从注解声明的包中开始。如果要定义扫描特定的包,可以按以下示例所示执行操作:
@SpringBootApplication
@ConfigurationPropertiesScan({ "com.example.app", "org.acme.another" })
public class MyApplication {
}
当使用配置属性扫描或通过
@EnableConfigurationProperties
注册@ConfigurationProperties
bean时,bean 有一个常用命名:< prefix >-< fqn >,其中< prefix >是@ConfigurationProperties
注解中指定的环境的键前缀,< fqn >是 bean 的完全限定名。如果注解没有提供任何前缀,则只使用 bean 的完全限定名。上面例子中的 bean 是
acme-com.example.AcmeProperties
。
建议 @ConfigurationProperties
只处理环境,特别是不要从上下文中注入其他 bean。对于角点情况(corner cases),可以使用 setter 注入或框架提供的任意 *Aware(例如,如果需要访问 Environment
,则使用 EnvironmentAware
)。如果仍要使用构造函数注入其他 bean,则必须使用 @Component
注解配置属性 bean,并使用基于 JavaBean 的属性绑定。
@ConfigurationProperties
-annotated types这种类型的配置在 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());
// ...
}
}
除了使用 @ConfigurationProperties
注解类之外,还可以在公开的 @Bean
方法上使用它。如果要将属性绑定到不在你控制范围内的第三方组件,那么这样做特别有用。
要从环境属性配置 bean,将 @ConfigurationProperties
添加到其 bean 注册中,如下例所示:
@ConfigurationProperties(prefix = "another")
@Bean
public AnotherComponent anotherComponent() {
...
}
用 another
前缀定义的任何 JavaBean 属性都映射到 AnotherComponent
bean上 ,映射方式类似于前面的 AcmeProperties
示例。
Spring Boot 使用一些宽松的规则将环境属性绑定到 @ConfigurationProperties
bean,因此环境属性名和 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;
}
}
使用上述代码,可以使用以下属性名:
属性 | 注意 |
---|---|
acme.my-project.person.first-name |
Kebab 案例,建议在 .properties 和 .yml 文件中使用。 |
acme.myProject.person.firstName |
标准的大小写语法。 |
acme.my_project.person.first_name |
下划线表示法,这是 .properties 和 .yml 文件中使用的另一种格式。 |
ACME_MYPROJECT_PERSON_FIRSTNAME |
大写格式,在使用系统环境变量时推荐使用。 |
注解的
orefix
值必须采用 kebab 表示(小写并以-分隔,如acme.my-project.person
)。
属性源的绑定规则
属性源 | Simple | List |
---|---|---|
Properties File | 驼峰表示、kebab 表示、下划线表示 | 使用 [] 或逗号分隔值的标准列表语法 |
YAML File | 驼峰表示、kebab 表示、下划线表示 | 标准的YAML列表语法或逗号分隔的值 |
Environment Variables | 用下划线作为分隔符的大写格式(参见环境变量绑定) | 由下划线包围的数值(参见环境变量绑定) |
System properties | 驼峰表示、kebab 表示、下划线表示 | 使用 [] 或逗号分隔值的标准列表语法 |
建议在可能的情况下,以小写的 kebab 格式存储属性,例如
my.property-name=acme
。
绑定到 map
属性时,如果键包含除小写字母数字字符或 -
以外的任何字符,则需要使用括号表示法,以便保留原始值。如果键没有被 [] 包围,则将删除不是字母数字或 -
的任何字符。例如,考虑将以下属性绑定到 map
:
acme:
map:
"[/key1]": value1
"[/key2]": value2
/key3: value3
上面的属性将绑定到以 /key1
、/key2
和 key3
作为 map
中的键的映射。
对于 YAML 文件,方括号需要用引号括起来,以便正确地解析键。
大多数操作系统都会对可用于环境变量的名称施加严格的规则。例如,Linux shell 的变量只能包含字母(a
到 z
或 A
到 Z
)、数字(0
到 9
)或下划线字符(_
)。按照惯例,Unix shell 的变量的名称也将是大写的。
Spring Boot 的松散绑定规则尽可能地与这些命名限制兼容。
要将规范格式的属性名转换为环境变量名,可以遵循以下规则:
用下划线(_
)替换点(.
)。
去掉所有扩折号(-
)。
转换为大写。
例如,配置属性 spring.main.log-startup-info
将是一个名为 SPRING_MAIN_LOGSTARTUPINFO
的环境变量。
下划线不能用于替换属性名称中的扩折号。如果尝试在上面的示例中使用
SPRING_MAIN_LOG_STARTUP_INFO
,则不会绑定任何值。
当绑定到对象列表时,也可以使用环境变量。要绑定到列表,应该在变量名中用下划线包围元素编号。
例如,配置属性 my.acme[0].other
将使用一个名为 MY_ACME_0_OTHER
的环境变量。
当在多个位置配置列表时,可以通过替换整个列表覆盖工作。
例如,假设 MyPojo
对象的名称和描述属性在默认情况下为 null
。下面的例子展示了来自 AcmeProperties
的一个 MyPojo
对象列表:
@ConfigurationProperties("acme")
public class AcmeProperties {
private final List<MyPojo> list = new ArrayList<>();
public List<MyPojo> getList() {
return this.list;
}
}
思考以下配置:
acme:
list:
- name: my name
description: my description
---
spring:
profiles: dev
acme:
list:
- name: my another name
如果 dev
配置未处于启用状态,则 AcmeProperties.list
包含一个 MyPojo
条目,像前面定义一样。但是,如果启用了 dev
配置,则列表仍然只包含一个条目(名称为 my another name
,并且 description 为 null
)。此配置不会向列表中添加第二个 MyPojo
实例,也不会合并项。
在多个配置文件中指定列表时,将使用优先级最高的配置文件(且仅使用该配置文件)。思考以下示例:
acme:
list:
- name: my name
description: my description
- name: another name
description: another description
---
spring:
profiles: dev
acme:
list:
- name: my another name
在前面的示例中,如果 dev
配置处于启用状态,那么 AcmeProperties.list
包含一个 MyPojo
条目(名称为 my another name
,并且 description 为 null
)。对于 YAML,逗号分隔列表和YAML 列表都可以用于完全重写列表的内容。
对于 map
属性,可以使用从多个源的属性值进行绑定。但是,对于多个源中的同一属性,将使用优先级最高的属性。以下示例来自 AcmeProperties
的 Map
:
@ConfigurationProperties("acme")
public class AcmeProperties {
private final Map<String, MyPojo> map = new HashMap<>();
public Map<String, MyPojo> getMap() {
return this.map;
}
}
思考以下配置:
acme:
map:
key1:
name: my name 1
description: my description 1
---
spring:
profiles: dev
acme:
map:
key1:
name: dev name 1
key2:
name: dev name 2
description: dev description 2
如果 dev
配置未处于活动状态,则 AcmeProperties.map
包含一个键为 key1
的条目(名称为 my name 1
,description 为 my description 1
)。但是,如果启用了dev 配置,那么 map
包含两个条目,键 key1
(名称为 dev name 1
,description 为 my description 1
)和 key2
(名称为 dev name 2
,description 为 dev description 2
)。
上面的合并规则适用于来自所有属性源的属性,而不仅仅是 YAML 文件。
当 Spring Boot 绑定到 @ConfigurationProperties
bean时,它尝试将外部应用程序属性强制转换为正确的类型。如果需要自定义类型转换,可以提供 ConversionService
bean(使用名为 ConversionService
的 bean)或自定义属性编辑器(通过 CustomEditorConfigurer
bean)或自定义转换器(使用注解为 @ConfigurationPropertiesBinding
的 bean 定义)。
由于该 bean 在应用程序生命周期的早期被使用,因此要确保限制
ConversionService
正在使用的依赖项。通常,你需要的依赖项在创建时可能无法完全初始化。如果配置键的强制转换不需要重命名自定义转换服务,并且只依赖于使用@ConfigurationPropertiesBinding
限定的自定义转换,那么你可能希望重命名自定义ConversionService
。
SpringBoot对表示时间有专门的支持。如果你公开了 java.time.Duration
属性,则可用应用程序属性中的以下格式:
常规的 long 表示(除非指定了 @DurationUnit
,否则使用毫秒作为默认单位)
java.time.Duration
使用的标准 ISO-8601 格式
一种更可读的格式,其中值和单位是耦合的(例如,10s
表示10 秒)
思考以下示例:
@ConfigurationProperties("app.system")
public class AppSystemProperties {
@DurationUnit(ChronoUnit.SECONDS)
private Duration sessionTimeout = Duration.ofSeconds(30);
private Duration readTimeout = Duration.ofMillis(1000);
public Duration getSessionTimeout() {
return this.sessionTimeout;
}
public void setSessionTimeout(Duration sessionTimeout) {
this.sessionTimeout = sessionTimeout;
}
public Duration getReadTimeout() {
return this.readTimeout;
}
public void setReadTimeout(Duration readTimeout) {
this.readTimeout = readTimeout;
}
}
要指定 30 秒的会话超时,30
、PT30S
和 30s
都是等效的。读取超时 500ms
可以用以下任何形式指定:500
、PT0.5S
和 500ms
。
你也可以使用任何受支持的单位。这些是:
ns
纳秒
us
微秒
ms
毫秒
s
秒
m
分钟
h
小时
d
天
默认单位是毫秒,可以使用 @DurationUnit
重写,如上面的示例所示。
如果你要从简单使用
Long
来表示持续时间的以前版本升级,如果它不是毫秒,确保在切换到Duration
时间的同时定义单元(使用@DurationUnit)。这样做提供了一个透明的升级路径,同时支持更丰富的格式。
Spring 框架有一个 DataSize
的值类型,它以字节表示大小。如果你暴露了 DataSize
属性,则可用应用属性中的以下格式:
常规的 long
表示(除非指定了 @DataSizeUnit
,否则使用字节作为默认单位)
一种更可读的格式,其中值和单位是耦合的(例如,10MB
表示 10 兆字节)
思考以下示例:
@ConfigurationProperties("app.io")
public class AppIoProperties {
@DataSizeUnit(DataUnit.MEGABYTES)
private DataSize bufferSize = DataSize.ofMegabytes(2);
private DataSize sizeThreshold = DataSize.ofBytes(512);
public DataSize getBufferSize() {
return this.bufferSize;
}
public void setBufferSize(DataSize bufferSize) {
this.bufferSize = bufferSize;
}
public DataSize getSizeThreshold() {
return this.sizeThreshold;
}
public void setSizeThreshold(DataSize sizeThreshold) {
this.sizeThreshold = sizeThreshold;
}
}
要指定 10 兆字节的缓冲区大小,10
和 10MB
是等效的。256 字节的大小阈值可以指定为 256
或 256B
。
也可以使用任意受支持的单元:
B
表示字节
KB
表示千字节
MB
表示兆字节
GB
表示千兆字节
TB
(兆字节)
默认单位是字节,可以使用 @DataSizeUnit
重写,如上面的示例所示。
如果你要从以前的版本升级,而以前的版本只是使用
Long
来表示大小,确保定义单元(使用@DataSizeUnit
),如果它不是字节,则切换到DataSize
。这样做提供了一个透明的升级路径,同时支持更丰富的格式。
每当使用 Spring 的 @Validated
注解对 @ConfigurationProperties
类进行注解时,Spring Boot 就会尝试验证它们。你可以直接在配置类上使用 JSR-303 javax.validation
约束注释。为此,应确保类路径上有一个兼容的J SR-303
实现,然后将约束注释添加到字段中,如下例所示:
@ConfigurationProperties(prefix="acme")
@Validated
public class AcmeProperties {
@NotNull
private InetAddress remoteAddress;
// ... getters and setters
}
你还可以通过注释
@Bean
方法来触发验证,该方法使用@Validated
创建配置属性。
为了确保对嵌套属性也能触发验证,即使找不到属性,也必须用 @Valid
注解关联的字段。以下示例基于前面 的 AcmeProperties
示例:
@ConfigurationProperties(prefix="acme")
@Validated
public class AcmeProperties {
@NotNull
private InetAddress remoteAddress;
@Valid
private final Security security = new Security();
// ... getters and setters
public static class Security {
@NotEmpty
public String username;
// ... getters and setters
}
}
还可以通过创建名为 configurationPropertiesValidator
的 bean 定义来添加自定义Spring Validator
。@Bean
方法应该声明为静态的。配置属性验证器是在应用程序生命周期的早期创建的,将 @Bean
方法声明为静态的话就可以创建Bean,而无需实例化@Configuration
类。这样做可以避免任何可能由早期实例化引起的问题。
spring-boot-actuator 模块包含一个端点,该端点公开所有
@ConfigurationProperties
bean。将 web 浏览器指向/actuator/configprops
或使用等效的 JMX 端点。有关详细信息,参阅 “生产就绪功能” 部分。
@Value
注解是一个核心容器特性,它不提供与类型安全配置属性相同的特性。下表总结了 @ConfigurationProperties
和 @Value
支持的功能:
特性 | @ConfigurationProperties | @Value |
---|---|---|
松散绑定 | Yes | Limited |
元数据支持 | Yes | No |
SpEL 表达式 |
No | Yes |
如果你为自己的组件定义了一组配置键,建议你将它们分组到一个带有 @ConfigurationProperties
注解的 POJO 中。这样做将提供结构化的、类型安全的对象,你可以将其注入到自己的 bean 中。
如果你确实想使用 @Value
,建议使用规范形式引用属性名(kebab case——只使用小写字母)。这将允许 Spring Boot 使用与松散绑定 @ConfigurationProperties
时相同的逻辑。例如,@Value("{demo.item price}")
将从 application.properties
文件中获取 demo.item-price
和 demo.itemPrice
表单,并从系统环境中获取 demo_itemPrice
表单。如果改用 @Value("{demo.item price}")
,则不考虑 demo.item-price
和 demo_itemPrice
。
最后,虽然可以在 @Value
中编写 SpEL
表达式,但此类表达式不会从应用程序属性文件中处理。
Spring Profile 提供了一个方法来将应用配置分离,并在不同的环境中使用它们。任意的 @Component
, @Configuration
或者 @ConfigurationProperties
都可以被标记为 @Profile
来限制它的加载,如下面的例子所示:
@Configuration(proxyBeanMethods = false)
@Profile("production")
public class ProductionConfiguration {
// ...
}
如果
@ConfigurationProperties
bean 是通过@EnableConfigurationProperties
而不是自动扫描注册的,则需要在具有@EnableConfigurationProperties
注解的@Configuration
类上指定@Profile
注释。在扫描@ConfigurationProperties
的情况下,可以在@ConfigurationProperties
类本身上指定@Profile
。
你可以使用 spring.profiles.active
指定 Environment
属性哪些配置是生效的,也可以使用本章前面描述的任何方式指定属性。比如,你可以写在你的 properties.properties
文件,如下所示:
spring.profiles.active=dev,hsqldb
你也可以在命令行上指定:--spring.profiles.active=dev,hsqldb
。
spring.profile.active
属性遵循着其它属性的顺序规则:最高的 PropertrySource
获胜。这意味着你可以在 application.properties
中指定启动的配置,然后在命令行中修改它。
有时,将 rofile-specific 属性添加到启用配置比替换它们更很有用的。spring.profiles.include
属性可用于无条件添加启用配置。SpringApplication
入口还有一个用于设置其他配置的Java API(即在 spring.profiles.active
属性激活配置之上)。可参阅 SpringApplication 中的 setAdditionalProfiles()
方法。
例如,--spring.profiles.active=prod
运行具有以下属性的应用程序时,proddb
和p rodmq
配置也会被激活:
---
my.property: fromyamlfile
---
spring.profiles: prod
spring.profiles.include:
- proddb
- prodmq
记住,可以在 YAML 文档中定义
spring.profiles
属性,以确定配置中何时包含此特定文档。有关详细信息,参见 howto.html。
在你的应用启动前,你可以调用 SpringApplication.setAdditionalProfiles(...)
方法来通过编程设置启动的配置,也可以通过使用 Spring 的 ConfigurableEnvironment
接口来启动配置。
application.properties
(或 application.yml
)和通过 @ConfigurationProperties
引用的文件的 Profile-specific 变量都被视为文件并加载。有关详细信息,参阅 “特定于配置文件的属性"。
Spring Boot 使用 Commons Logging
记录所有内部日志记录,但底层日志的实现是打开的。它为 Java Util Logging、Log4J2 和 Logback 提供了默认配置。在每种情况下,日志记录器都使用预先配置在控制台输出,还提供可选的文件输出。
默认情况下,如果使用 “Starters”,则使用 Logback 进行日志记录。还包括适当的 Logback 路由,以确保使用 Java Util Logging、Commons Logging、Log4J 或 SLF4J 的依赖库都能正常工作。
Java 有很多的日志框架,如果上面列表看起来让人困惑也不要当心。一般情况下,你不需要改变日志依赖,Spring Boot 默认下的工作就很好。
当你将应用程序部署到 servlet 容器或应用程序服务器时,通过 Java Util Logging API 执行的日志记录不会被路由到应用程序的日志中。这可以防止容器或其它已部署到容器的其他应用程序执行的日志记录出现在你的应用程序的日志中。
Spring Boot 默认情况下的输入格式类似于下面:
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: [/*]
输出项包括下面内容:
ERROR
,WARN
,INFO
,TRACE
。---
分隔符区分日志内容的开始Logback 没有
FATAL
级别,它被映射WieERROR
。
默认的日志配置会在消息写入时将其回显到控制台。默认情况下,将记录 ERROR
级别、WARN
级别和 INFO
级别的消息。你还可以通过使用 --debug
标志启动应用程序来启用调试模式。
$ java -jar myapp.jar --debug
你也可以在你的
application.properties
中指定debug=true
。
启用调试模式后,将配置一组核心记录器(嵌入式容器、Hibernate
和 Spring Boot
)以输出更多信息。启用调试模式不会将应用程序配置为使用 DEBUG
级别记录所有消息。
或者,可以通过使用 --trace
标志(或者在 application.properties
中设置 trace=true
)启动应用程序来启用 TRACE
模式。这样做可以为选择的核心记录器(嵌入式容器、Hibernate 模式生成器和整个 Spring 组合)启用跟踪日志记录。
如果你的终端支持 ANSI,则可以使用彩色输出来帮助可读性。可以将 spring.output.ansi.enabled
设置为支持的值以覆盖默认值。
使用 %clr 转换字配置颜色编码。在最简单的形式中,转换器根据日志级别为输出着色,如下例所示:
%clr(%5p)
下表描述了日志级别与颜色的映射:
级别 | 颜色 |
---|---|
FATAL |
红色 |
ERROR |
红色 |
WARN |
黄色 |
INFO |
绿色 |
DEBUG |
绿色 |
TRACE |
绿色 |
此外,你也可以指定使用的颜色或样式,将它作为选项提供给转换。例如,要使文本变成黄色,可以使用以下设置:
%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){yellow}
以下的颜色和样式是支持的:
blue
cyan
faint
green
magenta
red
yellow
默认情况下,Spring Boot 日志输出到控制台,不写入日志文件。如果希望在控制台输出之外写入日志文件,则需要设置一个 log.file.name
或 log .file.path
属性(例如,在你的 application.properties
)。
下表展示了能被一起使用的 logging.*
属性:
logging.file.name |
logging.file.path |
例子 | 描述 |
---|---|---|---|
(none) | (none) | 只输出到控制台 | |
指定文件 | (none) | my.log |
写入指定的日志文件。名称可以是确切的位置或相对于当前目录。 |
(none) | 指定目录 | /var/log |
将 spring.log 写入指定的目录。名称可以是确切的位置或相对于当前目录。 |
日志文件在达到 10 MB时会自动覆盖前面的,与控制台输出一样,默认情况下会记录 ERROR
级别、WARN
级别和 INFO
级别的消息。可以使用 logging.file.max-size
属性更改大小限制。除非设置了 logging.file.max-history
属性,否则默认情况下将保留最近 7 天的日志文件。可以使用 logging.file.total-size-cap
限制日志存档的总大小。当日志存档的总大小超过该阈值时,将删除备份。要在应用程序启动时强制清除日志存档,使用 logging.file.clean-history-on-start
属性。
日志属性独立于实际的日志基础结构。因此,特定的配置键(例如 Logback 的
logback.configurationFile
)不由 Spring Boot 管理。
Spring Boot 所有支持的日志系统的日志级别都以 logging.level.
的形式写在 Environment
中(比如在 application.properties
),其中 level
是 TRACE/DEBUG/INFO/WARN/ERROR/FATAL/OFF 中的一种,root
日志器能使用 logging.level.root
进行配置。
如下例展示了 application.properties
中部分日志设置:
logging.level.root=warn
logging.level.org.springframework.web=debug
logging.level.org.hibernate=error
也可以使用环境变量来设置日志级别,比如 LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_WEB=DEBUG
能将 org.springframework
设置为 DEBUG
。
上面的方法只适用于包级别的日志记录。因为松散绑定总是将环境变量转换为小写,所以不可能以这种方式为单个类配置日志记录。如果需要为类配置日志记录,可以使用
SPRING_APPLICATION_JSON
变量。
将相关的日志记录器分组在一起通常是很有用的,这样就可以同时对它们进行配置。例如,你通常可能会更改所有与 Tomcat 相关的日志记录程序的日志级别,但是你无法轻松记住顶级包。
为了帮助实现这一点,Spring Boot 允许在 Spring Environment
中定义日志组。例如,下面是如何定义一个 “tomcat” 组,方法是将其添加到你的 application.properties
中:
logging.group.tomcat=org.apache.catalina, org.apache.coyote, org.apache.tomcat
一旦被定义了,你就可以使用一行代码修改组中所有记录器的级别:
logging.level.tomcat=TRACE
Spring Boot 包含以下这些开箱即用的预定义记录组:
名字 | 记录器 |
---|---|
web | org.springframework.core.codec , org.springframework.http , org.springframework.web , org.springframework.boot.actuate.endpoint.web , org.springframework.boot.web.servlet.ServletContextInitializerBeans |
sql | org.springframework.jdbc.core , org.hibernate.SQL , org.jooq.tools.LoggerListener |
可以通过在类路径上安装适当的库来激活各种日志系统,还可以通过在类路径的根目录中或在由以下 Spring Environment
属性指定的位置提供适当的配置文件来进一步自定义日志系统:logging.config
。
通过使用 org.springframework.Boot.loggingSystem
属性,可以强制 Spring Boot 使用特定的日志系统。该值应为 LoggingSystem
实现的完全限定类名。你还可以使用值 none
来完全禁用 Spring Boot 的日志配置。
由于日志记录是在创建
ApplicationContext
之前初始化的,所以不可能控制来自Spring@Configuration
文件中的@PropertySources
的日志记录。更改日志系统或完全禁用它的唯一方法是通过系统属性。
根据您的日志系统,将加载以下文件:
日志系统 | 自定义文件 |
---|---|
Logback | logback-spring.xml , logback-spring.groovy , logback.xml , 或logback.groovy |
Log4j2 | log4j2-spring.xml 或log4j2.xml |
JDK (Java Util Logging) | logging.properties |
如果可能,建议在日志配置中使用
-spring
变体(例如,使用logback-spring.xml
而不是logback.xml
)。如果使用标准的配置位置,Spring无法完全控制日志初始化。
Java Util Logging 中存在一些已知的类加载问题,这些问题会在从 “可执行jar” 运行时造成错误。建议尽可能在从 “可执行jar” 运行时避免使用它。
为了帮助自定义,一些其他属性从 Spring 环境转移到了系统属性,如下表所示:
Spring Environment | System Property | Comments |
---|---|---|
logging.exception-conversion-word |
LOG_EXCEPTION_CONVERSION_WORD |
记录异常时使用的转换字。 |
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 |
日志日期格式的追加器模式。(仅支持默认的 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)。(仅支持默认的Logback设置。) |
PID |
PID |
当前进程ID(如果可能,在还没有定义为OS环境变量时发现)。 |
所有支持的日志系统在解析配置文件时都可以参考系统属性。查看 spring-boot.jar
中的默认配置示例:
如果要在日志属性中使用占位符,应该使用 Spring Boot的语法,而不是底层框架的语法。值得注意的是,如果使用 Logback,则应使用:作为属性名与其默认值之间的分隔符,而不是使用:
-
。
你可以通过仅用 Logback 覆盖
LOG_LEVEL_PATTERN
(或logging.pattern.level
)来将MDC和其他特殊内容添加到日志行。例如,如果使用logging.pattern.level=user:%X{user}%5p
,则默认日志格式包含 “user” 的MDC条目(如果存在),如下例所示:2019-08-30 12:30:04.031 user:someone INFO 22174 --- [ nio-8080-exec-0] demo.Controller Handling authenticated request
Spring Boot 包含许多 Logback 扩展,可以帮助进行高级配置。你可以在 logbackspring .xml
配置文件中使用这些扩展。
因为标准的
log.xml
配置文件加载得太早,所以不能在其中进行扩展。你需要使用logback-spring.xml
或定义logging.config
属性。
这些扩展不能与 Logback 的配置扫描一起使用。如果你尝试这样做,对配置文件进行更改将导致与以下记录类似的错误:
ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:71 - no applicable action for [springProperty], current ElementPath is [[configuration][springProperty]] ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:71 - no applicable action for [springProfile], current ElementPath is [[configuration][springProfile]]
标记允许根据启动的 Spring 配置选择包含或排除配置部分。配置部分在
元素中的任何地方都受支持。使用 name
属性指定哪个配置文件接受配置。
标记可以包含一个简单配置名称(例如 staging
)或者一个配置表达式。配置表达式允许表达更复杂的配置逻辑,例如 production & (eu-central | eu-west)
。查看参考指南了解更多细节。下面的清单显示了三个示例:
<springProfile name="staging">
springProfile>
<springProfile name="dev | staging">
springProfile>
<springProfile name="!production">
springProfile>
标记允许你暴露 Spring Environment
的属性,以便在 Logback 中使用。这样的话,如果你想在你的 Logback 配置中访问你的 application.properties
文件的变量很有用。标记的工作方式与 Logback 的标准
标记类似。但是,不是指定一个直接值,而是指定属性的源(来自 Environment
)。如果需要将该属性存储在本地范围之外的其他地方,可以使用 scope
属性。如果需要回退值(如果未在环境中设置属性),则可以使用 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>
source
指定方式必须为 kabab(比如my.property-name
)。然而,可以使用松散的规则将属性添加到Environment
中。
Spring Boot 支持本地化消息,因此你的应用可以满足不同语言的用户。默认情况下,Spring Boot 会在类路径的根目录中查找 message
资源包的存在。
当配置的资源包的默认属性文件可用时(即默认情况下为
messages.properties
),应用将自动配置。如果资源包仅包含特定于语言的属性文件,则需要添加默认值。如果找不到与任何配置的基名称匹配的属性文件,则不会有自动配置的MessageSource
。
可以使用 spring.messages
命名空间配置资源包的基名以及其他几个属性,如下例所示:
spring.messages.basename=messages,config.i18n.messages
spring.messages.fallback-to-system-locale=false
spring.message.basename
支持以逗号分隔的位置列表,可以是包限定符,也可以是从类路径根解析的资源。
查看 MessageSourceProperties
获取详情。
Spring Boot 提供了与三个 JSON 映射库的集成:
Jackson 是首选的和默认的库。
提供了Jackson 的自动配置,Jackson 是 spring-boot-starter-json
的一部分。当Jackson 在类路径上时,会自动配置一个 ObjectMapper
bean。提供了几个配置属性来定制 ObjectMapper
的配置。
提供了 Gson 的自动配置。当 Gson 位于类路径上时,将自动配置 Gson
bean。有几个 spring.gson.*
配置属性用于自定义配置。如果要进行更多的控制,可以使用一个或多个 ``GsonBuilderCustomizer。
提供了 JSON-B 的自动配置。当 JSON-B API 和实现位于类路径上时,将自动配置 Jsonb
bean。首选的 JSON-B
实现是 Apache Johnzon,它为其提供了依赖项管理。
Spring Boot 非常适合 web 应用程序开发。您可以使用嵌入的 Tomcat、Jetty、Undertow 或 Netty 来创建一个自包含的 HTTP 服务器。大多数 web 应用程序都使用 spring-boot-starter-web
模块来快速启动和运行。您你可以选择使用 spring-boot-starter-webflux
模块来构建响应式 web 应用程序。
如果你还没有开发一个 Spring Boot web 应用程序,你可以遵循入门部分中的 “Hello World!” 示例。
Spring Web MVC Framwork(通常简称为 “Spring MVC”)是一个丰富的 “模型-视图-控制器(model view controller)” Web框架。Spring MVC 允许你创建特殊的 @Controller
或@RestController
bean来处理传入的 HTTP 请求。控制器中的方法通过使用@RequestMapping
注解映射到 HTTP。
下面的代码显示了一个典型的服务 JSON 数据的 @RestController
:
@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 核心框架的一部分,详细信息可以在参考文档中找到。在 Spring .io/guides 中还有一些介绍Spring MVC的指南。
Spring Boot 为 Spring MVC 提供了自动配置,它可以很好地与大多数应用一起工作。
自动配置在 Spring 默认设置的基础上添加了以下功能:
包含 ContentNegotingViewResolver
和 BeanNameViewResolver
bean。
对服务静态资源的支持,包括对 WebJars 的支持。
自动注册 Converter
、GenericConverter
和 ``Formatter bean。
支持 HttpMessageConverter
。
自动注册 MessageCodesResolver
。
静态 index.html
支持。
自定义 Favicon
支持。
自动使用可配置的 WebBindingInitializerbean
。
如果你想在保留这些 Spring Boot MVC 自定义的同时进行更多 MVC 自定义(拦截器——interceptors、格式化——formatters、视图控制器——view controllers 和其他功能),可以添加自己的 @Configuration
类 webMvcConfiguer
类型,但不需要 @EnableWebMvc
。
如果要提供 RequestMappingHandlerMapping
、RequestMappingHandlerAdapter
或ExceptionHandlerExceptionResolver
的自定义实例,并且仍然保留 Spring Boot MVC 自定义,则可以声明 WebMVCregistration
类型的 bean,并使用它来提供这些组件的自定义实例。
如果想完全控制 Spring MVC,可以添加自己的 @Configuration
,并用 @EnableWebMvc
注解,或者添加自己的 @Configuration
注解 DelegatingWebMvcConfiguration
配置,像@EnableWebMvc
的文档说的那样。
Spring MVC 使用 HttpMessageConverter
接口来转换 HTTP 请求和响应。合理的默认行为是开箱即用。例如,对象可以自动转换为 JSON(通过使用 Jackson 库)或 XML(通过使用Jackson XML 扩展(如果可用),或者通过使用 JAXB(如果 Jackson XML 扩展不可用)。默认情况下,字符串是用 UTF-8
编码的。
如果需要添加或自定义转换器,可以使用 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 都将添加到转换器列表中。你也可以用同样的方法覆盖默认的转换器。
如果你使用 Jackson 来序列化和反序列化 JSON 数据,你可能想编写自己的 JsonSerializer
和 JsonDeserializer
类。自定义序列化器通常通过模块在 Jackson 中注册,但是 Spring Boot 提供了一个用于替代的 @JsonComponent
注释,这让它更容易注册到 Spring Beans 中。
你可以直接在 JsonSerializer
、JsonDeserializer
或 KeyDeserializer
实现上使用 @JsonComponent
注解。你也可以在包含序列化器/反序列化器作为内部类的类上使用它,如下所示:
import java.io.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import org.springframework.boot.jackson.*;
@JsonComponent
public class Example {
public static class Serializer extends JsonSerializer<SomeObject> {
// ...
}
public static class Deserializer extends JsonDeserializer<SomeObject> {
// ...
}
}
ApplicationContext
中的所有的 @JsonComponent
bean 都自动注册到 Jackson 中。因为 @JsonComponent
是用 @Component
作为元注解的,所以可以进行通常的组件扫描。
Spring Boot 还提供了 JsonObjectSerializer
和 JsonObjectDeserializer
基类,它们在序列化对象时为标准 Jackson 版本提供了有用的替代方法。有关详细信息,参阅 Javadoc 中的 JsonObjectSerializer 和 JsonObjectDeserializer。
Spring MVC 有一个生成错误代码的策略,用于渲染来自绑定的错误的消息: MessageCodesResolver
。如果设置了 spring.mvc.message-codes-resolver-format
属性为 PREFIX_ERROR_CODE
或 POSTFIX_ERROR_CODE
,则 Spring Boot 会为你创建一个(参阅DefaultMessageCodesResolver.Format 中的枚举)。
默认情况下,Spring Boot 服务的静态内容来自类路径下的 /static
(或 /public
或 /resource
或 /META-INF/resource
)目录或 ServletContext
的根路径,它使用来自Spring MVC 的 ResourceHttpRequestHandler
,因此你可以通过添加自己的 WebMvcConfigurer
和重写 addResourceHandlers
方法来修改它的行为。
在一个独立的web应用程序中,容器中的默认servlet也被启用,并充当备用,如果 Spring 决定不处理它,则从 ServletContext 的根目录提供内容。大多数情况下,这种情况不会发生(除非修改默认的 MVC 配置),因为 Spring 总是可以通过DispatcherServlet
处理请求。
默认情况下,资源映射在 /**
,但可以使用 spring.mvc.static-path-pattern
属性对其进行调整。例如,可以将所有资源重新定位到 /resources/**
中,如下所示:
spring.mvc.static-path-pattern=/resources/**
你可以使用 spring.resources.static-locations
自定义静态资源的位置(用目录位置列表替代默认值)。根 Servlet 上下文路径 /
也被自动作为一个位置添加。
如果你的应用是一个 jar 包,不要使用
src/main/webapp
目录。虽然这个目录是一个常用标准,但是它只在 war 包下起作用,如果你创建的是一个 jar 包,那么它在大多数的构建工具下都会被忽略。
Spring Boot 还支持 Spring MVC 提供的高级资源处理功能,允许使用诸如 cache-busting 静态资源或对 Webjars 使用版本不可知的 URL 等。
要对 Webjars 使用版本不可知的 URL,添加 webjars-locator-core
依赖项。然后声明你的 Webjar。以 jQuery 为例,添加 "/webjars/jQuery/jQuery.min.js"
将导致 "/webjars/jQuery/x.y.z/jQuery.min.js"
,其中 x.y.z
是Webjar版本。
如果使用 JBoss,则需要声明
webjar-locator-Jjboss-vfs
依赖项,而不是webjar-locator-core
。否则,所有 Webjars 都会被解析为404
。
要使用 cache busting,以下配置将为所有静态资源配置 cache busting 解决方案,有效地在URL中添加内容哈希,例如 spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
由于
ResourceUrlEncodingFilter
是为 Thymeleaf 和 FreeMarker 自动配置的,所以在运行时可以在模板中重写到资源的链接。在使用 JSP 时,你应该手动声明此过滤器。其他模板引擎目前还不被支持自动配置,但是可以使用自定义模板宏/帮助程序和ResourceUrlProvider
。
当使用比如 JavaScript 模块加载器动态加载资源时,不可以重命名文件。这就是为什么其他策略也受到支持,并且可以结合使用。“fixed” 策略在 URL 中添加一个不改变文件名的静态版本字符串,如下例所示:
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
spring.resources.chain.strategy.fixed.enabled=true
spring.resources.chain.strategy.fixed.paths=/js/lib/
spring.resources.chain.strategy.fixed.version=v12
通过这种配置,"/js/lib/" 下的 JavaScript 模块使用一种固定的版本控制策略(""/v12/js/lib/mymodule.js"),而其他资源仍然使用内容哈希策略(link://css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css“/)。
有关更多支持的选项,参阅 ResourceProperties
。
这个特性在一篇专门的 博文 和 Spring Framework 的参考文档中有详细的描述。
Spring Boot 同时支持静态和模板化欢迎页面。它首先在配置的静态内容位置中查找i index.html
文件。如果没有找到,则查找 index
模板。如果找到其中之一,它将自动用作应用程序的欢迎页面。
与其他静态资源一样,Spring Boot 在配置的静态内容位置中查找 favicon.ico
。如果存在这样的文件,它将自动用作应用程序的图标。
Spring MVC 可以通过查看请求路径并将其与应用程序中定义的映射(例如,控制器方法上的 @GetMapping
注解)匹配,将传入的 HTTP 请求映射到处理程序。
Spring Boot 默认选择禁用后缀模式匹配,这意味着 "GET/projects/Spring Boot.json"
之类的请求将不会与 @GetMapping("/projects/Spring Boot")
映射匹配。这被认为是 Spring MVC 应用程序的最佳实践。这个特性在过去对于没有发送正确的 “Accept” 请求头的 HTTP 客户端非常有用;我们需要确保向客户端发送正确的内容类型。如今,内容协商机制更加可靠。
还有其他方法来处理HTTP客户端,它们不会一致地发送适当的 “Accept” 请求头的 HTTP 客户端。我们应该使用查询参数而不是后缀匹配来确保像 "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
Spring MVC 使用 WebBindingInitializer
来为特定的请求初始化 WebDataBinder
。如果你创建了自己的 ConfigurableWebBindingInitializer
@Bean
, Spring Boot 会自动配置 Spring MVC 来使用它。
与 REST web 服务一样,你也可以使用 Spring MVC 来提供动态 HTML 内容。Spring MVC 支持各种模板技术,包括T hymeleaf、FreeMarker 和 JSP。此外,许多其他模板引擎也包含自己的Spring MVC集成。
Spring Boot 包含对下列模板引擎的自动配置支持:
如果可能,应该避免使用 JSP。它在与嵌入式 servlet 容器一起使用时,有几个已知的限制。
当你使用这些带有默认配置的模板引擎时,你的模板将自动从 src/main/resources/templates
中获取。
根据应用程序的运行方式,IntelliJ IDEA 对类路径的顺序不同。在 IDE 中从主方法运行应用程序的顺序与使用 Maven 或 Gradle 或其打包的 jar 运行应用程序的顺序不同。这可能会导致 Spring Boot 无法在类路径上找到模板。如果遇到此问题,可以在 IDE 中重新排序类路径,以将模块的类和资源放在第一位。或者,你可以将模板前缀配置为搜索类路径上的每个
templates
目录,如下所示:classpath*:/templates/
。
默认情况下,Spring Boot 提供了一个 /error
映射,它以合理的方式处理所有错误,并在 servlet 容器中将其注册为 “global” 错误页。对于机器客户端,它生成一个 JSON 响应,其中包含错误、HTTP 状态和异常消息的详细信息。对于浏览器客户端,有一个 “whitelabel” 错误视图,它以 HTML 格式呈现相同的数据(要自定义它,添加一个解析为 error
的 View
)。要完全替换默认行为,可以实现 ErrorController
并注册该类型的 bean 定义,或者添加 ErrorAttributes
类型的 bean 来使用现有机制,仅仅替换内容。
BasicErrorController
可以用作自定义ErrorController
的基类。如果你想为新的内容类型添加一个处理程序(默认情况下是专门处理text/html
并为其他所有内容提供一个后备处理程序),那么这一点特别有用。为此,扩展BasicErrorController
,添加一个带有@RequestMapping
的公共方法,该方法具有一个produces
属性,并创建一个新类型的 bean。
还可以定义一个带 @ControllerAdvice
注解的类,来自定义J SON 文档,使其返回特定的控制器和/或异常类型,如下面的示例所示:
@ControllerAdvice(basePackageClasses = AcmeController.class)
public class AcmeControllerAdvice extends ResponseEntityExceptionHandler {
@ExceptionHandler(YourException.class)
@ResponseBody
ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {
HttpStatus status = getStatus(request);
return new ResponseEntity<>(new CustomErrorType(status.value(), ex.getMessage()), status);
}
private HttpStatus getStatus(HttpServletRequest request) {
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
if (statusCode == null) {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
return HttpStatus.valueOf(statusCode);
}
}
在前面的示例中,如果与 AcmeController
在同一个包中定义的控制器抛出了 YourException
,则使用 CustomErrorType
POJO 的 JSON 表示,而不是 ErrorAttributes
表示。
如果你想要显示给定状态代码的自定义 HTML 错误页,你可以将文件添加到 /error
文件夹。错误页面可以是静态 HTML(即添加到任何静态资源文件夹下),也可以使用模板构建。文件的名称应该是确切的状态码或系列掩码。
例如,要将 404
映射到静态 HTML 文件,你的文件夹结构如下:
src/
+- main/
+- java/
| +
要使用 FreeMarker 模板来映射所有 5xx
的错误,你的文件夹结构如下:
src/
+- main/
+- java/
| +
对于更复杂的映射,你可以通过添加实现 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
方法和 @ControllerAdvice
https://docs.spring.io/spring/docs/5.2.6.RELEASE/spring-framework-reference/web.html#mvc-ann-controller-advice。然后 ErrorController
获取其它未处理的异常。
对于不使用 Spring MVC 的应用,可以使用 ErrorPageRegistrar
接口直接注册错误页面。这个抽象可以直接与底层的嵌入的 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"));
}
}
如果你注册了一个
ErrorPage
,其路径最终由一个过滤器处理(这在一些非 Spring web 框架中很常见,如 Jersey 和 Wicket),那么过滤器必须显式地注册为一个ERROR
调度程序,如下面的示例所示:@Bean public FilterRegistrationBean myFilter() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new MyFilter()); ... registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class)); return registration; }
注意,默认的 FilterRegistrationBean
不包括 ERROR
调度程序类型。
注意:当部署到 servlet 容器时,Spring Boot 使用其错误页过滤器将带有错误状态的请求转发到适当的错误页。如果尚未提交响应,则只能将请求转发到正确的错误页面。默认情况下,WebSphere Application Server 8.0 及以后在成功完成 servlet 的服务方法后提交响应。你应该通过设置 com.ibm.ws.webcontainer.invokeFlushAfterService=false
来禁用此行为。
如果你开发了一个使用超媒体的 RESTful API,那么 Spring Boot 为 Spring HATEOAS 提供了自动配置,它可以很好地与大多数应用一起工作。自动配置取代了使用 @EnableHypermediaSupport
的需要,并注册了许多 bean 来简化基于超媒体应用的构建,包括一个 LinkDiscoverers
(用于客户端支持)和一个 ObjectMapper
,它们被配置为将响应正确地封送到所需的表示中。ObjectMapper
是通过设置各种 spring.jackson.*
属性来定制的,或者可以通过 Jackson2ObjectMapperBuilder
bean来定制。
你可以使用 @EnableHypermediaSupport
来控制 Spring HATEOAS 的配置。注意,这样做会禁用前面描述的 ObjectMapper
自定义。
跨源资源共享(Cross-origin resource sharing, CORS)是一个由大多数浏览器实现的 W3C规范,它允许你以灵活的方式指定授权的跨域请求的类型。,而不是使用一些不那么安全、不那么强大的方法,如 IFRAME 或 JSONP。
从4.2版开始,Spring MVC 就支持 CORS。在 Spring Boot 应用程序中使用带有 @CrossOrigin
注解的控制器方法 CORS 不需要任何特定的配置。可以通过使用定制的addcorsm(CorsRegistry)
方法注册 WebMvcConfigurer
bean 来定义全局 CORS 配置,如下所示:
@Configuration(proxyBeanMethods = false)
public class MyConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**");
}
};
}
}
Spring WebFlux是 在 Spring framework 5.0 中引入的新的响应式性 web 框架。与 Spring MVC 不同的是,它不需要 Servlet API,完全异步且非阻塞,并通过 Reactor 实现响应式流规范。
Spring WebFlux 有两种风格:函数式和基于注解的。基于注解的模式非常接近于 Spring MVC 模式,如下例所示:
@RestController
@RequestMapping("/users")
public class MyRestController {
@GetMapping("/{user}")
public Mono<User> getUser(@PathVariable Long user) {
// ...
}
@GetMapping("/{user}/customers")
public Flux<Customer> getUserCustomers(@PathVariable Long user) {
// ...
}
@DeleteMapping("/{user}")
public Mono<User> deleteUser(@PathVariable Long user) {
// ...
}
}
“WebFlux.fn” 是函数变量,它将路由配置从实际的请求处理中分离出来,如下面的例子所示:
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 框架的一部分,详细的信息可以在它的参考文档中找到。
你可以定义任意多的
RouterFunction
bean来模块化路由器的定义。如果需要进行优先级设置,可以对 bean 进行排序。
在你的应用中添加 spring-boot-starter-webflux
模型就可以开始了。
应用程序中同时添加
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 为 Spring WebFlux 提供了自动配置,它可以很好地与大多数应用程序一起工作。
自动配置在 Spring 默认设置的基础上添加了以下功能:
为 HttpMessageReader
和 HttpMessageWriter
实例配置编解码器。
对服务静态资源的支持,包括对 WebJars 的支持。
如果你想保留 Spring Boot WebFlux 特性,并且想添加额外的 WebFlux 配置,那么可以添加自己的 @Configuration
类,类型为 WebFluxConfigurer
,但不需要 @EnableWebFlux
。
如果你想完全控制 Spring WebFlux,可以添加自己的 @Configuration
,并用 @EnableWebFlux
注释。
Spring WebFlux 使用 HttpMessageReader
和 HttpMessageWriter
接口来转换 HTTP 请求和响应。它们是用 CodecConfigurer
配置的,通过查看类路径中可用的库来获得合理的默认值。
Spring Boot为编解码器 Spring.codec.*
提供专用配置属性。它还通过使用 CodecCustomizer
实例应用进一步的自定义。例如,spring.jackson.*
配置键应用于 Jackson 编解码器。
如果需要添加或自定义编解码器,可以创建自定义编解码器自定义程序组件,如下例所示:
import org.springframework.boot.web.codec.CodecCustomizer;
@Configuration(proxyBeanMethods = false)
public class MyConfiguration {
@Bean
public CodecCustomizer myCodecCustomizer() {
return codecConfigurer -> {
// ...
};
}
}
你还可以定制 JSON 序列化器和反序列化器。
和 REST web 服务一样,你可以使用 Spring WebFlux 来提供动态 HTML 内容。Spring WebFlux 支持多种模板技术,包括 Thymeleaf、FreeMarker 和 Mustache。
Spring Boot 包含对下列模板引擎的自动配置支持:
当你使用这些带有默认配置的模板引擎时,你的模板将自动从 src/main/resources/templates
中获取。
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 文件,你的文件夹结构如下:
src/
+- main/
+- java/
| +
要使用 Mustache 模板来映射所有 5xx
错误,你的文件夹结构应该如下:
src/
+- main/
+- java/
| +
Spring WebFlux提供了一个 WebFilter
接口,可以实现这个接口来过滤 HTTP request-response 交换。在应用程序上下文中找到的 WebFilter
bean将自动用于过滤每个交换。
如果要指定过滤器的顺序,它们可以实现 Ordered
或使用 @Order
注解。Spring Boot 自动配置可以为你配置 we b过滤器。当它这样做时,将使用下表所示的顺序:
Web Filter | Order |
---|---|
MetricsWebFilter |
Ordered.HIGHEST_PRECEDENCE + 1 |
WebFilterChainProxy (Spring Security) |
-100 |
HttpTraceWebFilter |
Ordered.LOWEST_PRECEDENCE - 10 |
如果您更喜欢 REST 类型的 JAX-RS 编程模型,那么可以使用其中一个可用的实现,而不是 Spring MVC。Jersey 和 Apache CXF 在开箱即用的情况下工作得很好。CXF 要求你在应用程序上下文中将其 Servlet
或 Filter
注册为 @Bean
。Jersey有 一些本地的 Spring 支持,因此也在 Spring Boot 中为它提供自动配置支持,同时还提供了一个 starter。
要开始使用J ersey,将 spring-boot-starter-jersey
作为依赖项,然后需要一个 ResourceConfig
类型的 @Bean
,在其中注册所有端点,如下例所示:
@Component
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(Endpoint.class);
}
}
Jersey 对扫描可执行文件的支持相当有限。例如,当运行可执行 war 文件时,它无法扫描完全可执行 jar 文件或
WEB-INF/classes
中的包中的端点。为了避免这种限制,不应该使用packages
方法,而应该使用register
方法单独注册端点,如前一个示例所示。
对于更高级的定制,你还可以注册任意数量的 ResourceConfigCustomizer
实现类的 bean。
所有注册的端点都应该是带有 HTTP 资源注解的 @Components
(@GET
等)。如下例所示:
@Component
@Path("/hello")
public class Endpoint {
@GET
public String message() {
return "Hello";
}
}
Spring Boot 包含对嵌入式T omcat、Jetty 和 Undertow 服务器的支持。大多数开发人员使用对应的 “Starter” 来获得完全配置的实例。默认情况下,嵌入式服务器监听端口 8080 上的 HTTP 请求。
当使用嵌入式 servlet 容器时,你可以注册 servlet 规范中的 servlet、filter 和所有 listener(如 HttpSessionListener
),方法是使用 Spring bean或扫描 Servlet 组件。
任何作为 Spring bean 的 Servlet
、Filter
或 servlet *Listener
实例都会注册到嵌入式容器中。如果要在配置过程中引用 application.properties
中的值,这会特别方便。
默认情况下,如果上下文只包含一个Servlet,则将其映射到 /
。在多个 servlet bean的情况下,bean 名称用作路径前缀。过滤器映射到 /*
。
如果基于约定(convention-based)的映射不够灵活,则可以使用 ServletRegistrationBean
、FilterRegistrationBean
和 ServletListenerRegistrationBean
类进行完全控制。
通常情况下,无序的 Filter bean 是安全的。如果需要特定的顺序,则应使用 @Order
注解 Filter
,或使其实现 Ordered
。不能通过用 @Order
注解的 bean 方法来配置 Filter
的顺序。如果不能将 Filter
类添加 @Order
或实现 Ordered
,则必须为 Filter
定义 FilterRegistration
bean,并使用 setOrder(int)
方法设置注册 bean 的顺序。避免配置以 Ordered.HIGHEST_PRECEDENCE
读取请求正文的 Filter
,因为它可能违反应用程序的字符编码配置。如果Servlet过滤器包装了请求,则应使用小于或等于 OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER
的顺序对其进行配置。
要查看应用程序中每个
Filter
的顺序,可为 web 日志记录组启用调试级别日志记录(logging.level.web=debug
)。注册过滤器的详细信息,包括它们的顺序和 URL 模式,将在启动时记录下来。
注册
Filter
bean时要小心,因为它们在应用程序生命周期的早期就被初始化了。如果需要注册与其他 bean 交互的过滤器,请考虑改用DelegatingFilterProxyRegistrationBean
。
嵌入式 servlet 容器不会直接执行 Servlet3.0+ javax.servlet.ServletContainerInitializer
接口或Spring的 org.springframework.web.WebApplicationInitializer
接口。这是一个有意的设计决策,旨在降低设计用于在 war 中运行的第三方库可能会破坏 Spring 引导应用程序的风险。
如果需要在 Spring Boot 应用程序中执行 servlet上 下文初始化,则应注册实现 org.springframework.Boot.web.servlet.ServletContextInitializer
接口的 bean。 onStartup
方法提供对 ServletContext
的访问,如果需要,可以很容易地用作现有 WebApplicationInitializer
的适配器。
使用嵌入式容器时,可以使用 @ServletComponentScan
启用对 @WebServlet
、@WebFilter
和 @WebListener
注解的类的自动注册。
ServletComponentScan
在单个独立的容器中不起作用,因为它使用了容器内置的发现机制。可查看 https://blog.csdn.net/vipzyj/article/details/105622524
在底层,Spring Boot 使用不同类型的 ApplicationContext
来支持嵌入式 servlet 容器。ServletWebServerApplicationContext
是一种特殊类型的 WebApplicationContext
,它通过搜索单个 ServletWebServerFactory
bean来引导自己。通常,TomcatServletWebServerFactory
、JettyServletWebServerFactory
或UndertowServletWebServerFactory
都是自动配置的。
你通常不需要知道这些实现类。大多数应用程序都是自动配置的,会为你配置合适的
ApplicationContext
和ServletWebServerFactory
。
通用的servlet容器设置可以使用 Spring Environment
属性配置。通常,你可以在 application.properties
文件中定义属性。
常用服务器设置包括:
网络设置:接收HTTP请求的侦听端口(server.port
)、要绑定到的 server.address
接口地址,等等。
会话设置:会话是否持久(server.servlet.Session.persistent
)、会话超时(server.servlet.Session.timeout
)、会话数据位置(server.servlet.Session.store dir
)和会话 cookie 配置(server.servlet.Session.cookie.*
)。
错误管理:错误页的位置(server.Error.path
)等。
SSL
HTTP compression
Spring Boot 尽可能多地暴露公开的常用设置,但这不是万全之策。对于这些情况,专用名称空间提供了 server-specific 定制服务(查看 server.tomcat
和 server.undertow
)。例如,可以使用嵌入式 servlet 容器的特定特性来配置访问日志。
查看
ServerProperties
获取完整数据。
如果你需要以编程式的方法配置嵌入式 servlet 容器,可以注册实现 WebServerFactoryCustomizer
接口的 Spring bean。WebServerFactoryCustomizer
提供对 ConfigurableServletWebServerFactory
的访问,其中包括许多自定义的 setter 方法。以下示例展示了以编程式设置端口:
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);
}
}
TomcatServletWebServerFactory
、JettyServletWebServerFactory
和UndertowServletWebServerFactory
是ConfigurableServletWebServerFactory
的变体,它们分别为 Tomcat、Jetty 和 Undertow 提供了额外定制的 setter 方法。
如果认为前面的定制技术存在限制,你可以自己注册 TomcatServletWebServerFactory
、 JettyServletWebServerFactory
或 UndertowServletWebServerFactory
bean:
@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。如果你需要做一些更特别的事情,还提供了一些受保护的钩子函数。有关详细信息,参阅 源代码文档。
当使用嵌入式 servlet 容器(打包为可执行归档文件)的 Sprin Boot 应用程序时,JSP 支持会受到一些限制。
可以使用 war 打包 Jetty 和 Tomcat。一个可执行的 war 在用 java -jar
启动时可以工作,并且可以部署到任何标准容器。但使用可执行 jar 时不支持 JSP。
Undertow 不支持 JSP。
创建自定义 error.jsp
页面不会覆盖错误处理的默认视图,应改用自定义错误页。
Spring Boot 包括对以下嵌入式响应式 web 服务器的支持:Reactor Netty、Tomcat、Jetty 和 Undertow。大多数开发人员使用适当的 “Starter” 来获得完整配置的实例。默认情况下,嵌入式服务器侦听端口 8080 上的 HTTP 请求。
当自动配置 Reactor Netty 或 Jetty 服务器时,Spring Boot 将创建特定的bean,为服务器实例提供 HTTP 资源:ReactorResourceFactory
或 JettyResourceFactory
。
默认情况下,这些资源还将与Reactor Netty 和 Jetty 客户端共享,以获得最佳性能,前提是:
服务器和客户端使用相同的技术
客户机实例是使用由 Spring Boot 自动配置的 WebClient.Builder
bean构建的
开发人员可以通过提供自定义的 ReactorResourceFactory
或 JettyResourceFactory
bean来覆盖 Jetty 和 Reactor Netty 的资源配置——这将应用于客户端和服务器。
你可以在 WebClient 运行时部分中了解有关客户端资源配置的更多信息。
RSocket 是一种用于比特流传输的二进制协议,它通过在单个连接上异步传输消息来开启对称的交互模型。
Spring Framework 提供了 spring-messaging
模型用于支持 RSocket 服务端和客户端的请求和响应,有关更多细节(包括RSocket协议的概述),参见 Spring 框架参考的 RSocket部分。
Spring Boot 会自动配置一个 RSocketStrategies
bean,它提供了编码和解码 RSocket 有效负载所需的所有基础设置。默认情况下,自动配置将尝试配置以下(按照顺序):
Jackson 的 CBOR 编解码器
Jackson 的 JSON 编解码器
spring-boot-starter-rsocket
提供了所有依赖,可以查看 Jackson 支持部分了解更多的可用于自定义的组件。
开发人员可以通过创建实现 RSocketStrategies customizer
接口的 bean 来定制 RSocketStrategies
组件。注意它们的 @Order
很重要,因为它决定了编解码器的顺序。
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
只有 Reactor Netty 支持将 RSocket 插入web服务器,,因为 RSocket 本身就是用这个库构建的。
此外,RSocket TCP 或 websocket 服务可以作为独立的嵌入式服务器启动。除了依赖需求,唯一需要的配置是为该服务器定义一个端口:
spring.rsocket.server.port=9898 # the only required configuration
spring.rsocket.server.transport=tcp # you're free to configure other properties
Spring Boot将为 RSocket 自动配置 Spring Messaging 基础组件。
这意味着 Spring Boot 将创建一个 RSocketMessageHandler
bean,用于处理对应用程序的 RSocket 请求。
RSocketRequester
一旦在服务器和客户端之间建立了 RSocket 通道,任何一方都可以向另一方发送或接收请求。
作为服务器,可以在 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 在类路径上,那么 web 应用程序在默认情况下是安全的。Spring Boot 依赖于 Spring Security 的内容协商策略来决定是使用 httpBasic
还是 formLogin
。要向 web 应用程序添加方法级的安全性,还可以使用所需的设置添加 @EnableGlobalMethodSecurity
。其他信息可以在 Spring Security 参考指南 中找到。
UserDetailsService
默认只有一个用户。用户名是 user
,密码是随机的,并且会在应用程序启动时在 INFO 级别打印,如下例所示:
Using generated security password: 78fa095d-3f4c-48b1-ad50-e24c31d5cf35
如果你对日志配置进行了调整,要确保
org.springframework.boot.autoconfigure
的类别设置为 INFO 级别日志。否则,将不会打印默认的随机密码。
你可以通过提供 spring.security.user.name
和 spring.security.user.password
来更改用户名和密码。
默认情况下,web 应用程序中的基本功能包括:
一个具有内存存储的 UserDetailsService
(或者在 WebFlux 应用程序的情况下是 ReactiveUserDetailsService
)bean和一个具有生成的密码的用户(有关用户的属性,参阅 SecurityProperties.User
)。
整个应用程序都基于表单的登录或 HTTP Basic 安全性(取决于请求中的 Accept
头)(如果执行器位于类路径上,则包括执行器端点)。
用于发布身份验证事件的 DefaultAuthenticationEventPublisher
。
你可以通过添加 bean 来提供不同的 AuthenticationEventPublisher
。
默认的安全配置在 SecurityAutoConfiguration
和 UserDetailsServiceAutoConfiguration
中实现。SecurityAutoConfiguration
导入 SpringBootWebSecurityConfiguration
用于 web 安全和 UserDetailsServiceAutoConfiguration
用于配置身份验证,这在非 web 应用程序中也是差不多的。要完全关闭默认的 web 应用程序安全配置或组合多个Spring Security 组件(如 OAuth2 客户端和资源服务器),要添加 WebSecurityConfigurerAdapter
类型的 bean(这样做并不会禁用 UserDetailsService
配置或执行器的安全性)。
要同时关闭 UserDetailsService
配置,可以添加 UserDetailsService
、AuthenticationProvider
或 AuthenticationManager
类型的 bean。
访问规则可以通过添加自定义 WebSecurity
配置适配器来重写。Spring Boot 提供了一些方便的方法,可以用来覆盖执行器端点和静态资源的访问规则。EndpointRequest
可用于创建基于 management.endpoints.web.base-path
属性的 RequestMatcher
。PathRequest
可用于为常用位置的资源创建 RequestMatcher
。
与 Spring MVC 应用程序类似,可以通过添加 spring-boot-starter-security
依赖项来保护 WebFlux 应用程序。默认的安全配置在 ReactiveSecurityAutoConfiguration
和 UserDetailsServiceAutoConfiguration
中实现。ReactiveSecurityAutoConfiguration
导入 WebFluxSecurityConfiguration
用于 web 安全和 UserDetailsServiceAutoConfiguration
用于配置身份验证,这在非web应用程序中也是差不多的。要完全关闭默认的 we b应用程序安全配置,可以添加 WebFilterChainProxy
类型的 bean(这样做不会禁用 UserDetailsService
配置或执行器的安全性)。
要同时关闭 UserDetailsService
配置,可以添加 ReactiveUserDetailsService
或ReactiveAuthenticationManager
类型的bean。
访问规则多个 Spring Security 组件(如 OAuth2 客户端和资源服务器)的使用可以通过添加自定义 SecurityWebFilterChain
bean 进行配置。Spring Boot 提供了一些方便的方法,可以用来覆盖执行器端点和静态资源的访问规则。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();
}
OAuth2 是一个 Spring 支持的,被广泛用于用户验证的框架。
如果类路径上有 spring-security-oauth2-client
,那么可以利用一些自动配置来轻松地设置 OAuth2/Open ID Connect 客户端。这个配置使用了 OAuth2ClientProperties
下的属性。servlet 和响应式应用都是使用相同的属性。
你可以在 spring.security.oauth2
前缀下注册多个 OAuth2 客户端和服务端,如下例所示:
pring.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 发现机制 的OpenID Connect 提供者,可以进一步简化配置。提供者需要配置一个 issuer-uri
,该 URI 是它断言为其发布方的标识符。例如,如果提供 issuer-uri
是 “https://example.com”,那么将向 “https://example.com/.well-known/OpenID-Configuration” 发送 OpenID Provider Configuration Request
。结果应该是获得一个 OpenID Provider Configuration Response
。以下示例显示如何使用 issuer-uri
配置 OpenID Connector 提供者:
spring.security.oauth2.client.provider.oidc-provider.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/
默认情况下,Spring Security 的 OAuth2LoginAuthenticationFilter
只处理匹配 /login/oauth2/code/*
的 URL。如果要自定义重定向 URI 以使用不同的模式,则需要提供配置来处理该自定义模式。例如,对于 servlet 应用程序,可以添加自己的 WebSecurity
配置适配器,类似于以下内容:
public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login()
.redirectionEndpoint()
.baseUri("/custom-callback");
}
}
对于常见的 OAuth2 和 OpenID 提供者,包括 Google、Github、Facebook 和 Okta,Spring Boot 提供了一组提供者的缺省值(分别为 google
、github
、facebook
和 okta
)。
如果你不需要自定义这些提供这,你可以将提供者属性设置为你所需要的推断默认值的属性。此外,如果客户端注册的键与默认的受支持的提供程序匹配,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-resource-server
, Spring Boot 可以设置一个 OAuth2 资源服务器。对于 JWT 配置,需要指定 JWK Set URI 或 OIDC Issuer URI,如下例所示:
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://example.com/oauth2/default/v1/keys
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/
如果授权服务器不支持 JWK Set URI,则可以使用用于验证 JWT 签名的公钥配置资源服务器。此可以使用
spring.security.oauth2.resourceserver.jwt.public-key-location
属性完成,其中的值需要指向包含 PEM-encoded x509 格式的公钥的文件。
相同的属性适用于 servlet 和响应式应用程序。
或者,你可以为 servlet 应用程序定义自己的 JwtDecoder
bean,或者为响应式应用程序定义 ReactiveJwtDecoder
。
在使用不透明令牌而不是 JWTs 的情况下,你可以配置以下属性来通过自省来验证令牌:
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 应用程序定义你自己的 OpaquekenIntrospector
bean,或者为响应式应用程序定义一个 ReactiveOpaqueTokenIntrospector
。
目前,Spring Security 不支持实现 OAuth2.0 授权服务器。但是,这个功能可以从 Spring Security OAuth 项目获得,Spring Security 最终将完全取代这个项目。在此之前,你可以使用 spring-security-oauth2-autoconfigure
模块轻松设置 OAuth2.0 授权服务器,有关说明,参阅其文档。
如果类路径上有 spring-security-saml2-service-provider
,那么你可以利用一些自动配置来轻松地设置 SAML2.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
出于安全考虑,默认情况下,除 /health
和 /info
之外的所有执行器都是禁用的。可以使用 management.endpoints.web.exposure.include
属性启用执行器。
如果 Spring Security 在类路径上,并且不存在其他 WebSecurityConfigurerAdapter
,那么除了 /health
和 /info
之外的所有执行器都由 Spring 引导自动配置保护。如果你定义了一个自定义 WebSecurityConfigurerAdapter
,Spring Boot 自动配置机制将会停止,你将完全控制执行器的访问规则。
设置
management.endpoints.web.exposure
之前。确保暴露的执行器不包含敏感信息 和/或 通过将它们放置在防火墙后或通过类似 Spring Security 的东西来保护它们。
因为 Spring Boot 依赖于 Spring Security 的默认值,所以 CSRF 保护在默认情况下是打开的。这意味着,当使用默认安全配置时,执行器端点进行 POST
(关闭和日志记录器端点)、PUT
或 DELETE
将得返回 403。
建议只在创建非浏览器客户端使用的服务时才完全禁用 CSRF 保护。
有关 CSRF 保护的其他信息可以在 Spring Security 参考指南中找到。
Spring Framework 为使用 SQL 数据库提供了广泛的支持,从使用 JdbcTemplate
的直接 JDBC 访问到完成 “对象关系映射(object relational mapping)” 技术,如 Hibernate。Spring Data 提供了附加的功能:直接从接口创建 Repository
实现,并遵循约定从方法名生成查询。
Java的 javax.sql.DataSource
接口提供了处理数据库连接的标准方法。传统上,“DataSource” 使用一个 URL
和一些凭证来建立数据库连接。
查看 “How-to” 一节获取更多高级的例子,尤其是如何完全靠自己数据源的配置。
使用内存中的嵌入式数据库开发应用程序通常很方便。当然,内存数据库不提供持久存储。你需要在应用程序启动时填充数据库,并准备在应用程序结束时丢弃数据。
“How-to” 一节中包含了 如何初始化数据库。
Spring Boot 可以自动配置嵌入的 H2、HSQL 和 Derby 数据库。你不需要提供任何连接 URL。只需要包含对要使用的嵌入式数据库的构建依赖项。
如果你在测试中使用这个特性,你可能会注意到,无论你使用多少应用程序上下文,整个测试套件都会重用相同的数据库。如果你想确保每个上下文都有一个单独的嵌入式数据库,你应该设置
spring.datasource.generate-unique-name
为 true。
例如,典型的 POM 依赖关系如下:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-jpaartifactId>
dependency>
<dependency>
<groupId>org.hsqldbgroupId>
<artifactId>hsqldbartifactId>
<scope>runtimescope>
dependency>
要自动配置嵌入式数据库,需要依赖
spring-jdbc
。在本例中,它是通过spring-boot-starter-data-jpa
间接拉入的。
如果出于任何原因,你为嵌入式数据库配置了连接 URL,要注意确保数据库的自动关闭被禁用。如果使用 H2,则应使用
DB_CLOSE_ON_EXIT=FALSE
来执行此操作。如果使用HSQLDB,则应确保不使用shutdown=true
。禁用数据库的自动关闭让 Spring Boot控制它的关闭,从而确保在在需要访问数据库时再次开启。
可以使用池数据源自动配置产生的数据库连接。Spring Boot使用以下算法选择特定的实现:
我们更喜欢 {HikariCP](https://github.com/brettwooldridge/HikariCP) 的性能和并发性。如果 HikariCP 可用,我们总是选择它。
否则,如果 Tomcat 池数据源可用,我们就使用它。
如果 HikariCP 和 Tomcat 池数据源都不可用,并且 Commons DBCP2 可用,则使用它。
如果使用 spring-boot-starter-jdbc
或 spring -boot-starter-data-jpa
“starters”,则会自动获取对 HikariCP 的依赖。
你可以绕过该算法,通过设置
spring.datasource
指定要使用的连接池。如果在 Tomcat 容器中运行应用程序,这一点尤其重要,因为默认情况下它提供了tomcat -jdbc
。
其他连接池始终可以手动配置。如果定义了自己的
DataSource
bean,则不会进行自动配置。
数据源配置由 spring.datasource.*
中的外部配置属性控制。例如,你可以在 application.properties
中声明以下部分:
spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
如果你不设置
spring.datasource-url
属性,Spring Boot 就会尝试自动配置内嵌数据库。
通常不需要指定
driver-class-name
,因为 Spring Boot 可以从url
推断大多数数据库的驱动程序类名。
为了创建一个
DataSource
,需要能够验证一个有效的驱动程序类是可用的,所以我们在进行数据库操作之前都要检查它。换句话说,如果设置spring.datasource.driver class name=com.mysql.jdbc.driver
,那么该类必须是可加载的。
参阅 DataSourceProperties 查看更多支持的选项,无论实际实现如何,这些都是标准的选项。还可以使用它们各自的前缀(spring.datasource.hikari.*
、spring.datasource.tomcat.*
和 spring.datasource.dbcp2.*
)调整特定于实现的设置。
例如,如果使用 Tomcat连接池,可以自定义许多其他设置,如下例所示:
# 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
如果将 Spring Boot 应用程序部署到应用程序服务器,则可能需要使用应用程序服务器的内置功能配置和管理数据源,并使用 JNDI 访问它。
spring.datasource.jndi-name
属性可以用作 spring.datasource.url
、spring.datasource.username
和 spring.datasource.password
属性的替代项,以从特定 JNDI 位置访问数据源。例如,application.properties
中的以下部分展示了如何访问JBoss 定义的 DataSource
:
spring.datasource.jndi-name=java:jboss/datasources/customers
Spring 的 JdbcTemplate
和 NamedParameterJdbcTemplate
类是自动配置的,你可以用 @Autowire
直接将它们放到你自己的 bean 中,如下例所示:
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.*
属性自定义模板的一些属性,如下例所示:
spring.jdbc.template.max-rows=500
在后台,
NamedParameterJdbcTemplate
重用相同的JdbcTemplate
实例。如果定义了多个JdbcTemplate
且不存在主候选项,则不会自动配置NamedParameterJdbcTemplate
。
Java 持久化 API是一种标准的技术,允许将对象映射到关系数据库。spring-boot-starter-data-jpa
POM 提供了一种快速启动方法。它提供了以下关键依赖:
Hibernate:最流行的JPA实现之一。
Spring Data JPA:使实现基于JPA的存储库变得很容易。
Spring ORM:来自Spring框架的核心 ORM 支持。
不会在这里讨论太多 JPA 或 Spring Data 的细节。你可以遵循 Spring 的使用 JPA 访问数据指南,spring.io 和阅读 Spring Data JPA 和 Hibernate 参考文档。
传统上,JPA 实体类是在 persistence.xml
文件中指定的。对于 Spring Boot,不需要这个文件,而是使用实体扫描。默认情况下,将搜索主配置类(用 @EnableAutoConfiguration
或 @SpringBootsApplication
注解包)下面所有的包。
任何用 @Entity
、@Embeddable
或 @MappedSuperclass
注释的类都将被考虑进去。典型的实体类类似于以下示例:
package com.example.myapp.domain;
import java.io.Serializable;
import javax.persistence.*;
@Entity
public class City implements Serializable {
@Id
@GeneratedValue
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String state;
// ... additional members, often include @OneToMany mappings
protected City() {
// no-args constructor required by JPA spec
// this one is protected since it shouldn't be used directly
}
public City(String name, String state) {
this.name = name;
this.state = state;
}
public String getName() {
return this.name;
}
public String getState() {
return this.state;
}
// ... etc
}
可以使用
@EntityScan
注解自定义实体扫描位置。具体可查看 “howto.html” 指南。
Spring Data JPA 存储库是你可以定义来访问数据的接口。JPA 查询是根据你的方法名自动创建的。例如,CityRepository
接口可以声明一个 findAllByState(String state)
方法来查找给定状态下的所有城市。
对于更复杂的查询,可以使用 Spring Data 的 Quer
注解来标注你的方法。
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 存储库支持三种不同的引导模式:默认、延迟和懒加载。要启用延迟或懒加载,要将 spring.data.jpa.repositories.bootstrap-mode
属性设置为 deferred
或 lazy
。使用延迟或懒加载时,自动配置的 EntityManagerFactoryBuilder
将使用上下文的 AsyncTaskExecutor
(如果有)作为引导执行器。如果存在多个,则将使用名为 applicationTaskExecutor
的。
以上仅仅触及了 Spring Data JPA 的皮毛。有关完整的详细信息,参阅 Spring Data JPA参考文档。
默认情况下,只有在使用嵌入式数据库(H2、HSQL 或 Derby)时,才会自动创建 JPA 数据库。你可以使用 spring.jpa.*
属性显式地配置 JPA 设置。例如,要创建和删除表,可以将以下行添加到 application.properties
:
spring.jpa.hibernate.ddl-auto=create-drop
Hibernate 自己的内部属性名是
hibernate.hbm2ddl.auto
。你可以使用spring.jpa.properties.*
(在将前缀添加到实体管理器之前去掉前缀)将其与其他 Hibernate 本机属性一起设置。下一行显示了为 Hibernate 设置 JPA 属性的示例:
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
上例中将 hibernate.globally_quoted_identifiers
属性的值 true 传递给 hibernate 实体管理器。
默认情况下,DDL执行(或验证)将延迟到 ApplicationContext
启动。还有一个 spring.jpa.generate-ddl
标志,但如果 Hibernate 自动配置处于启动状态,则不使用该标志,因为 DDL 的自动设置更细粒度。
如果你在运行一个 web 应用程序,Spring Boot 默认情况下会注册 OpenEntityManagerInViewInterceptor
来使用 “Open EntityManager in View” 模式,以允许在 web 视图中延迟加载。如果不需要此行为,则应在 application.properties
中将 spring.jpa.open-in-view
设置为 false
。
Spring Data 包括对 JDBC 的存储库支持,并将自动为 CrudRepository
上的方法生成 SQL。对于更高级的查询,将提供 @Query
注解。
当必要的依赖项在类路径上时,Spring Boot 将自动配置 Spring Data 的 JDBC 存储库。它们可以通过对 spring-boot-starter-data-jdbc
的单一依赖性添加到你的项目中。如有必要,你可以通过向应用程序添加 @EnableJdbcRepositories
注解或 JdbcConfiguration
子类来控制 Spring Data JDBC 的配置。
查看文档获取 Spring Data JDBC 的详细信息。
H2 dataset提供了一个基于浏览器的控制台,Spring Boot可以为您自动配置。当满足以下条件时,控制台自动配置:
正在开发的基于 servlet 的 web 应用程序。
在类路径上的 com.h2database:h2
。
正在使用的 Spring Boot 开发人员工具。
如果你没有使用 Spring Boot 开发工具,仍然向使用 H2 控制台,那么可以将
spring.h2.console.enabled
属性设置为true
。
H2 控制台只在开发过程中使用,所以你要注意在生产环境中不要把
spring.h2.console.enabled
设置为true
。
默认情况下,控制台的路径是在 /h2-console
,你可以使用 spring.h2.console.path
自定义控制台路径。
面向对象查询(JOOQ Object Oriented Querying,,jOOQ)是 Data Geekery 的一个流行产品,它从数据库生成 Java 代码,并允许你通过它的流式 API 构建类型安全的 SQL 查询。商业版和开源版都可以与 Spring Boot 一起使用。
为了使用 jOOQ 类型安全查询,需要从数据库模式生成 Java 类。你可以按照 jOOQ 用户手册中的说明进行操作。如果你使用 jooq codegen maven
插件,并且还使用 spring-boot-starter-starter-parent
,那么可以安全地省略该插件的
标记。你还可以使用 Spring Boot 定义的版本变量(例如 h2.version
)来声明插件的数据库依赖项。下面的列表显示了一个示例:
<plugin>
<groupId>org.jooqgroupId>
<artifactId>jooq-codegen-mavenartifactId>
<executions>
...
executions>
<dependencies>
<dependency>
<groupId>com.h2databasegroupId>
<artifactId>h2artifactId>
<version>${h2.version}version>
dependency>
dependencies>
<configuration>
<jdbc>
<driver>org.h2.Driverdriver>
<url>jdbc:h2:~/yourdatabaseurl>
jdbc>
<generator>
...
generator>
configuration>
plugin>
jOOQ 提供的流式 API 是通过 org.jOOQ.DSLContext
接口启动的。Spring Boot 将 DSLContext
自动配置为 Spring Bean,并将其连接到应用程序数据源。要使用 DSLContext
,可以通过 @Autowire
使用它,如下例所示:
@Component
public class JooqExample implements CommandLineRunner {
private final DSLContext create;
@Autowired
public JooqExample(DSLContext dslContext) {
this.create = dslContext;
}
}
jOOQ 手册中倾向于使用一个名为
create
的变量来保存DSLContext
。
然后你可以使用 DSLContext
构造你的查询,如下面的示例所示:
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);
}
可以通过定义自己的 @Bean
定义来实现更高级的定制,在创建 jOOQ 配置时使用 @Bean
定义。你可以为以下 jOOQ 类型定义 bean:
ConnectionProvider
ExecutorProvider
TransactionProvider
RecordMapperProvider
RecordUnmapperProvider
Settings
RecordListenerProvider
ExecuteListenerProvider
VisitListenerProvider
TransactionListenerProvider
还可以创建自己的 org.jooq
。如果你想完全控制 jOOQ 配置,可以使用 @Bean
。
Spring Data 提供了额外的项目,帮助你访问各种 NoSQL 技术,包括:
Spring Boot为 Redis、MongoDB、Neo4j、Elasticsearch、Solr Cassandra、Couchbase 和 LDAP 提供了自动配置。你也可以使用其他项目,但是必须自己配置它们。可参考 spring.io/projects/spring-data 中相应的参考文档。
Redis 是一个缓存、消息代理和功能丰富的键值存储。Spring Boot为 Lettuce 和 Jedishttps://github.com/xetorthio/jedis/ 客户端库以及 Spring Data Redis 提供的抽象提供基本的自动配置。
spring-boot-starter-data-redis
“Starter” 可以十分方便地收集相关依赖。默认情况下,它使用 Lettuce。该 starter 同时处理传统应用程序和响应式应用程序。
还提供了一个
spring-boot- Starter -data-re -reactive
“Starter”,用于与具有响应式支持的其他存储保持一致性。
您可以像注入其他 Spring Bean 一样注入一个自动配置的 RedisConnectionFactory
、StringRedisTemplate
或普通的 RedisTemplate
实例。默认情况下,实例尝试连接到 localhost:6379
的Redis服务器。下面的代码显示了这样一个 bean 的例子:
@Component
public class MyBean {
private StringRedisTemplate template;
@Autowired
public MyBean(StringRedisTemplate template) {
this.template = template;
}
// ...
}
你还可以注册实现了
LettuceClientConfigurationBuilderCustomizer
,用于更高级的定制的 bean。如果你使用 Jedis,也可以使用JedisClientConfigurationBuilderCustomizer
。
如果你添加自己的 @Bean
(属于任何自动配置的类型),它将替换默认的(在 RedisTemplate
的情况下除外,当排除基于 Bean
名称的 RedisTemplate
而不是其类型时)。默认情况下,如果 commons-pool2
位于类路径上,你将会得到一个池连接工厂。
MongoDB 是一个开源的 NoSQL 文档型数据库,它使用类似 JSON 的模式,而不是传统的基于表的关系数据。Spring Boot 为使用 MongoDB 提供了一些便利,包括 spring-boot-starter-data-mongodb
和 spring-boot-starter-data-mongodb-reactive
Starters。
你可以注入一股自动配置的 org.springframework.data.mongodb.MongoDbFactory
来访问数据库。默认情况下,实例尝试连接到 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 并配置其他设置,如复制集,如下面的示例所示:
spring.data.mongodb.uri=mongodb://user:[email protected]:12345,mongo2.example.com:23456/test
此外,只要你使用了 Mongo 2.x,可以指定主机/端口。比如,你可以在 application.properties
中声明以下设置:
spring.data.mongodb.host=mongoserver
spring.data.mongodb.port=27017
如果你已经定义了你自己的 MongoClient
,它将被用来自动配置一个合适的 MongoDbFactory
。支持 com.mongodb.MongoClient
和 com.mongodb.client.MongoClient
。
如果你使用 Mongo3.0 Java 驱动,则不再支持
spring.data.mongodb.host
和spring.data.mongodb.port
。在这种情况下,应该使用spring.data.mongodb.uri
来提供所有的配置。
如果
spring.data.mongodb.port
未指定,使用的默认值为 27017。你可以从前面显示的示例中删除这一行。
如果你不使用 Spring Data Mongo,可以注入
com.mongodb.MongoClient
。使用MongoClient
bean 而不是MongoDbFactory
。如果你想完全控制建立 MongoDB 连接,还可以声明自己的MongoDbFactory
或MongoClient
bean。
如果你在使用响应式驱动程序,则 SSL 需要 Netty。如果 Netty 可用且工厂尚未定制,则自动配置将自动配置此工厂。
Spring Data MongoDB 提供了一个 MongoTemplate
类,它的设计与 Spring 的 JdbcTemplate
非常类似。与 JdbcTemplate
一样,Spring Boot 会自动配置一个 bean 来注入模板,如下所示:
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 获取详情。
Spring Data 包括对 MongoDB 的存储库支持。与前面讨论的 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);
}
可以使用
@EntityScan
注解自定义文档扫描位置。
有关 Spring Data MongoDB 的完整细节,包括它的富对象映射技术,参考它的参考文档。
Spring Boot 为嵌入式 Mongo 提供了自动配置。要在 Spring Boot 应用程序中使用它,添加对de.flapdoodle.embed:de.flapdoodle.embed.mongo
的依赖。
Mongo 监听的端口可以通过设置 spring.data.mongodb.port
属性进行配置。要使用随机分配的空闲端口,可使用值 0。MongoAutoConfiguration
创建的 MongoClient
会自动配置为使用随机分配的端口。
如果没有配置自定义端口,则默认情况下嵌入式支持使用随机端口(而不是27017)。
如果类路径上有 SLF4J,那么 Mongo 生成的输出将自动路由到名为 org.springframework.boot.autoconfigure.Mongo.embedded.EmbeddedMongo
的记录器。
你可以声明自己的 IMongodConfig
和 IRuntimeConfig
bean 来控制 Mongo 实例的配置和日志路由。可以通过声明 DownloadConfigBuilderCustomizer
bean 自定义下载配置。
Neo4j 是一个开源的 NoSQL 图形数据库,它使用了一个由第一级关系连接的节点的富数据模型,这比传统的 RDBMS 方法更适合于大数据连接。Spring Boot 为使用 Neo4j 提供了一些便利,包括 spring-boot-starter-data-neo4j
“Starter”。
要访问Neo4j服务器,可以插入自动配置的 org.Neo4j.ogm.session.session
。默认情况下,该实例尝试使用 Bolt 协议连接到 localhost:7687
上的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
来完全控制会话的创建。配置 bean 或 org.neo4j.ogm.session.SessionFactory
bean。
如果你为你的应用程序添加了 org.neo4j:neo4j-ogm-embedded-driver
依赖,Spring Boot 会自动配置一个进程内的 Neo4j 嵌入式实例,该实例在应用程序关闭时不会保留任何数据。
因为内嵌的 Neo4j OGM 驱动程序本身不提供 Neo4j 内核,所以必须声明
org.neo4j:neo4j
就是依赖你自己。有关兼容版本的列表,参阅 Neo4j OGM 文档。
当类路径上有多个驱动程序时,嵌入式驱动程序优先于其他驱动程序。可以通过设置 spring.data.neo4j.embedded.enabled=false
显式禁用嵌入模式。
如果嵌入式驱动程序和 Neo4j 内核位于上述类路径上,则数据 Neo4j 测试会自动使用嵌入式 Neo4j 实例。
你可以通过在配置中提供到数据库文件的路径来启用嵌入式模式的持久性,例如,
spring.data.neo4j.uri=file://var/tmp/graph.db
。
Neo4j OGM 可以将一些类型(如 java.time.*
中的类型)映射到基于字符串的属性或 Neo4j 提供的本地类型之一。出于向后兼容性的原因,Neo4j OGM 的默认设置是使用基于字符串的表示。若要使用原类型,要添加对 org.neo4j:neo4j-ogm-bolt-native-types
或org.neo4j:neo4j-ogm-embedded-native-types
的依赖项,并配置 spring.data.neo4j.use-native-types
属性,如下例所示:
spring.data.neo4j.use-native-types=true
默认情况下,如果你运行的是 web 应用程序,则会话将绑定到整个请求处理的线程(即,它使用"在视图中打开会话"模式)。如果不需要此行为,可将以下行添加到 application.properties
文件中:
spring.data.neo4j.open-in-view=false
Spring Data 括对 Neo4j 的存储库支持。
与许多其他 Spring Data 模块一样,Spring Data Neo4j 与 Spring Data JPA 共享公共基础组件。你可以使用前面的 JPA 示例,并将 City
定义为 Neo4j OGM @NodeEntity
而不是 JPA @Entity
,并且存储库抽象以相同的方式工作,如下面的示例所示:
package com.example.myapp.domain;
import java.util.Optional;
import org.springframework.data.neo4j.repository.*;
public interface CityRepository extends Neo4jRepository<City, Long> {
Optional<City> findOneByNameAndState(String name, String state);
}
spring-boot-starter-data-neo4j
“Starter” 支持存储库支持和事务管理。你可以通过在 @Configuration
-bean上分别使用 @EnableNeo4jRepositories
和 @EntityScan
来自定义查找存储库和实体的位置。
有关 Spring Data Neo4j 的完整细节,包括它的对象映射技术,参考参考文档。
Apache Solr 是一个搜索引擎。Spring Boot 为 Solr5 客户端库提供了基本的自动配置,并在此基础上提供了 Spring Data Solr 提供的抽象。以 spring-boot-starter-data-solr
“Starter” 用于收集依赖项。
可以像注入任何其他 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
,那么它将取代默认值。
Spring Data 包括对 Apache Solr 的存储库支持。与前面讨论的 JPA 存储库一样,基本原则是根据方法名自动构造查询。
事实上,Spring Data JPA 和 Spring Data Solr 共享相同的公共基础组件。你可以从前面的 JPA 示例开始,假设 City
现在是一个 @SolrDocument
类,而不是一个 JPA @Entity
,那么它的工作方式是相同的。
有关 Spring Data Solr 的完整详细信息,参阅参考文档。
Elasticsearch 是一个开源、分布式、RESTful 风格的搜索和分析引擎。Spring Boot为Elasticsearch提供了基本的自动配置。
Spring Boot支持多个客户端:
Java “低级” 和 “高级” REST 客户端
Spring Data Elasticsearch 提供的 ReactiveElasticsearchClient
传输客户端仍然可用,但它的支持在 Spring Data Elasticsearch 和 Elasticsearch 本身中已被弃用。它将在以后的版本中删除。Spring Boot 提供了一个专用的 “Starter”,spring-boot-starter-data-elasticsearch
。
Jest 客户端也被弃用,因为 Elasticsearch 和 Spring Data Elasticsearch 都为 REST 客户机提供了官方支持。
Elasticsearch 提供了 两个不同的 REST 客户端,你可以使用"低级客户端"和"高级客户端"来查询集群。
如果你在类路径上有 org.elasticsearch.client:elasticsearch-rest-client
依赖,Spring Boot 将自动配置并注册一个 RestClient
bean,该 bean 的默认目标是 localhost:9200
。你可以进一步调整如何配置 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
你也可以注册任意数量的 bean,这些 bean 实现 RestClientBuilderCustomizer
,用于更高级的定制。要完全控制注册,需要定义一个 RestClient
bean。
如果你有 org.elasticsearch.client:elasticsearch-rest-high-level-client
依赖于,Spring Boot 将自动配置一个 RestHighLevelClient
,该客户端封装了所有现有的 RestClient
bean,重用其 HTTP 配置。
Spring Data Elasticsearch 以响应的方式发送 ReactiveElasticsearchClient
来查询 Elasticsearch 实例。它构建在 WebFlux 的 WebClient
之上,因此 spring-boot-starter-elasticsearch
和 spring-boot-starter-webflux
依赖项都有助于实现这种支持。
默认情况下,Spring Boot 会自动配置并注册一个 ReactiveElasticsearchClient
bean,目标是 localhost:9200
。你可以进一步调整它的配置,如下面的例子所示:
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。
既然 Spring Boot 支持官方的 RestHighLevelClient
,那么对 Jest 的支持是将被弃用。
如果类路径上有 Jest
,你可以注入一个自动配置的 JestClient
,默认情况下它的目标是 localhost:9200
。你可以进一步调整如何配置客户端,如下例所示:
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
你也可以注册任意数量的 bean,这些 bean 实现 HttpClientConfigBuilderCustomizer
以实现更高级的定制。下面的例子优化额外的HTTP设置:
static class HttpSettingsCustomizer implements HttpClientConfigBuilderCustomizer {
@Override
public void customize(HttpClientConfig.Builder builder) {
builder.maxTotalConnection(100).defaultMaxTotalConnectionPerRoute(5);
}
}
要完全控制注册,需要定义一个 JestClient
bean。
为了连接到 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 客户机的是等效的。
Spring Data 包括对 Elasticsearch 的存储库支持。与前面讨论的 JPA 存储库一样,基本原则是根据方法名自动构造查询。
事实上,Spring Data JPA 和 Spring Data Elasticsearch 都共享相同的基础组件。你可以使用前面的 JPA 示例,并假设 City
现在是一个 Elasticsearch @Document
类而不是 JPA @Entity
,它以相同的方式工作。
有关 Spring Data Elasticsearch 的完整细节,参考参考文档。
Spring Boot 支持经典的和响应式的E lasticsearch 存储库,使用E lasticsearchRestTemplate
或响应式的 ElasticSearchTemplate
bean。由于存在所需的依赖项,这些 bean 很可能是由 Spring Boot 自动配置的。
如果希望使用自己的模板来支持 Elasticsearch 存储库,可以添加自己的E lasticsearchRestTemplate
或 ElasticsearchOperations
@Bean,只要它名为 "elasticsearchTemplate"
。这同样适用于 ReactiveElasticsearchTemplate
和 ReactiveElasticsearchOperations
,bean 名为 "reactiveElasticsearchTemplate"
。
你可以选择使用以下属性禁用存储库支持:
spring.data.elasticsearch.repositories.enabled=false
Cassandra 是一个开源的分布式数据库管理系统,设计用于处理跨服务器的大量数据。Spring Boot 为 Cassandra 提供了自动配置,并在其上提供 Spring Data Cassandra提 供的抽象。以 spring-boot-starter-data-cassandra
“Starter” 的方式收集依赖项。
你您可以注入一个自动配置的 CassandraTemplate
或 Cassandra Session
实例,就像你注入任何其他 Spring Bean 一样。spring.data.cassandra.*
属性可用于自定义连接。通常,你可以提供 keyspace-name
和 contract-points
属性,如下面的示例所示:
spring.data.cassandra.keyspace-name=mykeyspace
spring.data.cassandra.contact-points=cassandrahost1,cassandrahost2
你还可以注册任意数量的 bean,这些 bean 实现 ClusterBuilderCustomizer
以实现更高级的定制。
下面的代码展示了如何注入一个 Cassandra bean:
@Component
public class MyBean {
private CassandraTemplate template;
public MyBean(CassandraTemplate template) {
this.template = template;
}
// ...
}
如果添加自己的 @Bean
类型 CassandraTemplate
,它将取代默认值。
Spring Data 包括对 Cassandra 的基本存储库支持。目前,这比前面讨论的 JPA 存储库更受限制,需要使用 @Query
注解查找方法。
查看 参考文档 了解 Spring Data Cassandra。
Couchbase 是一个开源、分布式、多模型的 NoSQL 面向文档的数据库,它针对交互式应用程序进行了优化。Spring Boot 提供了对 Couchbase 的自动配置,以及 Spring Data Couchbase 在其上提供的抽象。有 spring-boot-starter-data-couchbase
和 spring-boot-starter-data-couchbase-reactive
“Starts” 收集依赖项。
可以通过添 加Couchbase SDK 和一些配置获得 Bucket
和 Cluster
。spring.couchbase.*
属性可用于自定义连接。一般情况下,需要提供地址、bucket名称和密码,如下例所示:
spring.couchbase.bootstrap-hosts=my-host-1,192.168.1.123
spring.couchbase.bucket.name=my-bucket
spring.couchbase.bucket.password=secret
你至少需要提供地址,在这种情况下,bucket 名称是默认的,密码是一个空字符串。或者,可以定义自己的
org.springframework.data.couchbase.config.CouchbaseConfigurer
@Bean
来控制整个配置。
还可以定制一些 CouchbaseEnvironment
设置。例如,下面的配置更改了用于打开新桶并启用 SSL 支持的超时:
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.*
属性获取更多详细信息。
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:
couchbaseTemplate
的 CouchbaseTemplate
@Bean
。couchbaseIndexManager
的 IndexManager
@Bean
。couchbaseCustomConversions
的 CustomConversions
@Bean
。为了避免在自己的配置中硬编码这些名称,可以重用 Spring Data Couchbase 提供的 BeanNames
。例如,你可以自定义要使用的转换器,如下所示:
@Configuration(proxyBeanMethods = false)
public class SomeConfiguration {
@Bean(BeanNames.COUCHBASE_CUSTOM_CONVERSIONS)
public CustomConversions myCustomConversions() {
return new CustomConversions(...);
}
// ...
}
如果你想完全绕过 Spring Data Couchbase 的自动配置,那么要提供自己的
org.springframework.data.couchbase.config.AbstractCouchbaseDataConfiguration
的实现。
LDAP(轻量级目录访问协议)是一种开放的、与供应商无关的行业标准应用程序协议,用于通过 IP 网络访问和维护分布式目录信息服务。Spring Boot 为兼容的 LDAP 服务器提供自动配置,并支持来自 UnboundID 的嵌入式内存 LDAP 服务器。
LDAP 抽象是由 Spring Data LDAP 提供的。用 spring-boot-starter-data-ldap
“Starter” 收集依赖项。
为了连接到 LDAP 服务器,确保加载了 spring-boot-starter-data-ldap
或 spring-ldap-core
的依赖,然后在应用程序中声明服务器的 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
使用它。
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;
}
// ...
}
出于测试目的,Spring Boot 支持从 UnboundID 自动配置内存中的 LDAP 服务器。要配置服务器,要添加一个 com.unboundid:unboundid-ldapsdk
依赖项。并声明一个 spring.ldap.embedded.base-dn
属性,如下:
spring.ldap.embedded.base-dn=dc=spring,dc=io
可以定义多个 base-dn 值,但是,由于专有名称通常包含逗号,因此必须使用正确的符号来定义它们。
在 yaml 文件中,可以使用 yaml 列表符号:
spring.ldap.embedded.base-dn: - dc=spring,dc=io - dc=pivotal,dc=io
在 properties 文件中,必须包含索引作为属性名称的一部分:
spring.ldap.embedded.base-dn[0]=dc=spring,dc=io spring.ldap.embedded.base-dn[1]=dc=pivotal,dc=io
默认情况下,服务器在一个随机端口上启动,并触发常规的 LDA P支持。不需要指定 spring.ldap.urls
属性。
如果有一个 schema.ldif
文件在你的类路径上,那么它会被用于初始化服务器。如果希望从不同的资源加载初始化脚本,还可以使用 spring.ldap.embedded.ldif
属性。
默认情况下,使用标准模式验证 LDIF
文件。你可以通过设置 spring.ldap.embedded.validation.enabled
来完全关闭验证。如果有自定义属性,可以使用 spring.ldap.embedded.validation.schema
来定义自定义属性类型或对象类。
InfluxDB 是一个开放源码的时间序列数据库,用于快速、高可用性存储和检索时间序列数据,如操作监视、应用程序指标、物联网传感器数据和实时分析。
Spring Boot自动配置一个 InfluxDB
数据库实例,前提是 influxdb-java
客户端位于类路径上,并且设置了数据库的 URL,如下例所示:
spring.influx.url=https://172.0.0.1:8086
如果 InfluxDB 的连接需要用户和密码,可以设置 spring.influx.user
和 spring.influx.password
属性。
InfluxDB 库依赖于 OkHttp。如果你需要调优 InfluxDB 使用的 http 客户端,你可以注册一个 InfluxDbOkHttpClientBuilderProvider
bean。
Spring Framework 提供对透明添加缓存到应用中的支持。抽象的核心是将缓存应用于方法,从而减少了基于缓存中可用信息的执行次数。缓存逻辑是透明地应用的,对调用程序没有任何干扰。只要通过 @EnableCaching
注注解用缓存支持,Spring Boot 就会自动配置缓存基础组件。
有关更多细节,参阅 Spring 框架参考 的相关部分。
简而言之,将缓存添加到服务的操作中就像将相关注解添加到其方法中一样简单,如下面的示例所示:
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
参数匹配的条目。如果找到一个条目,缓存中的内容会立即返回给调用者,而方法不会被调用。否则,将调用该方法,并在返回值之前更新缓存。
你还可以透明地使用标准 JSR-107 (JCache)注解(比如
@CacheResult
)。但是,强烈建议你不要混合使用 Spring 缓存和 JCache 注释。
你如果不添加任何特定的缓存库,Spring Boot 会自动配置一个在内存中使用并发映射的简单提供程序。当需要缓存时(如上例中的 piDecimals
),此提供程序将为你创建缓存。该提供程序并不真正推荐用于生产,但它对于入门和确保你了解这些特性非常有用。当你决定使用缓存提供程序时,要先阅读其文档以了解如何配置应用程序使用的缓存。几乎所有提供程序都要求你显式配置在应用程序中使用的每个缓存。有些提供了一种自定义由 spring.cache.cache-names
属性定义的默认缓存的方法。
还可以从缓存中透明地更新或删除数据。
抽象缓存不提供实际的存储,而是依赖于 org.springframework.cache.Cache
实现的抽象和 org.springframework.cache.CacheManager
接口。
如果你还没有定义类型为 CacheManager
的 bean 或名为 cacheResolver
的 CacheResolver
(参阅 CachingConfigurer
), Spring Boot 将尝试检测以下提供程序(按照指定的顺序):
可以通过设置
spring.cache.type
来强制特定的缓存提供程序。类型属性。如果需要在某些环境(如测试)中完全禁用缓存,使用此属性。
使用
spring-boot-starter-cache
“Starter” 快速添加基本缓存依赖项。启动器引入了spring-context-support
。如果手动添加依赖项,则必须包含spring-context-support
,以便使用 JCache EhCache2.x,或 Caffeine 支持。
如果 CacheManager
是由 Spring Boot 自动配置的,则可以通过公开实现 CacheManagerCustomizer
接口的 bean,在完全初始化之前进一步优化其配置。以下示例设置了一个标志,表示应将空值传递给基础映射:
@Bean
public CacheManagerCustomizer<ConcurrentMapCacheManager> cacheManagerCustomizer() {
return new CacheManagerCustomizer<ConcurrentMapCacheManager>() {
@Override
public void customize(ConcurrentMapCacheManager cacheManager) {
cacheManager.setAllowNullValues(false);
}
};
}
在前面的示例中,需要自动配置的
ConcurrentMapCacheManager
。如果不是这样(你提供了自己的配置或自动配置了其他缓存提供程序),则不会调用自定义程序。你可以拥有任意数量的自定义项,也可以使用@order
或Ordered
对它们排序。
如果上下文中定义了不止一个 org.springframework.cache.Cache
bean,那么就会使用通用缓存。Spring Boot 将会创建一个包装所有 bean 的 CacheManager
类型。
JCache 是通过类路径上的 javax.cache.spi.CachingProvide
r(即类路径上存在一个符合 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
当缓存库同时提供本地实现和 JSR-107 支持时,Spring Boot 更喜欢使用 JSR-107 支持,因此如果切换到不同的 JSR-107 实现,也可以使用相同的特性。
Spring Boot 一般支持 Hazelcast。如果有一个
HazelcastInstance
可用,那么它会自动被CacheManager
重用,除非指定了spring.cache.jcache.config
属性。
有两种方法可以自定义底层的 javax.cache.cacheManager
:
spring.cache.cache-names
属性让缓存在启动时被创建,如果你定义了一个 javax.cache.configuration.Configuration
bean,则使用它来自定义它们。CacheManager
的引用调用 org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer
bean 进行完全定制。如果定义了一个标准的
javax.cache.CacheManager
bean,它将自动包装在抽象所期望的org.springframework.cache.CacheManager
实现中。不会对其应用进行进一步的自定义。
如果可以在类路径的根目录中找到名为 EhCache.xml
的文件,则使用 EhCache2.x 缓存。如果找到 EhCache 2.x,则使用 spring-boot-starter-cache
“starter” 提供的 EhCacheCacheManager
来引导缓存管理器。此外还可以提供备用配置文件,如下例所示:
spring.cache.ehcache.config=classpath:config/another-config.xml
Spring Boot 一般支持 Hazelcast,如果 HazelcastInstance
已经被自动配置,那么它将被自动包装在 CacheManager
中。
Infinispan 没有默认的配置文件位置,因此必须显式地指定它。否则,将使用默认的引导程序。
spring.cache.infinispan.config=infinispan.xml
通过设置 spring.cache.cache-names
在启动时创建缓存。如果定义了自定义的 ConfigurationBuilder
bean,则使用它定制缓存。
在 Spring Boot 中对
Infinispan
的支持仅限于嵌入式模式,这是非常基本的。如果你想要更多的选项,应该使用官方的 Infinispan Spring Boot starter。有关更多细节,参见 Infinispan 文档。
如果 Couchbase Java 客户端和 couchbase-spring-cache
实现可用并且 Couchbase 已配置,则 Couchbas e缓存管理器将自动配置。还可以通过设置 spring.cache.cache-names
属性在启动时创建其他缓存。这些缓存在自动配置的 Bucke
t上操作。还可以使用自定义程序在另一个 Bucket
上创建其他缓存。假设你需要主 Bucket
上的两个缓存(cache1
和 cache2
)和其它 Bucket
上的一个(cache3
)缓存(自定义生存时间为2秒)。你可以通过配置创建前两个缓存,如下所示:
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
。
如果 Redis 可用且已配置,则自动配置 RedisCacheManager
。通过设置 spring.cache
,可以在启动时创建额外的缓存。可以使用 spring.cache.redis.*
配置 spring.cache.cache-names
和缓存默认值。例如,下面的配置创建了时间为 10分钟 的 cache1
和 cache2
缓存:
spring.cache.cache-names=cache1,cache2
spring.cache.redis.time-to-live=600000
默认情况下,添加一个键前缀,这样,如果两个单独的缓存使用相同的键,Redis 也没有重复的键,也不会返回无效的值。如果你创建自己的
RedisCacheManager
,强烈建议保持启用此设置。
你可以通过添加自己的
RedisCacheConfiguration
@Bean 来完全控制缺省配置。如果你正在寻找自定义默认序列化策略的方法,那么这将非常有用。
如果需要对配置进行更多控制,可以考虑注册一个 RedisCacheManagerBuilderCustomizer
bean。下面的例子显示了一个定制器,它为 cache1
和 cache2
配置了一个特定的生存时间:
@Bean
public RedisCacheManagerBuilderCustomizer myRedisCacheManagerBuilderCustomizer() {
return (builder) -> builder
.withCacheConfiguration("cache1",
RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(10)))
.withCacheConfiguration("cache2",
RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(1)));
}
Caffeine 是 Java8 对 Guava 缓存的重写,取代了对 Guava 的支持。如果有 Caffeine,Spring Boot 会自动配置 CaffeineCacheManager
(由 spring-boot-starter-cache
“Starter” 提供)。通过设置 spring.cache.cache-names
,可以在启动时创建缓存,而且该属性可以通过以下方式之一(按指定的顺序)进行自定义:
spring.cache.caffine.spec
定义的缓存规范com.github.benmanes.caffine.cache.CaffeineSpec
beancom.github.benmanes.caffee.cache.Caffeine
bean例如,下面的配置创建了最大大小为 500、生存时间为 10分钟 的 cache1
和 cache2
缓存:
spring.cache.cache-names=cache1,cache2
spring.cache.caffeine.spec=maximumSize=500,expireAfterAccess=600s
如果定义了 com.github.benmanes.caffine.cache.CacheLoader
bean,它将自动关联到 CaffeineCacheManager
。由于 CacheLoader
将与缓存管理器管理的所有缓存关联,因此必须将其定义为 CacheLoader
,因为自动配置忽略任何其他泛型类型。
如果找不到其他的缓存提供程序,则可以配置一个使用 ConcurrentHashMap
作为缓存存储的简单实现。如果应用程序中没有缓存库,这是默认设置。默认情况下,缓存是根据需要创建的,但是你可以通过设置 cache-names
属性来限制可用缓存的列表。例如,如果你只想要 cache1
和 cache
2缓存,可以设置 cache-names
属性如下:
spring.cache.cache-names=cache1,cache2
如果你这么做,并且你的应用程序使用了未列出的缓存,那么它在运行时需要缓存时就会失败,但在启动时不会失败。这与使用未声明的缓存时真正的缓存提供程序的行为类似。
当配置中出现 @EnableCaching
时,也需要适当的缓存配置。如果需要在某些环境中完全禁用缓存,则强制将缓存类型设置为 none
以使用无操作实现,如下面的示例所示:
spring.cache.type=none
Spring Frameword 为消息传递系统的集成提供了广泛的支持,从使用 JmsTemplate
的 JMS API 的简化使用到异步接收消息的完整基础结构。Spring AMQP 为高级消息队列协议提供了类似的功能集。Spring Boot 还为 RabbitTemplate
和 RabbitMQ 提供了自动配置选项。Spring WebSocket 包含了对 STOMP 消息的支持,Spring Boot 通过启动器和少量的自动配置支持这一点。Spring Boot 还支持 Apache Kafka。
javax.jms.ConnectionFactory
接口提供了创建 javax.jms.Connection
与 JMS 代理交互的标准方法。尽管 Spring 需要一个 ConnectionFactory
来处理 JMS,但你通常不需要自己直接使用它,而是可以依赖于更高级别的消息传递抽象。(有关详细信息,参阅 Spring 框架参考文档的相关部分。)Spring Boot 还自动配置发送和接收消息所需的基础组件。
当 ActiveMQ 可用时,Spring Boot 还可以配置 ConnectionFactory
。如果存在代理,则会自动启动并配置嵌入式代理(假设没有通过配置指定代理 URL)。
如果使用了
spring-boot-starter-activemq
,则会提供连接或嵌入 ActiveMQ 实例所需的依赖项,以及与 JMS 集成的 Spring 基础组件。
ActiveM Q配置由 spring.activemq.*
中的外部配置属性控制。例如,你可以在 application.properties
中声明以下部分:
spring.activemq.broker-url=tcp://192.168.1.210:9876
spring.activemq.user=admin
spring.activemq.password=secret
默认情况下,CachingConnectionFactory
将本地 ConnectionFactory
包装起来,并使用一些合理的设置,你可以通过 spring.jms.*
中的外部配置属性来控制这些设置。
spring.jms.cache.session-cache-size=5
如果你希望使用本机池,可以通过向 org.messaginghub:pooled-jms
添加一个依赖项来实现,并相应地配置 JmsPoolConnectionFactory
,如下面的示例所示:
spring.activemq.pool.enabled=true
spring.activemq.pool.max-connections=50
有关更多受支持的选项,参见 ActiveMQProperties。你还可以注册任意数量的 bean,这些 bean 实现
ActiveMQConnectionFactoryCustomizer
以实现更高级的定制。
默认情况下,ActiveMQ 会创建一个目的地(如果它还不存在),以便根据它们提供的名称解析目的地。
当 Spring Boot 检测到类路径下的 Attemis 可用时,它会自动配置好 ConnectionFactory
。如果存在代理,则会自动启动并配置嵌入式代理(除非已显式设置了 mode 属性)。受支持的模式包括嵌入式模式(为了明确说明需要嵌入式代理,如果代理在类路径上不可用,则会出现错误)和本地模式(为了使用 netty
传输协议连接到代理)。配置后一个代理时,Spring Boot 会配置一个 ConnectionFactory
,它使用默认设置连接本地机器上运行的代理。
spring-boot-starter=antemis
提供了连接到现有的 Artemis 实例的必要依赖项,以及与 JMS 集成的 Spring 基础组件。将org.apache.activemq:artemis-jms-server
提交到你的应用中可以允许你使用嵌入式模式。
可以使用 spring.artemis.*
属性控制 Artemis 配置。比如,你可以在 application.properties
上声明以下内容:
spring.artemis.mode=native
spring.artemis.host=192.168.1.210
spring.artemis.port=9876
spring.artemis.user=admin
spring.artemis.password=secret
在嵌入式模式中,你可以启动持久化和列出可用的代理之间的距离。可以将它们指定为用逗号分隔的列表项,然后用默认选项创建它们,或者你可以定义一个 org.apache.activemq.artemis.jms.server.config.JMSQueueConfiguration
或 org.apache.activemq.artemis.jms.server.config.TopicConfiguration
类型的 bean分别用于高级队列和主题配置。
默认情况下,CachingConnectionFactory
会通过 spring.jms.*
中合理的值来封装本地的 ConnectionFactory
。
spring.jms.cache.session-cache-size=5
如果你想使用本地池,可以添加 org.messaginghub:pooled-jms
依赖,并且配置好对应的 JmsPollConecctionFactory
,如下例所示:
spring.artemis.pool.enabled=true
spring.artemis.pool.max-connections=50
可以查看 ArtemisProperties 获取更多支持的选项参数。
目的地根据它们的名称解析,并不涉及 JNDI 的查找,可以使用 Artemis 配置中的 name
属性或通过配置提供的名称。
如果你在应用服务器上运行应用程序,Spring Boot 会尝试使用 JNDI 来定位 JMS 的 ConnectionFactory
。默认情况下,它会检查 java:/JmsXA
和j ava:/XAConnectionFactory
位置。你可以使用 spring.jms-jndi-name
指定另一个位置如下例所示:
spring.jms.jndi-name=java:/MyConnectionFactory
Spring 的 JmsTemplate
是自动配置的,你可以直接将其自动装配到自己的 bean 中,如下面的示例所示:
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;
}
// ...
}
可以以类似的方式注入
JmsMessagingTemplate
。如果定义了DestinationResolver
或MessageConverte
r bean,它将自动关联到自动配置的JmsTemplate
。
当 JMS 基础组件存在时,任何 bean 都可以使用 @JmsListener
注解创建监听器端点。如果没有 JmsListenerContainerFactory
被定义,则会自动配置默认的 JmsListenerContainerFactory
。如果定义了 DestinationResolver
或 MessageConverte
r bean,它将自动关联到默认工厂。
默认情况下,默认工厂是事务性的。如果你在一个存在 JtaTransactionManager
的基础组件中运行,默认情况下它与监听器容器相关联。如果没有,则启用 sessionTransacted
标志。在后一种情况下,可以通过在监听器方法(或其委托)上添加 @Transactional
来将本地数据存储事务与传入消息的处理关联起来。这将确保在本地事务完成后确认传入消息,还包括发送在同一 JMS 会话上执行的响应消息。
下面的组件在 someQueue
目的地创建一个监听器端点:
@Component
public class MyBean {
@JmsListener(destination = "someQueue")
public void processMessage(String content) {
// ...
}
}
查看
@EnableJms
文档 获取更多信息。
如果你需要创建更多的 JmsListenerContainerFactory
实例或者覆盖默认实例,Spring Boot将提供一个 DefaultJmsListenerContainerFactoryConfigurer
,可以使用与自动配置的设置相同的设置来初始化 DefaultJmsListenerContainerFactory
。
例如,下面的示例展示了另一个使用特定 MessageConverter
的工厂:
@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
注解方法:
@Component
public class MyBean {
@JmsListener(destination = "someQueue", containerFactory="myFactory")
public void processMessage(String content) {
// ...
}
}
高级消息队列协议(AMQP)是一种与平台无关的、面向消息中间件的线程级别协议。Spring AMQP 项目将核心 Spring 概念应用于基于 AMQP 的消息传递解决方案的开发。Spring Boot 为通过 RabbitMQ 使用 AMQP 提供了一些便利,包括 spring-boot-starter-amqp
“Starter”。
RabbitMQ 是一种基于 AMQP 协议的轻量级、可靠、可伸缩和可移植的消息代理。Spring 使用 RabbitMQ 通过 AMQP 协议进行通信。
外部配置 spring.rabbitmq.*
控制 RabbitMQ 配置。比如,你可以在 application.properties
中声明以下属性:
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=secret
此外,你也可以使用 address
属性定义连接:
spring.rabbitmq.addresses=amqp://admin:secret@localhost
如果上下文中存在 ConnectionNameStrategy
bean,它将被自动配置的 ConnectionFactory
用于创建连接。有关更多受支持的选项,参见 RabbitProperties。
查看 理解使用 RabbitMQ 协议的 AMQP 获取更多内容。
Spring 的 AmqpTemplate
和 AmqpAdmin
是自动配置的,您你以直接将它们自动装配到自己的 bean 中,如下面的示例所示:
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;
}
// ...
}
可以以类似的方式注入
RabbitMessagingTemplate
。如果定义了MessageConverter
bean,它将自动关联到自动配置的AmqpTemplate
。
如果需要,任何定义为 bean 的 org.springframework.amqp.core.Queue
都会自动用于在 RabbitMQ 实例上声明相应的队列。
如果要重复操作,可以在 AmqpTemplate
上启用重试(例如,在代理连接丢失的情况下):
spring.rabbitmq.template.retry.enabled=true
spring.rabbitmq.template.retry.initial-interval=2s
默认情况下重试是被禁止的。你还可以通过声明一个 RabbitRetryTemplateCustomizer
bean 以编程的方式定制 RetryTemplate
。
当 Rabbit 基本组件存在时,任何 bean 都可以用 @RabbitListener
注解来创建监听器端点。如果尚未定义 RabbitListenerContainerFactory
,则会自动配置默认的 SimpleRabbitListenerContainerFactory
,你可以使用 spring.rabbitmq.listener.type
属性切换到直接容器。如果定义了 MessageConverter
或 MessageRecoverer
bean,它将自动与默认工厂关联。
下列展示了 someQueue
队列创建了一个监听器端点的简单组件:
@Component
public class MyBean {
@RabbitListener(queues = "someQueue")
public void processMessage(String content) {
// ...
}
}
查看
@EnableRabbit
文档 获取更多内容。
如果你需要创建多个 RabbitListenerContainerFactory
实例或者你想覆盖默认的,Spring Boot 提供了SimpleRabbitListenerContainerFactoryConfigurer
和 DirectRabbitListenerContainerFactoryConfigurer
,你可以用它来初始化一个与 SimpleRabbitListenerContainerFactory
和 DirectRabbitListenerContainerFactory
相同的设置工厂使用的自动配置。
选择哪种容器类型并不重要。这两个 bean 会通过自动配置暴露出来。
例如,下面的配置类公开了另一个使用特定 MessageConverter
的工厂:
@Configuration(proxyBeanMethods = false)
static class RabbitConfiguration {
@Bean
public SimpleRabbitListenerContainerFactory myFactory(
SimpleRabbitListenerContainerFactoryConfigurer configurer) {
SimpleRabbitListenerContainerFactory factory =
new SimpleRabbitListenerContainerFactory();
configurer.configure(factory, connectionFactory);
factory.setMessageConverter(myMessageConverter());
return factory;
}
}
然后你可以在任何 @RabbitListener
注解方法中使用该工厂,如下所示:
@Component
public class MyBean {
@RabbitListener(queues = "someQueue", containerFactory="myFactory")
public void processMessage(String content) {
// ...
}
}
你可以启用重试来处理侦啊今天器引发异常的情况。默认情况下,使用 RejectAndDontRequeueRecoverer
,但你可以定义自己的消息恢复程序。当重试次数用尽时,消息将被拒绝,如果代理配置这样做,则消息将被丢弃或路由到死信交换。默认情况下,禁用重试。你还可以通过声明 RabbitRetryTemplateCustomizer
bean以编程的方式自定义 RetryTemplate
。
默认情况下,如果禁用重试并且监听器引发异常,则会无限期重试传递。你可以通过两种方式修改此行为:将
defaultRequeueRejected
属性设置为false,进行零次重新传递,或者抛出AmqpRejectAndDontRequeueException
,以表示应拒绝邮件。后者是启用重试并达到最大传递尝试次数时使用的机制。
spring-kafka
项目支持 Apache KafKa 的自动配置。
外部配置 spring.kafka.*
控制 RabbitMQ 配置。比如,你可以在 application.properties
中声明以下属性:
spring.kafka.bootstrap-servers=localhost:9092
spring.kafka.consumer.group-id=myGroup
要在启动时创建主题,添加
NewTopic
类型的 bean。如果主题已经存在,则忽略该 bean。
查看 KafkaProperties 获取更多支持的选项参数。
Spring 的 KafkaTemplate
是自动配置的,你可以直接在你自己的 bean 中自动装配它,如下面的例子所示:
@Component
public class MyBean {
private final KafkaTemplate kafkaTemplate;
@Autowired
public MyBean(KafkaTemplate kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate;
}
// ...
}
如果定义了属性
spring.kafka.producer.transaction-id-prefix
,则会自动配置KafkaTransactionManager
。此外,如果定义了RecordMessageConverter
bean,它将自动与自动配置的KafkaTemplate
关联。
当 Apache Kafka 基本组件存在时,任何 bean 都可以使用 @KafkaListener
进行注释,以创建监听器端点。如果没有定义 KafkaListenerContainerFactory
,则会自动配置默认值,并在 spring.kafka.listener.*
中定义键。
下面的组件在 someTopic
主题上创建一个监听器端点:
@Component
public class MyBean {
@KafkaListener(topics = "someTopic")
public void processMessage(String content) {
// ...
}
}
如果定义了 KafkaTransactionManager
bean,它将自动与容器工厂关联。类似地,如果定义了 ErrorHandler
、AfterRollbackProcessor
或 ConsumerAwareRebalanceListener
bean,它将自动关联到默认工厂。
根据监听器类型,RecordMessageConverter
或 BatchMessageConverter
bean与默认工厂关联。如果批处理监听器只存在 RecordMessageConverter
bean,则它将被包装在BatchMessageConverter
中。
自定义的
ChainedKafkaTransactionManager
必须标记为@Primary
,因为它通常引用自动配置的KafkaTransactionManager
bean。
Spring 为 Kafka 提供了一个工厂 bean 来创建 StreamsBuilder
对象并管理其流的生命周期。只要 kafka-streams
在类路径上并且 Kafka 流通过 @EnableKafkaStreams
注解启用,Spring Boot就会自动配置所需的 KafkaStreamsConfiguration
bean。
启用 Kafka 流意味着必须设置应用程序 id 和引导服务器。前者可以使用 spring.kafka.streams.application-id
配置,如果未设置,则默认为 spring.application.name
。后者可以全局设置,也可以专门为流重写。
使用专用属性时可以使用几个附加属性;可以使用 spring.Kafka.streams.properties
命名空间设置其他任意 Kafka 属性。有关详细信息,参见其他 Kafka 属性。
要使用工厂 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
其行为。
自动配置支持的属性记录在 appendix-application-properties.html 中。注意,在大多数情况下,这些属性(连字符或驼峰字符)直接映射到 Apache Kafka 点式属性(dotted properties)。有关详细信息,参阅 Apache Kafka文档。
前几个属性应用于所有组件(生产者、消费者、管理者和流),但如果希望使用不同的值,则可以在组件级别指定。Apache Kafka 指定重要性分别为 HIGH、MEDIUM 或 LOW 的属性。Spring Boot 自动配置支持所有高重要性属性、某些选定的中、低属性以及任何没有默认值的属性。
只有 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
admin属性设置为 second
,prop.three
consumer 属性设置为 third
,prop.four
producer属性设置为 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
以这种方式设置的属性覆盖 Spring Boot 显式支持的任何配置项。
Spring 为 Apache Kafka 提供了一种使用嵌入式 Apache Kafka 代理测试项目的便捷方法。要使用此功能,要在测试类上添加来自 spring-kafka-test
模块的 EmbeddedKafka
注解。有关更多信息,参阅 Spring For Apache Kafka 参考手册。
要使 Spring Boot 自动配置与前面提到的嵌入式 Apache Kafka 代理一起工作,需要将嵌入式代理地址(由 EmbeddedKafkaBroker
填充)的系统属性重新映射到 Apache Kafka 的 Spring Boot 配置属性中。有几种方法可以做到这一点:
提供一个系统属性来将嵌入式代理地址映射到测试类中的 spring.kafka.bootstrap-servers
:
static {
System.setProperty(EmbeddedKafkaBroker.BROKER_LIST_PROPERTY, "spring.kafka.bootstrap-servers");
}
在 @EmbeddedKafka
注解上配置属性名:
@EmbeddedKafka(topics = "someTopic",
bootstrapServersProperty = "spring.kafka.bootstrap-servers")
在配置属性中使用占位符:
spring.kafka.bootstrap-servers=${spring.embedded.kafka.brokers}
如果需要从应用程序调用远程 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
包含许多有用的方法,可用于快速配置RestTemplate
。例如,要添加基本的 auth 支持,可以使用builder.basicAuthentication("user", "password").build()
。
有三种主要方法来自定义 RestTemplate
,取决于你希望定制应用的范围。
要尽可能缩小任何自定义的范围,可插入自动配置的 RestTemplateBuilder
,然后根据需要调用其方法。每个方法调用都返回一个新的 RestTemplateBuilder
实例,因此自定义只影响这个 builder 的使用。
要在应用程序范围内进行附加自定义,使用 Restemplatecustomizer
bean。所有这些bean 都自动注册到自动配置的 RestTemplateBuilder
中,并应用到用它构建的任何模板。
以下示例显示一个自定义程序,该自定义程序为除 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。
如果类路径上有 Spring WebFlux,也可以选择使用 WebClient
调用远程 REST 服务。与 RestTemplate
相比,这个客户端具有更高的功能性,并且是响应式的。你可以在 Spring Framework 文档的专用部分了解更多关于 WebClient 的信息。
SpringBoot 为你创建并预配置了一个 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);
}
}
根据应用程序类路径上可用的库,Spring Boot 将自动检测要用于驱动 WebClient
的ClientHttpConnector
。目前,Reactor Netty 和 Jetty 的客户机是受支持的。
spring-boot-starter-webflux
默认依赖于 io.projectreactor.netty:reactor-netty
,它同时提供服务器和客户端实现。如果你选择使用 Jetty 作为一个反应性服务器,那么你应该添加对 Jetty 响应式 HTTP 客户端库 org.eclipse.jetty:jetty-reactive-httpclient
的依赖。对服务器和客户机使用相同的技术有这个优点,因为它将在客户机和服务器之间自动共享 HTTP 资源。
开发人员可以通过提供自定义的 ReactorResourceFactory
或 JettyResourceFactory
bean来覆盖 Jetty 和 Reactor Netty 的资源配置——这将应用于客户端和服务器。
如果你希望为客户机重写该选项,则可以定义自己的 ClientHttpConnector
bean并完全控制客户机配置。
你可以在 Spring 框架参考文档中了解更多关于 WebClient
配置选项的信息。
WebClient
自定义的方法主要有三种,这取决于你希望定制应用的范围。
要尽可能缩小任何自定义的范围,可插入自动配置的 WebClient.Builde
r,然后根据需要调用其方法。Builder
实例是有状态的:对 Builder
的任何更改都反映在随后用它创建的所有客户端中。如果要使用同一生成器创建多个客户端,还可以考虑使用 WebClient.Builder other = builder.clone();
。
要对所有 WebClient.Builder
实例进行应用程序范围的附加自定义,可以声明 WebClientCustomizer
bean,并在注入点本地更改 WebClient.Builder
。
最后,你可以返回到使用原始 API 并使用 WebClient.create()
。在这种情况下,不会使用自动配置或 WebClientCustomizer
。
只要在类路径上有 JSR-303实现(如 Hibernate 验证器),就会自动启用 Bean validation 1.1支持的方法验证功能。这样就可以用 javax.validation
约束对 bean 方法的参数和/或返回值进行注解。具有此类带注解方法的目标类需要在类型级别使用 @Validated
注解进行注释,以便在其方法中搜索内联约束注释。
例如,以下服务触发第一个参数的验证,确保其大小在 8 到 10 之间:
@Service
@Validated
public class MyBean {
public Archive findByCodeAndAuthor(@Size(min = 8, max = 10) String code,
Author author) {
...
}
}
Spring Framework 通过使用 JavaMailSender
接口为发送电子邮件提供了一个简单的抽象,Spring Boo t为其提供了自动配置以及一个启动模块。
有关如何使用
JavaMailSender
的详细说明,参阅参考文档。
如果 spring.mail.host
和相关库(由 spring-boot-starter-mail
定义)可用,那么要是不存在 JavaMailSender
,就创建默认的 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
后,它优先于所有其他与会话相关的设置。
Spring Boot 通过使用 Atomikos 或 Bitronix 嵌入式事务管理器支持跨多个 XA 资源的分布式 JTA 事务。在部署到合适的 Java EE 应用服务器时,也支持 JTA 事务。
当检测到 JTA 环境时,Spring 的 JtaTransactionManager
被用于管理事务。自动配置的 JMS、DataSource 和 JPA bean被升级为支持 XA 事务。你可以使用标准的 Spring 用法(如@Transactional
)来参与分布式事务。如果你在 JTA 环境中,仍然希望使用本地事务,可以将 spring.jta.enabled
属性设置为 false
以禁用 JTA 自动配置。
Atomikos 是一个流行的开源事务管理器,可以嵌入到你的 Spring Boot 应用程序中。可以使用 spring-boot-starter-jta-atomikos
拉入相应的 Atomikos 库。Spring Boot 自动配置Atomikos,并确保对 Spring beans 应用适当的 depends-on
设置,以获得正确的启动和关闭顺序。
默认情况下,Atomikos 事务日志被写入应用程序主目录(应用程序 jar文件所在的目录)中的 transaction-logs
目录。通过在 application.properties
文件中设置 spring.jta.log-dir
属性,可以自定义此目录的位置。从 spring.jta.atomikos.properties
开始的属性也可以用于自定义 Atomikos UserTransactionServiceImp
。有关完整的详细信息,参阅A tomikosProperties 文档。
为了确保多个事务管理器可以安全地协调同一个资源管理器,每个 Atomikos 实例都必须配置一个唯一的 ID。默认情况下,此 ID 是运行 Atomikos 的计算机的 IP 地址。为了确保生产中的唯一性,应该为应用程序的每个实例配置
spring.jta.transaction-manager-id
属性,使其具有不同的值。
Bitronix 是一种流行的开源 的JTA 事务管理器实现。可以使用 spring-boot-starter-jta-bitronix
将 Bitronix 依赖项添加到项目中。与 Atomikos 一样,Spring Boot 会自动配置 Bitronix 并对 bean 进行后置处理,以确保启动和关闭顺序正确。
默认情况下,Bitronix 事务日志文件(part1.btm
和 part2.btm
)将写入应用程序主目录中的事务日志目录。可以通过设置 spring.jta.log-dir
属性自定义此目录的位置。以 spring.jta.bitronix.properties
开头的属性也绑定到 bitronix.tm.Configuration
bean,允许完全自定义。有关详细信息,参阅 Bitronix 文档。
为了确保多个事务管理器可以安全地协调相同的资源管理器,必须为每个 Bitronix 实例配置唯一的 ID。默认情况下,此 ID 是运行 Bitronix 的计算机的IP地址。为了确保生产中的唯一性,应该为应用程序的每个实例配置
spring.jta.transaction-manager-id
属性,使其具有不同的值。
如果将 Spring Boot 应用程序打包为 war 或 jar 文件并将其部署到 Java EE 应用服务器,则可以使用应用服务器的内置事务管理器。Spring Boot 试图通过查看常见的 JNDI 位置(java:comp/UserTransaction
、java:comp/TransactionManager
等等)来自动配置事务管理器。如果使用应用服务器提供的事务服务,通常还需要确保所有资源都由服务器管理并通过 JNDI 公开。Spring Boot 尝试通过在 JNDI 路径(java:/JmsXA
或 java:/XAConnectionFactory
)中查找 ConnectionFactory
来自动配置 JMS,你可以使用 spring.datasource.jndi-name
property 属性来配置 DataSource
。
当使用 JTA 时,主JMS ConnectionFactory
bean是 XA-aware,并参与分布式事务。在某些情况下,你可能希望使用非XA ConnectionFactory
来处理某些 JMS 消息。例如,JMS 处理逻辑可能需要比 XA 超时更长的时间。
如果要使用非XA ConnectionFactory
,可以注入非XA jmsConnectionFactory
bean,而不是 @Primary
jmsConnectionFactory
bean。为了保持一致性,jmsConnectionFactory
bean 也通过使用 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;
XAConnectionFactoryWrapper
和 XADataSourceWrapper
接口可用于支持其他嵌入式事务管理器。接口负责包装 XAConnectionFactory
和 XADataSource
bean,并将它们公开为常规的 ConnectionFactory
和 DataSource
bean,它们将被透明地注册到分布式事务中。数据源和 JMS 自动配置使用会 JTA 变量,前提是在 ApplicationContext
中注册了JtaTransactionManager
bean和合适的 XA 包装 bean。
BitronixXAConnectionFactoryWrapper
和 BitronixXADataSourceWrapper
提供了如何编写 XA 包装器的好例子。
如果 Hazelcast 在类路径上,并且找到了合适的配置,那么 Spring Boot会自动配置一个 Hazelcast 实例,你可以在应用程序中注入它。
如果你定义了一个 com.hazelcast.config.Config
bean,那么Spring Boot将使用它。如果你的配置定义了一个实例名,那么 Spring Boot 将尝试定位一个现有实例,而不是创建一个新实例。
你还可以指定要通过配置使用的 Hazelcast 配置文件,如下例所示:
spring.hazelcast.config=classpath:config/my-hazelcast.xml
否则,Spring Boot将尝试从默认位置查找 Hazelcast 配置:工作目录中的 hazelcast.xml
或类路径的根目录中的 hazelcast.xml
,或在相同位置的 .yaml
对应项。还会还检查是否设置了 hazelcast.config
系统属性。有关更多详细信息,参见 Hazelcast 文档。
如果类路径上存在 hazelcast-client
,Spring Boot 将首先通过检查以下配置选项来尝试创建客户端:
存在 com.hazelcast.client.config.ClientConfig
bean。
由 spring.hazelcast.config
属性定义的配置文件。
hazelcast.client.config
系统属性的存在。
工作目录或类路径根目录中的 hazelcast-client.xml
。
工作目录或类路径根目录中的 hazelcast-client.yaml
。
Spring Boot 还对 Hazelcast 提供了显式的缓存支持。如果启用了缓存,
HazelcastInstance
将自动包装在CacheManager
实现中。
Spring Boot 为使用 Quartz 调度程序提供了一些便利,包括 spring-boot-starter-quartz
“starter”。如果 Quartz 可用,则会自动配置调度程序(通过 SchedulerFactoryBean
抽象)。
以下类型的 bean 将自动与调度程序关联:
JobDetail
:定义特定任务。可以使用JobBuilder API构建JobDetail实例。
Calendar
。
Trigger
:定义触发特定任务的时间。
默认情况下,使用内存中的 JobStor
e。但是,如果应用程序中有可用的Datasource
bean,并且相应地配置了 spring.quartz.job-store-type
属性,则可以配置基于 JDBC 的存储,如下例所示:
spring.quartz.job-store-type=jdbc
当使用 JDBC 存储时,模式可以在启动时初始化,如下面的例子所示:
spring.quartz.jdbc.initialize-schema=always
默认情况下,会使用 Quartz 库提供的标准脚本检测和初始化数据库。这些脚本会删除现有的表,在每次重新启动时删除所有触发器。还可以通过设置
spring.quartz.jdbc.schema
来提供自定义脚本。
要让 Quartz 使用应用程序主数据源以外的数据源,需要声明一个 Datasource
bean,用 @QuartDataSource
注解其 @Bean
方法。这样做可以确保 SchedulerFactoryBean
和模式初始化都使用 Quartz 特定的数据源。
默认情况下,由配置创建的任务不会覆盖已从持久任务存储读取的已注册任务。要启用覆盖现有任务定义,需要设置 spring.quartz.overwrite-existing-jobs
属性。
Quartz 调度程序配置可以使用 spring.quartz
属性和 SchedulerFactoryBeanCustomizer
bean 进行自定义,后者允许编程式自定义 SchedulerFactoryBean
。高级 Quartz 配置属性可以使用 spring.Quartz.properties.*
自定义。
Executor
bean与调度器没有关联,因为 Quartz 提供了一种通过spring.quartz.properties
配置调度器的方法。如果需要自定义任务执行器,考虑实现SchedulerFactoryBeanCustomizer
。
任务可以定义 setter 来注入数据映射属性。常规的 bean 也可以以类似的方式注入,如下例所示:
public class SampleJob extends QuartzJobBean {
private MyService myService;
private String name;
// Inject "MyService" bean
public void setMyService(MyService myService) { ... }
// Inject the "name" job data property
public void setName(String name) { ... }
@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
...
}
}
在上下文中没有 Executor
bean的情况下,Spring Boot 会自动配置 ThreadPoolTaskExecutor
,并使用合理的默认值,这些默认值可以自动关联到异步任务执行(@EnableAsync
)和 Spring MVC 异步请求处理。
如果你已经在上下文中定义了一个自定义
Executor
,那么常规任务执行(即@EnableAsync
)将直接使用它,但是 Spring MVC 支持将不会配置,因为它需要一个AsyncTaskExecutor
实现(名为applicationTaskExecutor
)。根据你的目的,你可以将执行程序更改为ThreadPoolTaskExecuto
r,或者定义ThreadPoolTaskExecutor
和包装Executor
的AsyncConfigurer
。自动配置的
TaskExecutorBuilder
能让你轻松地创建实例,重现自动配置在默认情况下所做的事情。
线程池使用 8 个核心线程,这些线程可以根据负载进行增长和收缩。可以使用 spring.task.execution
对这些默认设置进行调整。如下例所示:
spring.task.execution.pool.max-size=16
spring.task.execution.pool.queue-capacity=100
spring.task.execution.pool.keep-alive=10s
这将把线程池更改为使用有界队列,以便当队列满时(100个任务),线程池将增加到最多 16 个线程。当线程空闲 10 秒(而不是默认情况下的60秒)时回收线程,此时池的收缩会更加严重。
如果需要与计划的任务执行相关联,还可以自动配置 ThreadPoolTaskScheduler
(@ EnableScheduling
)。线程池默认使用一个线程,这些设置可以使用 spring.task.scheduling
进行调整。
如果需要创建自定义执行器或调度器,则可以在上下文中使用 TaskExecutorBuilder
bean 和 TaskSchedulerBuilder
bean。
Spring Boot 为使用 Spring Integeration 提供了一些便利,包括 spring-boot-starter-integration
“starter”。Spring Integration 提供了对消息传递和其他传输(如HTTP、TCP等)的抽象。如果你的类路径上有 Spring Integration,那么它将通过 @EnableIntegration
注解进行初始化。
Spring Boot 还配置了一些由其他 Spring Integration 模块触发的特性。如果 spring-integration-jmx
也在类路径上,那么消息处理统计信息将通过 JMX 发布。如果 spring-integration-jdbc
可用,则可以在启动时创建默认数据库架构,如下所示:
spring.integration.jdbc.initialize-schema=always
参见 IntegrationAutoConfiguration
和 IntegrationProperties
类了解更多细节。
默认情况下,如果存在 Micrometer meterRegistry
bean, Spring Integration 指标将由 Micrometer 管理。如果你希望使用遗留的 Spring Integration 指标,要在应用程序上下文中添加一个 DefaultMetricsFactory
bean。
Spring Boot为各种数据存储提供了 Spring Session 自动配置。在构建 Servlet web 应用程序时,可以自动配置以下存储:
在构建响应式 web 应用程序时,可以自动配置以下存储:
Redis
Mongodb
如果类路径上存在单个 Spring Session 模型,Spring Boot 将自动使用该存储实现。如果有多个实现,则必须选择要用于存储会话的存储类型。例如,要使用 JDBC 作为后端存储,可以对应用程序进行如下配置:
spring.session.store-type=jdbc
你可以通过将
store-type
设置为none
来禁用 Spring Session。
每个存储都有特定的附加设置。例如,可以为 JDBC 存储指定表的名称,如下面的例子所示:
spring.session.jdbc.table-name=SESSIONS
可以使用 spring.session.timeout
设置会话的超时时间。如果未设置该属性,则自动配置将回落到 server.servlet.session.timeout
的值。
Java Management Extensions(JMX)提供了监控和管理应用程序的标准机制。Spring Boot 将最合适的 MBeanServer
公开为一个 ID 为 MBeanServer
的 bean。使用Spring JMX 注解(@ManagedResource
、@ManagedAttribute
或 @ManagedOperation
)任何 bean 都将公开给它。
如果平台提供了一个标准的 MBeanServer
,那么 Spring Boot 将使用它,并且在必要时默认为 VM MBeanServer
。如果所有这些都失败了,将创建一个新的 MBeanServer
。
有关更多详细信息,参阅 JmxAutoConfiguration 类。
Spring Boot 在测试应用程序时提供了许多实用的程序和注解。测试支持由两个模块提供:spring-boot-test
包含核心项,spring-boot-test-autoconfigure
支持对测试进行自动配置。
大多数开发人员使用 spring-boot-starter-test
“Starter”,它既导入了 Spring Boot test 模块,也导入 JUnit Jupiter、AssertJ、Hamcrest 和许多其他有用的库。
该 starter 还带来了老式的引擎,因此你可以同时运行JUnit4 和 JUnit5测试。如果你已经将测试迁移到JUnit5,那么应该排除 JUnit4 支持,如下例所示:
<dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-testartifactId> <scope>testscope> <exclusions> <exclusion> <groupId>org.junit.vintagegroupId> <artifactId>junit-vintage-engineartifactId> exclusion> exclusions> dependency>
spring-boot-starter-test
“Starter”(在 test
scope
) 包含以下提供的库:
Spring Boot 发现这些公共库在编写测试时非常有用。如果这些库不适合你的需要,你可以添加你自己的附加测试依赖项。
依赖注入的一个主要优点是它使代码更容易进行单元测试。你可以使用 new
操作符实例化对象,甚至不涉及 Spring。也可以使用 mock 对象而不是实际依赖项。
通常,你需要超越单元测试,来进行集成测试(使用 Spring ApplicationContext
)。Spring Test 是你能够在不需要部署应用程序或连接到其他基础结构的情况下执行集成测试。
Spring Framework 包含了一个专门的集成测试模块。你可以直接向 org.springframework:spring
测试声明一个依赖项,或者使用 ``spring-boot-starter-test` “starter” 以传递方式将其拉入。
如果以前没有使用过 spring-test
模块,那么应该从阅读 Spring Framework 框架参考文档的相关部分开始。
Spring Boot 应用程序实际上是一个 Spring ApplicationContext
,所以除了通常使用普通的 Spring 上下文所做的事情,不需要做什么特别的事情来测试它。
默认情况下,只有在使用
SpringApplication
创建时,才会在上下文中安装 Spring Boot 的外部属性、日志记录和其他特性。
Spring Boot 提供了一个 @SpringBootTest
注解,当你测试时需要 Spring Boot 特性时,它可以作为标准 spring-test
@ContextConfiguration
注解的替代。注解的工作方式是通过 SpringApplication
创建测试中使用的 ApplicationContext
。除了 @SpringBootTest
之外,还提供了一些其他注解,用于测试应用程序的更具体的部分。
如果您正在使用 JUnit4,不要忘记在测试中添加
@RunWith(SpringRunner.class)
,否则该注解将被忽略。如果你正在使用 JUnit 5,则不需要添加与之等价的@ExtendWith(SpringExtension.class)
作为@SpringbootTest
,而其他的@Test
注解已经用它进行了注解。
默认情况下,@SpringBootTest
不会启动服务器。你可以使用 @SpringBootTest
的webEnvironment
属性来进一步细化你的测试运行方式:
MOCK
(默认):加载 web ApplicationContext
并提供 mock web 环境。使用此注解时,嵌入式服务器不会启动。如果类路径上没有可用的 web 环境,则此模式会透明地返回到创建常规的非 web ApplicationContext
。它可以与 @AutoConfigureMockMvc
或 @AutoConfigurewebTestClient
结合使用,对 web 应用程序进行基于 mock 的测试。RANDOM_PORT
:加载WebServerApplicationContext 并提供真实的 web 环境。嵌入式服务器在一个随机端口上启动和监听。DEFINED_PORT
:加载 WebServerApplicationContext
并提供真实的 web 环境。嵌入式服务器在一个定义的端口(来自application.properties
)或默认端口 8080
上启动和监听。NONE
:通过使用 SpringApplication
加载 ApplicationContex
t,但不提供任何 web 环境(mock 或其他)。如果你的测试是
@Transactional
,那么默认情况下,它会在每个测试方法结束时回滚事务。然而,由于对随机端口或定义的端口隐式地提供了一个真正的 servlet 环境,HTTP 客户机和服务器在单独的线程中运行,因此在单独的事务中运行。在这种情况下,服务器上启动的任何事务都不会回滚。
使用
webEnvironment=webEnvironment.RANDOM_PORT
的@SpringBootTest
也将在单独的随机端口上启动管理服务器,如果你的应用程序对管理服务器使用不同的端口。
如果 Spring MVC 可用,则配置一个常规的基于 MVC 的应用程序上下文。如果只有 Spring WebFlux,Spring Boot 将检测它并配置一个基于 WebFlux 的应用程序上下文。
如果两者都存在,则 Spring MVC 优先。如果要在此场景中测试响应性 web 应用程序,必须设置 spring.main.web-application-type
属性:
@SpringBootTest(properties = "spring.main.web-application-type=reactive")
class MyWebFluxTests { ... }
如果你熟悉 Spring 测试框架,那么可以使用 @ContextConfiguration(classes=...)
来指定要加载哪个 Spring @Configuration
。或者,你可能经常在测试中使用的嵌套 @Configuration
类。
在测试 Spring Boot 应用程序时,这通常不是必需的。Spring Boot的 @*Test
注解在你没有显式定义主配置时会自动搜索你的主配置。
搜索算法从包含测试的包开始工作,直到找到用 @SpringBootApplication
或 @SpringBootConfiguration
注解的类为止。只要以合理的方式构造代码,通常都会找到主配置。
如果你使用测试注解测试应用程序的更特殊的部分,则应避免添加特别于主方法的应用程序类上特定区域的配置设置。
@SpringBootApplication
的底层组件扫描配置定义了用于确保切片按预期工作的排除过滤器。如果在@SpringBootApplication
注解类上使用显式的@ComponentScan
指令,这些过滤器将被禁用。如果使用切片,你应该重新定义它们。
如果想自定义主配置,可以使用一个嵌套的 @TestConfiguration
类。与嵌套的 @Configuration
类不同,嵌套的 @TestConfiguration
类是在应用程序的主配置之外使用的。
Spring 的测试框架在测试之间缓存应用程序上下文。因此,只要你的测试共享相同的配置(无论如何发现),加载上下文的潜在耗时过程就只会发生一次。
如果你的应用使用组件扫描(例如,如果使用 @SpringBootApplication
或 @ComponentScan
),你可能会发现,你仅为特定测试创建的顶级配置类会意外地在任何地方出现。
正如前面看到的,可以在测试的内部类上使用 @TestConfiguration
来定制主配置。当放在顶级类上时,@TestConfiguration
表明 src/test/java
中的类不应该通过扫描获得。然后可以在需要的地方显式导入该类,如下面的示例所示:
@SpringBootTest
@Import(MyTestsConfiguration.class)
class MyTests {
@Test
void exampleTest() {
...
}
}
如果你直接使用
@ComponentScan
(不通过@SpringBootApplication
),则需要注册TypeExcludeFilter
。有关详细信息,参见 java 文档。
如果应用程序需要参数,可以使用 args
属性让 @SpringBootTest
注入参数。
@SpringBootTest(args = "--app.test=one")
class ApplicationArgumentsExampleTests {
@Test
void applicationArgumentsPopulated(@Autowired ApplicationArguments args) {
assertThat(args.getOptionNames()).containsOnly("app.test");
assertThat(args.getOptionValues("app.test")).containsOnly("one");
}
}
默认情况下,@SpringBootTest
不会启动服务器。如果你有想要在这个 mock 环境中测试的 web 端点,还可以配置 MockMvc
,如下面的示例所示:
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"));
}
}
如果你只关注 web 层,而不想启动一个完整的
ApplicationContext
,那么可以考虑使用@WebMvcTest
。
此外,你可以配置一个 WebTestClient
,如下面的例子所示:
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");
}
}
在 mock 环境中进行测试通常比使用完整的 Servlet 容器运行要快。但是,由于 mocking 发生在 Spring MVC 层,依赖于低级 Servlet 容器行为的代码不能直接用 MockMvc 测试。
例如,Spring Boot 的错误处理基于 Servlet 容器提供的"错误页面"支持。这意味着,虽然可以按预期测试 MVC 层抛出和处理异常,但不能直接测试是否呈现了特定的自定义错误页。如果需要测试这些较低级别的关注点,可以按照下一节中的说明启动完全运行服务器。
如果需要启动的服务器,建议使用随机端口。如果使用@SpringBootTest(webEnvironment=webEnvironment.RANDOM_PORT)
,则每次运行测试时都会随机选择一个可用端口。
@LocalServerPort
注解可用于将实际使用的端口注入测试。为了方便起见,需要对启动的服务器进行 REST 调用的测试还可以 @Autowire
一个 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 也提供了一个T estRestTemplate
工具:
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");
}
}
自定义 WebTestClient
bean,需要配置 WebTestClientBuilderCustomizer
bean。使用用于创建 WebTestClient
的 WebTestClient.Builder
调用此类的 bean。
当测试上下文框架缓存上下文时,JMX 在默认情况下是禁用的,以防止相同的组件注册在相同的域中。如果这样的测试需要访问 MBeanServer
,考虑将它标记:
@ExtendWith(SpringExtension.class)
@SpringBootTest(properties = "spring.jmx.enabled=true")
@DirtiesContext
class SampleJmxTests {
@Autowired
private MBeanServer mBeanServer;
@Test
void exampleTest() {
// ...
}
}
运行测试时,有时需要在应用程序上下文中模拟某些组件。例如,可能有一个表象覆盖了一些在开发期间不可用的远程服务。当你希望模拟在实际环境中可能难以触发的故障时,mock 也很有用。
Spring Boot 包含一个 @MockBean
注解,可以用来为 ApplicationContext
中的 bean 定义 Mockito 模拟。你可以使用注解添加新的 bean 或替换单个现有 bean 定义。注解可以直接用于测试类、测试中的字段或 @Configuration
类和字段。在字段上使用时,创建的模拟的实例也会被注入。模拟的 bean 在每个测试方法之后自动重置。
如果你的测试使用了 Spring Boot 的一个测试注释(例如
@SpringBootTest
),则会自动启用此功能。要在不同的安排中使用此功能,必须显式地添加一个监听器,如下面的示例所示:@TestExecutionListeners(MockitoTestExecutionListener.class)
下面的示例使用模拟实现替换现有的 RemoteService
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");
}
}
@MockBean
不能用于模拟在应用程序上下文刷新期间执行的 bean 的行为。在执行测试时,应用程序上下文刷新已经完成,现在配置模拟行为已经太晚了。建议在这种情况下使用@Bean
方法来创建和配置 mock。
此外,你可以使用 @SpyBean
将任何现有的 bean 与 Mockito spy
打包在一起。参阅 java 文档以获得完整的细节。
CGLib 代理,例如为作用域 bean 创建的代理,将代理方法声明为
final
。这会阻止 Mockito 正常工作,因为它无法在默认配置中模拟或监视最终方法。如果想模拟或监视这样的 bean,可以通过将org.mockito:mockito-inline
添加到应用程序的测试依赖项中来配置 Mockito。这是允许 Mockito 模拟和监视最终方法。
虽然 Spring 的测试框架在测试之间缓存应用程序上下文,并为共享相同配置的测试重用上下文,但是使用
@MockBean
或@SpyBean
会影响缓存键,这很可能会增加上下文的数量。
如果你使用
@SpyBean
监控具有@Cacheable
方法的 bean,这些方法通过名称引用参数,那么你的应用程序必须使用-parameters
进行编译。这可以确保一旦 bean 被监视后,参数名对缓存基础组件是可用的。
Spring Boot 的自动配置机制对应用的运行良好,但有时对测试来说可能有点太多了。它通常有助于只加载测试应用程序部分所需的配置部分。例如,你可能希望测试 Spring MVC 控制器是否正确映射了 URL,并且你不希望在这些测试中涉及数据库调用,或者你可能希望测试 JPA 实体,并且你对运行这些测试时的 web 层不感兴趣。
spring-boot-test-autoconfigure
模块包括许多自己注解,可以用来自动配置这些部分。它们中的每一个都以类似的方式工作,提供一个加载 ApplicationContext
的 @...Test
注解和一个或多个可用于自定义自动配置设置的 @AutoConfigure...
注解。
每个切片将组件扫描限制到合适的组件,并加载一组非常有限的自动配置类。如果需要排除其中一个,大多数
@...Test
注解都提供excludeAutoConfiguration
属性。或者,可以使用@ImportAutoConfiguration#exclude
。
不支持在一个测试中使用多个
@…Test
注解来包含多个切片。 如果你需要多个"切片’’,可选择@ ...Test
注解之一,并手动添加其他切片的@AutoConfigure ...
注解。
也可以将
@AutoConfigure...
注解与标准的@SpringBootTest
注解一起使用。如果你对应用程序的切片不感兴趣,但需要一些自动配置的测试 bean,则可以使用此组合。
要测试对象JSON序列化和反序列化是否如预期的那样工作,可以使用 @JsonTest
注解。@JsonTest
自动配置支持的 JSON 映射,它可以是以下库之一:
Jackson ObjectMapper
、任何 @JsonComponent
bean和任何 Jackson 模块
Gson
Jsonb
可以在附录中找到由
@JsonTest
启用的自动配置列表。
如果你需要配置自动配置的元素,您可以使用 @AutoConfigureJsonTesters
注解。
Spring Boot 包括基于 AssertJ 的辅助程序,它们与 JSONAssert 和 JsonPath 库一起工作,以检查 JSON 是否按预期显示。JacksonTester
、GsonTester
、JsonbTester
和 BasicJsonTester
类可以分别用于Jackson、Gson、Jsonb 和 String。在使用 @JsonTest
时,可以 @Autowired
测试类中的任何帮助字段。下面的例子显示了Jackson 的一个测试类:
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");
}
}
JSON 帮助类也可以直接用于标准单元测试。为此,如果不使用
@JsonTest
,要在@Before
方法中调用辅助程序的initFields
方法。
如果使用 Spring Boot 的基于 AssertJ 的辅助程序对给定 JSON 路径上的数值进行断言,则可能无法根据类型使用 isEqualTo
。相反,你可以使用 AssertJ 的 satisfies
来断言值与给定条件是否匹配。例如,下面的示例断言实际数字是一个浮动值,接近 0.15
,偏移量为 0.01
:
assertThat(json.write(message))
.extractingJsonPathNumberValue("@.test.numberValue")
.satisfies((number) -> assertThat(number.floatValue()).isCloseTo(0.15f, within(0.01f)));
要测试 Spring MVC 控制器是否按预期工作,使用 @WebMvcTest
注解。@WebMvcTest
自动配置 Spring MVC 基础组件,并将扫描的 bean 限制为 @Controller
、@ControllerAdvice
、@JsonComponent
、Converter
、GenericConverter
、Filter
、HandlerInterceptor
、WebMvcConfigurer
和 HandlerMethodArgumentResolver
。在使用这个注解时,不会扫描常规的 @Component
bean。
可以在附录中找到由
@WebMvcTest
启用的自动配置设置列表。
如果你需要注册额外的组件,比如 Jackson 模块,可以在测试中使用
@Import
导入额外的配置类。
通常,@WebMvcTest
被限制在单个控制器中,并与 @MockBean
结合使用,为所需的协作者提供模拟实现。
@WebMvcTest
也会自动配置 MockMvc
。Mock MVC 提供了一种强大的方法来快速测试 MVC 控制器,而不需要启动完整的 HTTP 服务器。
你还可以在非
@WebMvcTest
(例如@SpringBootTest
)中使用@AutoConfigureMockMvc
对MockMvc
进行注解,从而自动配置MockMvc
。下面的例子使用了MockMvc
:
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"));
}
}
如果需要配置自动配置的元素(例如,当应用 servlet 过滤器时),可以使用
@AutoConfigureMockMvc
注解中的属性。
如果你使用 HtmlUnit 或 Selenium, 自动配置机制还提供了一个 HtmlUnit WebClient
bean和/或 Selenium WebDriver
bean。下面的例子使用 HtmlUnit:
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");
}
}
默认情况下,Spring Boot 将
WebDriver
bean放在一个特殊的作用域中,以确保驱动程序在每次测试之后退出,并注入一个新实例。如果你不想要这种行为,你可以将@Scope("singleton")
添加到你的WebDriver
@Bean定义中。
Spring Boot创建的
webDriver
作用域将替换任何用户定义的同名作用域。如果你定义了你自己的webDriver
范围,你可能会发现当你使用@WebMvcTest
时它停止了工作。
如果类路径上有Spring Security,@WebMvcTest
还将扫描 WebSecurityConfigurer
bean。你可以使用 Spring Security 的测试支持,而不是完全禁用此类测试的安全性。有关如何使用Spring Security 的 MockMvc
支持的更多详细信息,参阅 how-to.html 部分。
有时仅仅编写 Spring MVC 测试是不够的,Spring Boot 可以帮助你在实际服务器上运行完整的端到端测试。
要测试 Spring WebFlux 控制器是否按预期工作,可以使用 @WebFluxTest
注解。 @WebFluxTest
自动配置 Spring WebFlux 基础组件,并将扫描的 bean 限制为 @Controller
、@ControllerAdvice
、@JsonComponent
、Converter
、GenericConverter
、WebFilter
和 WebFluxConfigurer
。使用 @WebFluxTest
注解时,不会扫描常规的 @Component
bean。
可以在附录中找到由
@WebFluxTest
启用的自动配置列表。
如果你需要注册额外的组件,比如 Jackson 模块,可以在测试中使用
@Import
导入额外的配置类。
通常,@WebFluxTest
被限制在单个控制器中,并与 @MockBean
注解结合使用,为所需的协作者提供模拟实现。
@WebFluxTest
还自动配置了 WebTestClient
,它提供了一种强大的方法来快速测试 WebFlux 控制器,而不需要启动一个完整的 HTTP 服务器。
你还可以在非
@WebFluxTest
(例如@SpringBootTest
)中使用@AutoConfigureWebTestClient
对WebTestClient
进行注解,从而自动配置WebTestClient
。下面的例子展示了一个同时使用@WebFluxTest
和WebTestClient
的类:
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");
}
}
这个设置只被 WebFlux 应用程序支持,因为在一个模拟的 web 应用程序中使用
WebTestClient
目前只适用于 WebFlux。
@WebFluxTest
无法检测通过函数式 web 框架注册的路由。要在上下文中测试RouterFunction
bean,可以考虑自己通过@Import
或@SpringBootTest
导入RouterFunction
。
@WebFluxTest
无法检测通过SecurityWebFilterChain
类型的@Bean
注册的自定义安全配置。要在测试中包含它,需要导入通过@Import
或使用@SpringBootTest
注册 bean 的配置。
有时仅仅编写 Spring WebFlux`测试是不够的,Spring Boot可以帮助你在实际服务器上运行完整的端到端测试。
Spring Boot 为嵌入式 Tomcat、Jetty 和 Undertow 提供 WebSockets 自动配置。如果你将一个 war 文件部署到一个独立的容器中,Spring Boot 假设该容器负责其 WebSocket 支持的配置。
Spring 框架为 MVC web 应用程序提供了丰富的 WebSocket 支持,这些应用程序可以通过 spring-boot-starter-websocket
模块轻松访问。
WebSocket 支持也可用于响应式 web 应用程序,需要在spring-boot-starter-webflux
中包含WebSocket API:
<dependency>
<groupId>javax.websocketgroupId>
<artifactId>javax.websocket-apiartifactId>
dependency>
Spring Boot 提供了 Web 服务自动配置,因此你只需定义端点。
使用 spring-boot-starter-webservices
模块可以很容易地访问 Spring Web 服务特性。
可以分别为 WSDLs 和 XSD 自动创建SimpleWsdl11Definition
定义和 SimpleXsdSchema
bean。为此,要配置它们的位置,如下例所示:
spring.webservices.wsdl-locations=classpath:/wsdl
如果需要从应用程序调用远程 Web 服务,可以使用 WebServiceTemplate
类。由于 WebServiceTemplate
实例通常需要在使用前进行自定义,所以 Spring Boot 不提供任何自动配置的 WebServiceTemplatebean
。但是,它会自动配置 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
使用类路径上可用的 HTTP 客户端库检测一个合适的基于 HTTP 的 WebServiceMessageSender
。你自定义读取和连接超时如下:
@Bean
public WebServiceTemplate webServiceTemplate(WebServiceTemplateBuilder builder) {
return builder.messageSenders(new HttpWebServiceMessageSenderBuilder()
.setConnectTimeout(5000).setReadTimeout(2000).build()).build();
}
如果你在开发共享库的公司工作,或者你在开源或商用库上工作,则可能需要开发自己的自动配置。自动配置类可以捆绑在外部 jar 中,仍然可以由 Spring Boot 获取。
自动配置可以关联到一个 “starter”,它提供自动配置代码以及将与之一起使用的典型库。首先介绍构建自己的自动配置所需的知识,然后继续介绍创建自定义启动程序所需的典型步骤。
在底层,自动配置是用标准的 Configuration
类实现的。附加的 @Conditional
注解用于约束何时应用自动配置。通常,自动配置类使用 @ConditionalOnClass
和 @ConditionalOnMissingBean
注解。这将确保只有在找到相关类并且尚未声明自己的 @Configuration
时,才应用自动配置。
你可以浏览 spring-boot-auto-configure
的源代码,查看 Spring 提供的 @Configuration
类(参见 META-INF/spring.factories
文件)。
Spring 检查是否存在 META-INF/spring.factories
文件在你发布的 jar 中。该文件应该在 EnableAutoConfiguration
键下列出你的配置类,如下面的示例所示:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.mycorp.libx.autoconfigure.LibXAutoConfiguration,\
com.mycorp.libx.autoconfigure.LibXWebAutoConfiguration
自动配置只能以这种方式加载。确保它们是在特定的包空间中定义的,并且它们绝不是组件扫描的目标。此外,自动配置类不应启用组件扫描以查找其他组件。应该使用特定的
@import
。
如果需要按特定顺序应用配置,则可以使用 @AutoConfigureAfter
或@AutoConfigureBefore
注解。例如,如果提供特定于 web 的配置,则可能需要在 WebMvcAutoConfiguration
之后应用类。
如果你想订购某些不应该相互直接了解的自动配置,也可以使用 @AutoConfigureOrder
。该注解与常规的 @Order
注解具有相同的语义,但为自动配置类提供了专用的顺序。
你几乎总是希望在自动配置类中包含一个或多个 @Conditional
注解。@ConditionalOnMissingBean
注解是一个常见的示例,用于允许开发人员在对默认值不满意时重写自动配置。
Spring Boot 包含许多 @Conditional
注解,你可以通过注解 @Configuration
类或单个 @Bean
方法在自己的代码中重用这些注解。这些注解包括:
@ConditionalOnClass
和 @ConditionalOnMissingClass
注解允许 @Configuration
类基于特定类的存在或不存在而被包含。由于注解元数据是使用 ASM 解析的,因此可以使用 value
属性来引用实际的类,即使该类可能不会实际出现在正在运行的应用程序类路径上。如果希望使用 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() { ... }
}
}
如果你使用
@ConditionalOnClass
或@ConditionalOnMissingClass
作为元注解的一部分来组成自己的复合注释,那么在这种情况下,必须使用名称来引用类。
@ConditionalOnBean
和 @ConditionalOnMissingBean
注解允许根据特定 bean 的存在或不存在来包含 bean。可以使用 value
属性按类型指定 bean,也可以使用 name
指定bean。 search
属性允许你限制在搜索 bean 时应该考虑的 ApplicationContext
层次结构。
当放置在 @Bea
n方法上时,目标类型默认为方法的返回类型,如下面的例子所示:
@Configuration(proxyBeanMethods = false)
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyService myService() { ... }
}
在前面的示例中,如果 ApplicationContext
中不包含 MyService
类型的bean,则将创建 myService
bean。
你需要非常注意添加 bean 定义的顺序,因为这些条件是基于到目前为止所处理的内容进行评估的。由于这个原因,建议在自动配置类上只使用
@ConditionalOnBean
和@ConditionalOnMissingBean
注解(因为这些注解保证在添加任何用户定义的 bean 定义之后加载)。
@ConditionalOnBean
和@ConditionalOnMissingBean
不会阻止创建@Configuration
类。在类级别使用这些条件和用注解标记每个包含@Bean
的方法之间的唯一区别是,前者防止在条件不匹配时将@Configuration
类注册为bean。
@ConditionalOnProperty
注解允许基于 Spring 环境属性进行配置。使用 prefix
和 name
属性指定应该检查的属性。默认情况下,存在且不等于 false
的任何属性都会被匹配。还可以使用 havingValue
和 matchIfMissing
属性创建更高级的检查。
@ConditionalOnResource
注解只允许在存在特定资源时包含配置。可以使用通常的 Spring 约定来指定资源,如下面的示例所示:file:/home/user/test.dat
。
据应用程序是否为 “web 应用程序”,@ConditionalOnWebApplication
和 @ConditionalOnNotWebApplication
允许是否包括配置。基于 servlet 的 web 应用程序是使用 Spring WebApplicationContext
、定义 seesion
范围或具有 ConfigurableWebEnvironment
的任意应用程序。响应式web 应用程序是使用 ReactiveWebApplicationContext
或具有可配置 ReactiveWebApplicationContext
的任意应用程序。
@ConditionalOnExpression
注解允许基于 SpEL 表达式的结果进行配置。
自动配置可能受到许多因素的影响:用户配置(@Bean
定义和 Environment
自定义)、条件评估(特定库的存在)等等。具体来说,每个测试都应该创建一个定义良好的 ApplicationContext
,它表示这些定制的组合。ApplicationContextRunner
提供了一个很好的方法来实现这一点。
ApplicationContextRunner
通常定义为测试类的一个字段,用于收集基本的公共配置。下面的示例确保总是调用 UserServiceAutoConfiguration
:
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(UserServiceAutoConfiguration.class));
如果必须定义多个自动配置,则不需要按照与运行应用程序时完全相同的顺序调用它们的声明。
每个测试都可以使用运行者来表示一个特定的用例。例如,下面的示例调用一个用户配置(UserConfiguration
)并检查自动配置是否正确地回退。调用 run
提供了一个可以与 Assert4J
一起使用的回调上下文。
@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");
});
}
还可以使用运行者展示 ConditionEvaluationReport
。报告可以在 INFO
或 DEBUG
级别打印。下面的示例显示如何使用 ConditionEvaluationReportLoggingListener
在自动配置测试中打印报告。
@Test
public void autoConfigTest {
ConditionEvaluationReportLoggingListener initializer = new ConditionEvaluationReportLoggingListener(
LogLevel.INFO);
ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withInitializer(initializer).run((context) -> {
// Do something...
});
}
如果需要测试只在 servlet 或响应式 web 应用程序上下文中运行的自动配置,可分别使用 WebApplicationContextRunner
或 ReactiveWebApplicationContextRunner
。
还可以测试当特定类和/或包在运行时不存在时会发生什么。Spring Boot 附带一个 FilteredClassLoader
,运行器可以很容易地使用它。在下面的例子中,断言如果 UserService
不存在,自动配置将被正确地禁用:
@Test
void serviceIsIgnoredIfLibraryIsNotPresent() {
this.contextRunner.withClassLoader(new FilteredClassLoader(UserService.class))
.run((context) -> assertThat(context).doesNotHaveBean("userService"));
}
你需要确保为启动程序提供正确的名称空间。不要用 spring-boot
启动你的模块名,即使使用的是不同的 Maven groupId
。Spring Boot 以后可能会为您自动配置的东西提供官方支持。
根据经验,你应该在启动程序之后命名组合模块。例如,假设你正在为 “acme” 创建一个启动程序,并将自动配置模块命名为 acme-spring-boot-autoconfigure
,将启动程序命名为 acme-spring-boot-starter
。如果只有一个模块组合了这两个模块,那么将其命名为 acme-spring-boot-starter
。
如果启动程序提供了配置键,那么为它们使用唯一的名称空间。特别是,不要在 Spring Boot 使用的名称空间中包含键(如 server
、management
、spring
等)。如果你使用相同的名称空间,Spring Boot 将来可能会以破坏模块的方式修改这些名称空间。根据经验,可以在所有键的前面加上自己的名称空间(例如 acme
)。
确保通过为每个属性添加字段 Javadoc 来记录配置键,如下面的示例所示:
@ConfigurationProperties("acme")
public class AcmeProperties {
/**
* Whether to check the location of acme resources.
*/
private boolean checkLocation = true;
/**
* Timeout for establishing a connection to the acme server.
*/
private Duration loginTimeout = Duration.ofSeconds(3);
// getters & setters
}
你应该只使用带有
@ConfigurationProperties
字段 Javadoc 的简单文本,因为它们在被添加到 JSON 之前不会被处理。
下面是一些 Spring Boot 内部遵循的规则,以确保描述是一致的:
java.time.Duration
,而不是 long
,如果它不是毫秒,那么要说明单位。要确保触发元数据生成,以便 IDE 插件也可用于你的键。你可能需要查看生成的元数据(META-INF/spring configuration metadata.json
),以确保你的键有正确的文档记录。在兼容的 IDE 中使用自己的 starter 也是验证元数据质量的好主意。
autoconfigure
模块包含启动库所需的所有内容。它还可能包含配置键定义(例如 @ConfigurationProperties
)和任何回调接口,可以使用这些回调接口进一步定制组件的初始化方式。
你应该将库的依赖项标记为可选,这样就可以在项目中更轻松地包含
autoconfigure
模块。如果这样做,则不提供库,并且默认情况下,Spring Boot 会回退。
Spring Boot 使用一个注解处理器来收集元数据文件中关于自动配置的条件(META-INF/ spring-autoconfigure-metada.properties
)。如果存在该文件,则使用它来过滤不匹配的自动配置,这将优化启动时间。建议在包含自动配置的模块中添加以下依赖项:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-autoconfigure-processorartifactId>
<optional>trueoptional>
dependency>
在 Gradle4.5 及更早版本中,依赖项应该在 compileOnly
配置中声明,如下例所示:
dependencies {
compileOnly "org.springframework.boot:spring-boot-autoconfigure-processor"
}
在 Gradle4.6 及更高版本中,依赖项应该在 annotationProcessor
配置中声明,如下例所示:
dependencies {
annotationProcessor "org.springframework.boot:spring-boot-autoconfigure-processor"
}
Kotlin 是一种针对 JVM(和其他平台)的静态类型语言,它允许编写简洁优雅的代码,同时提供与用 Java 编写的现有库的互操作性。
Spring Boot 通过利用其他 Spring 项目(如Spring Framework、Spring Datasource 和 Reactor)中的支持来提供 Kotlin 支持。有关更多信息,参阅 Spring Framework Kotlin支持文档。
从 Spring Boot 和 Kotlin 开始最简单的方法就是遵循这个全面的教程。你可以通过start.spring.io 创建新的 Kotlin 项目。如果需要支持,可以加入Kotlin Slack 的 #spring 通道,或者在堆栈溢出时使用 spring
和 kotlin
标记进行分析。
Spring Boot支持 Kotlin 1.3.x。要使用 Kotlin,org.jetbrains.Kotlin:kotlin-stdlib
和 org.jetbrains.Kotlin:kotlin-reflect
必须出现在类路径上。也可以使用 kotlin-stdlib
变体 kotlin-stdlib-jdk7
和 kotlin-stdlib-jdk8
。
由于 Kotlin 类在默认情况下是不可变的,所以你可能希望配置 kotlin-spring 插件,来自动打开 Spring 注解类,以便可以代理它们。
在 Kotlin 中序列化/反序列化 JSON 数据需要 Jackson 的 Kotlin 模块。在类路径上找到时,它会自动注册。如果 Jackson 和 Kotlin 存在,但Jackson Kotlin模块不存在,则会记录一条警告消息。
如果在 start.spring.io 上引导 Kotlin 项目,则默认情况下会提供相关依赖项和插件。
Kotlin的一个关键特性是空值安全。它在编译时处理 null
,而不是将问题推迟到运行时并直到 NullPointerException
。这有助于消除常见的错误源,而不必像 Optional
那样支付包装器的成本。Kotlin 还允许使用函数构造,其值可以为空,如 Kotlin 中的空安全性综合指南所述。
尽管 Java 不允许在其类型系统中表示空安全,但是 Spring Framwork、Spring Data 和 Reacto r现在通过工具友好的注解提供了 API 的空安全性。默认情况下,Kotlin 中使用的Java API 中的类型被识别为松散型空检查的平台类型。Kotlin 对 JSR 305 注解和可空性注释的支持为 Kotlin 中相关的 Spring API 提供了空安全性。
JSR 305 检查可以通过添加带有以下选项的 -Xjsr305
编译器标志来配置:-Xjsr305={strict | warn | ignore}
。默认行为与 -Xjsr305=warn
相同。strict
值要求在从 Spring API 推断的 Kotlin 类型中考虑 空安全性,但应在使用时知道 Spring API 可空性声明可能会在较小的版本之间演变,并且将来可能会添加更多的检查。
目前还不支持泛型类型参数、varargs 和数组元素的可空性。有关最新信息,参阅 SPR-15942。
Spring Boot 提供了一种使用 runApplication
运行应用程序的常用方法,如下面的示例所示:
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)
}
Kotlin 扩展提供了用附加功能扩展现有类的能力。Spring Boot Kotlin API 利用这些扩展为现有 API 添加新的 Kotlin 特有的便利性。
提供了 TestRestTemplate
扩展,类似于 Spring Framework 中用于 RestOperations
的 Spring Framework 提供的扩展。 除其他事项外,这些扩展使利用 Kotlin 修饰类型参数成为可能。
为了避免在类路径上混合不同版本的Kotlin依赖项,Spring Boot 导入 Kotlin BOM。
使用 Maven,可以通过 kotlin.version
属性自定义 Kotlin 版本,并为 kotlin-maven-plugin
提供插件管理。使用 Gradle,Spring Boot 插件会自动将 kotlin.version
与 Kotlin插件的版本对齐。
Spring Boot 还通过导入 Kotlin 协程 BOM 来管理协程依赖项的版本。可以通过 kotlin-coroutines.version
属性自定义版本。
kotlinx:kotlinx coroutines-reactor
依赖项在默认情况下是提供的,如果一个引导一个 Kotlin 项目,并且至少有一个对 start.spring.io 的对应依赖项。
@ConfigurationProperties
与 @ConstructorBinding
结合使用时,支持具有不可变 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
)
}
要使用注解处理器生成自己的元数据,
kapt
应该配置spring-boot-configuration-processor
依赖项。注意,由于kapt
模型中的限制,一些特性(如检测默认值或不推荐的项)无法工作。
虽然可以使用 JUnit4 测试 Kotlin 代码,但 JUnit5 是默认提供的,建议使用。JUnit5 允许一个测试类被实例化一次,并为该类的所有测试重用。这使得可以在非静态方法上使用 @BeforeClass
和 @AfterClass
注解,这非常适合Kotlin。
JUnit5 是默认的,vintage
引擎是为向后兼容 JUnit4 而提供的。如果不使用它,请排除org.junit.vintange:junit vintage
引擎。你还需要将测试实例生命周期切换到 “pre-class”。
为了模拟 Kotlin 类,建议使用 MockK。如果需要 Mockk
等价于 Mockito
特定的 @MockBean
和 @SpyBean
注解,可以使用 SpringMockK,它提供了类似的 @MockBean
和 @SpykBean
注解。
spring
and kotlin
tags如果你想进一步了解本节讨论的任何类,可以查看 Spring Boot API 文档或直接浏览源代码。如果你有特定的问题,可查看“操作”部分。
如果你对 Spring Boot 的核心功能感到满意,那么可以继续阅读有关生产就绪功能的内容。