添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
  • 2.8.2. 构造函数绑定
  • 2.8.3. 启用 @ConfigurationProperties 注解的类型
  • 2.8.4. 使用 @ConfigurationProperties 注解类型
  • 2.8.5. 第三方配置
  • 2.8.6. 宽松绑定
  • 2.8.7. 合并复杂类型
  • 2.8.8. 属性转换
  • 转换 duration
  • 转换 Data Size
  • 2.8.9. @ConfigurationProperties 验证
  • 2.8.10. @ConfigurationProperties @Value 对比
  • 7.1.1. Spring MVC 自动配置
  • 7.1.2. HttpMessageConverters
  • 7.1.3. 自定义 JSON Serializer 和 Deserializer
  • 7.1.4. MessageCodesResolver
  • 7.1.5. 静态内容
  • 7.1.6. 欢迎页面
  • 7.1.7. 自定义 Favicon
  • 7.1.8. 路径匹配与内容协商
  • 7.1.9. ConfigurableWebBindingInitializer
  • 7.1.10. 模板引擎
  • 7.1.11. 错误处理
  • 自定义错误页面
  • 映射到 Spring MVC 之外的错误页面
  • 7.1.12. Spring HATEOAS
  • 7.1.13. CORS 支持
  • 7.2. Spring WebFlux 框架
  • 7.2.1. Spring WebFlux 自动配置
  • 7.2.2. 使用 HttpMessageReader 和 HttpMessageWriter 作为 HTTP 编解码器
  • 7.2.3. 静态内容
  • 7.2.4. 模板引擎
  • 7.2.5. Error Handling
  • 自定义错误页面
  • 7.2.6. Web 过滤器
  • 7.3. JAX-RS 与 Jersey
  • 7.4. 内嵌 Servlet 容器支持
  • 7.4.1. Servlets, Filters, 与 listeners
  • 将 Servlet、Filter 和 Listener 注册为 Spring
  • 7.4.2. Servlet 上下文初始化
  • 扫描 Servlet、Filter 和 Listener
  • 7.4.3. ServletWebServerApplicationContext
  • 7.4.4. 自定义内嵌 Servlet 容器
  • 以编程方式自定义
  • 直接自定义 ConfigurableServletWebServerFactory
  • 7.4.5. JSP 局限
  • 7.5. 内嵌响应式服务器支持
  • 7.6. 响应式服务器资源配置
  • 8. RSocket
  • 8.1. RSocket策略自动配置
  • 8.2. RSocket服务器自动配置
  • 8.3. Spring Messaging RSocket支持
  • 8.4. 使用 RSocketRequester 调用RSocket服务
  • 9. 安全
  • 9.1. MVC 安全
  • 9.2. WebFlux 安全
  • 9.3. OAuth2
  • 9.3.1. 客户端
  • OAuth2 客户端注册常见的提供者
  • 9.3.2. 资源服务器
  • 9.3.3. 授权服务器
  • 9.4. SAML 2.0
  • 9.4.1. 依赖方
  • 9.5. Actuator 安全
  • 9.5.1. 跨站请求伪造保护
  • 11.5.1. 使用 REST 客户端连接 Elasticsearch
  • 11.5.2. 使用 Reactive REST 客户端连接
  • 11.5.3. 使用 Jest 连接 Elasticsearch
  • 11.5.4. 使用 Spring Data 连接 Elasticsearch
  • 11.5.5. Spring Data Elasticsearch 资源库
  • 11.6. Cassandra
  • 11.6.1. 连接 Cassandra
  • 11.6.2. Spring Data Cassandra 资源库
  • 11.7. Couchbase
  • 11.7.1. 连接 Couchbase
  • 11.7.2. Spring Data Couchbase 资源库
  • 11.8. LDAP
  • 11.8.1. 连接 LDAP 服务器
  • 11.8.2. Spring Data LDAP 资源库
  • 11.8.3. 内嵌内存式 LDAP 服务器
  • 11.9. InfluxDB
  • 11.9.1. 连接 InfluxDB
  • 使用 Mock MVC 自动配置的Spring REST Docs测试
  • 使用 WebTestClient 自动配置的Spring REST Docs测试
  • 使用 RES TAssured 自动配置的Spring REST Docs测试
  • 25.3.24. 其他的自动配置和切片
  • 25.3.25. 用户配置和切片
  • 25.3.26. 使用Spock测试Spring Boot应用程序
  • 25.4. 测试实用工具
  • 25.4.1. ConfigFileApplicationContextInitializer
  • 25.4.2. TestPropertyValues
  • 25.4.3. OutputCapture
  • 25.4.4. TestRestTemplate
  • public static void main(String[] args) {
        SpringApplication.run(MySpringConfiguration.class, args);
    

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

      .   ____          _            __ _ _
     /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
    ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
     \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
      '  |____| .__|_| |_|_| |_\__, | / / / /
     =========|_|==============|___/=/_/_/_/
     :: Spring Boot ::   v2.2.5.RELEASE
    2019-04-31 13:09:54.117  INFO 56603 --- [           main] o.s.b.s.app.SampleApplication            : Starting SampleApplication v0.1.0 on mycomputer with PID 56603 (/apps/myapp.jar started by pwebb)
    2019-04-31 13:09:54.166  INFO 56603 --- [           main] ationConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6e5a8246: startup date [Wed Jul 31 00:08:16 PDT 2013]; root of context hierarchy
    2019-04-01 13:09:56.912  INFO 41370 --- [           main] .t.TomcatServletWebServerFactory : Server initialized with port: 8080
    2019-04-01 13:09:57.501  INFO 41370 --- [           main] o.s.b.s.app.SampleApplication            : Started SampleApplication in 2.992 seconds (JVM running for 3.658)

    默认情况下,将显示 INFO 级别的日志信息,包括一些应用启动相关信息. 如果您需要修改 INFO 日志级别,请参考日志等级.

    使用主应用程序类包中的实现版本来确定应用程序版本. 可以通过将 spring.main.log-startup-info 设置为 false 来关闭启动信息记录. 这还将关闭对应用程序 active 配置文件的日志记录.

    如果没有失败分析器能够处理的异常,您仍然可以显示完整的条件报告以便更好地了解出现的问题. 为此,您需要针对 org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener 启用 debug 属性 或者开启 DEBUG 日志.

    例如,如果您使用 java -jar 运行应用,可以按以下方式启用 debug 属性:

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

    1.2. 延迟初始化

    SpringApplication 允许延迟地初始化应用程序. 启用延迟初始化后,将根据需要创建bean,而不是在应用程序启动期间创建bean. 因此,启用延迟初始化可以减少应用程序启动所需的时间. 在Web应用程序中,启用延迟初始化将导致许多与Web相关的Bean直到收到HTTP请求后才被初始化.

    延迟初始化的缺点是,它可能会延迟发现应用程序问题的时间. 如果错误配置的Bean延迟初始化,则启动期间将不再发生故障,并且只有在初始化Bean时问题才会变得明显. 还必须注意确保JVM有足够的内存来容纳所有应用程序的bean,而不仅仅是启动期间初始化的bean. 由于这些原因,默认情况下不会启用延迟初始化,因此建议在启用延迟初始化之前先对JVM的堆大小进行微调.

    可以使用 SpringApplicationBuilder 上的 lazyInitialization 方法或 SpringApplication 上的 setLazyInitialization 方法以编程方式启用延迟初始化. 另外,可以使用 spring.main.lazy-initialization 属性启用它,如以下示例所示:

    spring.main.lazy-initialization=true

    1.3. 自定义 banner

    可以通过在 classpath 下添加一个 banner.txt 文件,或者将 spring.banner.location 属性指向该文件的位置来更改启动时打印的 banner. 如果文件采用了非 UTF-8 编码,您可以设置 spring.banner.charset 来解决. 除了文本文件, 您还可以将 banner.gifbanner.jpg 或者 banner.png 图片文件添加到 classpath 下,或者设置 spring.banner.image.location 属性. 指定的图片将会被转换成 ASCII 形式并打印在 banner 文本上方.

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

    Table 1. Banner 变量

    ${application.version}

    您的应用版本号,声明在 MANIFEST.MF 中. 例如,Implementation-Version: 1.0 将被打印为 1.0.

    ${application.formatted-version}

    您的应用版本号,声明在 MANIFEST.MF 中,格式化之后打印 (用括号括起来,以 v 为前缀) ,例如 (v1.0).

    ${spring-boot.version}

    您使用的 Spring Boot 版本. 例如 2.2.5.RELEASE.

    ${spring-boot.formatted-version}

    您使用的 Spring Boot 版本格式化之后显示 (用括号括起来,以 v 为前缀) . 例如 (v2.2.5.RELEASE).

    ${Ansi.NAME} (or ${AnsiColor.NAME}, ${AnsiBackground.NAME}, ${AnsiStyle.NAME})

    其中 NAME 是 ANSI 转义码的名称. 有关详细信息,请参阅 AnsiPropertySource.

    ${application.title}

    您的应用标题,声明在 MANIFEST.MF 中,例如 Implementation-Title: MyApp 打印为 MyApp.

    您还可以使用 spring.main.banner-mode 属性来确定是否必须在 System.out (console) 上打印 banner,还是使用日志记录器 (log)或者都不打印(off).

    打印的 banner 被注册名为 springBootBanner 的单例 bean.

    1.4. 自定义 SpringApplication

    如果 SpringApplication 的默认设置不符合您的想法,您可以创建本地实例进行定制化. 例如,要关闭 banner,您可以这样:

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

    1.5. Fluent Builder API

    如果您需要构建一个有层级关系的 ApplicationContext (具有父/子关系的多上下文) ,或者偏向使用 fluent (流式) 构建器 API,可以使用 SpringApplicationBuilder.

    SpringApplicationBuilder 允许您链式调用多个方法,包括能创建出具有层次结构的 parentchild 方法.

    new SpringApplicationBuilder()
            .sources(Parent.class)
            .child(Application.class)
            .bannerMode(Banner.Mode.OFF)
            .run(args);

    ApplicationContext 创建之前,实际上触发了一些事件,因此您不能像 @Bean 一样注册监听器. 您可以通过 SpringApplication.addListeners(​…​) 或者 SpringApplicationBuilder.listeners(…​​) 方法注册它们. 如果您希望无论应用使用何种创建方式都能自动注册这些监听器,您都可以将 META-INF/spring.factories 文件添加到项目中,并使用 org.springframework.context.ApplicationListener 属性键指向您的监听器. 比如: org.springframework.context.ApplicationListener=com.example.project.MyListener

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

    准备 ApplicationContext 并调用 ApplicationContextInitializers 之后但在加载任何bean定义之前,将发送 ApplicationContextInitializedEvent.

    开始刷新之前,bean 定义被加载之后发送 ApplicationPreparedEvent.

    在上下文刷新之后且所有的应用和命令行运行器 (command-line runner) 被调用之前发送 ApplicationStartedEvent.

    在应用程序和命令行运行器 (command-line runner) 被调用之后,将发出 ApplicationReadyEvent,该事件用于通知应用已经准备处理请求.

    如果启动时发生异常,将发送 ApplicationFailedEvent.

    应用程序事件发送使用了 Spring Framework 的事件发布机制. 该部分机制确保在子上下文中发布给监听器的事件也会发布给所有祖先上下文中的监听器. 因此,如果您的应用程序使用有层级结构的 SpringApplication 实例,则监听器可能会收到同种类型应用程序事件的多个实例.

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

    1.7. Web 环境

    SpringApplication 试图为您创建正确类型的 ApplicationContext. 确定 WebApplicationType 的算法非常简单:

    如果 Spring MVC 不存在且存在 Spring WebFlux,则使用 AnnotationConfigReactiveWebServerApplicationContext

    否则,使用 AnnotationConfigApplicationContext

    这意味着如果您在同一个应用程序中使用了 Spring MVC 和 Spring WebFlux 中的新 WebClient,默认情况下将使用 Spring MVC. 您可以通过调用 setWebApplicationType(WebApplicationType) 修改默认行为.

    也可以调用 setApplicationContextClass(…​) 来完全控制 ApplicationContext 类型.

    import org.springframework.boot.*;
    import org.springframework.beans.factory.annotation.*;
    import org.springframework.stereotype.*;
    @Component
    public class MyBean {
        @Autowired
        public MyBean(ApplicationArguments args) {
            boolean debug = args.containsOption("debug");
            List<String> files = args.getNonOptionArgs();
            // if run with "--debug logfile.txt" debug=true, files=["logfile.txt"]
    

    1.9. 使用 ApplicationRunner 或 CommandLineRunner

    如果您需要在 SpringApplication 启动时运行一些代码,可以实现 ApplicationRunner 或者 CommandLineRunner 接口. 这两个接口的工作方式是一样的,都提供了一个单独的 run 方法,它将在 SpringApplication.run(​…​) 完成之前调用.

    CommandLineRunner 接口提供了访问应用程序字符串数组形式参数的方法,而 ApplicationRunner 则使用了上述的 ApplicationArguments 接口. 以下示例展示 CommandLineRunnerrun 方法的使用:

    import org.springframework.boot.*;
    import org.springframework.stereotype.*;
    @Component
    public class MyBean implements CommandLineRunner {
        public void run(String... args) {
            // Do something...
    

    如果您定义了多个 CommandLineRunner 或者 ApplicationRunner bean,则必须指定调用顺序,您可以实现 org.springframework.core.Ordered 接口,也可以使用 org.springframework.core.annotation.Order 注解解决顺序问题.

    1.10. 应用程序退出

    每个 SpringApplication 注册了一个 JVM 关闭钩子,以确保 ApplicationContext 在退出时可以优雅关闭. 所有标准的 Spring 生命周期回调 (比如 DisposableBean 接口,或者 @PreDestroy 注解) 都可以使用.

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

    @SpringBootApplication
    public class ExitCodeApplication {
        @Bean
        public ExitCodeGenerator exitCodeGenerator() {
            return () -> 42;
        public static void main(String[] args) {
            System.exit(SpringApplication.exit(SpringApplication.run(ExitCodeApplication.class, args)));
    

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

    1.11. 管理功能

    可以通过指定 spring.application.admin.enabled 属性来为应用程序启用管理相关的功能. 其将在 MBeanServer 平台上暴露 SpringApplicationAdminMXBean. 您可以使用此功能来远程管理 Spring Boot 应用. 该功能对服务包装器的实现也是非常有用的.

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

    Spring Boot 使用了一个非常特别的 PropertySource 指令,用于智能覆盖默认值. 属性将按照以下顺序处理:

    @Configuration 类上的 @PropertySource 注解. 请注意,在刷新应用程序上下文之前,不会将此类属性源添加到环境中. 现在配置某些属性 (如 logging.spring.main. ) 为时已晚,这些属性在刷新开始之前就已读取.

    默认属性 (使用 SpringApplication.setDefaultProperties 指定) .

    import org.springframework.stereotype.*;
    import org.springframework.beans.factory.annotation.*;
    @Component
    public class MyBean {
        @Value("${name}")
        private String name;
        // ...
    

    在您的应用程序的 classpath 中 (比如在 jar 中) ,您可以有一个 application.properties,它为 name 提供了一个合适的默认属性值. 当在新环境中运行时,您可以在 jar 外面提供一个 application.properties 来覆盖 name. 对于一次性测试,您可以使用命令行指定形式启动 (比如 java -jar app.jar --name="Spring") .

    my.bignumber=${random.long} my.uuid=${random.uuid} my.number.less.than.ten=${random.int(10)} my.number.in.range=${random.int[1024,65536]}

    random.int* 语法为 OPEN value (,max) CLOSE,OPEN,CLOSE 可为任意字符,value,max 为整数. 如果使用了 max,value 则为最小值,max 为最大值.

    2.2. 访问命令行属性

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

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

    2.3. 应用程序属性文件

    SpringApplication 从以下位置的 application.properties 文件中加载属性 (properties) ,并将它们添加到 Spring Environment 中: SpringApplication loads properties from application.properties files in the following locations and adds them to the Spring Environment:

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

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

    以下示例展示了如何指定两个位置:

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

    如果 spring.config.location 包含目录 (而不是文件) ,则它们应该以 / 结尾 (并且在运行期间,在加载之前追加从 spring.config.name 生成的名称,包括指定 profile 的文件名) . spring.config.location 中指定的文件按原样使用,不支持指定 profile 形式,并且可被任何指定 profile 的文件的属性所覆盖.

    配置位置以相反的顺序搜索. 默认情况下,配置的位置为 classpath:/,classpath:/config/,file:./,file:./config/. 生成的搜索顺序如下:

    2.4. 特定 Profile 的属性文件

    application.properties 文件外,还可以使用以下命名约定定义特定 profile 的属性文件: application-{profile}.properties. Environment 有一组默认配置文件 (默认情况下为 default) ,如果未设置激活的 (active) profile,则使用这些配置文件. 换句话说,如果没有显式激活 profile,则会加载 application-default.properties 中的属性.

    特定 profile 的属性文件从与标准 application.properties 相同的位置加载,特定 profile 的属性文件无论是否在打包的 jar 内部,都始终覆盖非特定文件.

    如果指定了多个配置文件,则应用 last-wins 策略 (优先采取最后一个) . 例如,spring.profiles.active 属性指定的配置文件是在使用 SpringApplication API 配置的配置文件之后添加的,因此优先应用.

    2.6. 加密属性

    Spring Boot 没有为加密属性值提供任何内置支持,然而,它提供了修改 Spring Environment 包含的值所必需的钩子. EnvironmentPostProcessor 接口允许您在应用程序启动之前操作 Environment. 有关详细信息,请参见 在启动前自定义 Environment 或 ApplicationContext .

    如果您正在寻找一种可用于存储凭据和密码的安全方法, Spring Cloud Vault 项目支持在 HashiCorp Vault 中存储外部化配置.

    2.7. 使用 YAML 代替属性文件

    YAML 是 JSON 的超集,是一个可用于指定层级配置数据的便捷格式. 只要在 classpath 上有 SnakeYAML 库,SpringApplication 类就会自动支持 YAML 作为属性文件 (properties) 的替代.

    2.7.1. 加载 YAML

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

    例如以下 YAML 文档:

    environments:
            url: https://dev.example.com
            name: Developer Setup
        prod:
            url: https://another.example.com
            name: My Cool App

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

    environments.dev.url=https://dev.example.com
    environments.dev.name=Developer Setup
    environments.prod.url=https://another.example.com
    environments.prod.name=My Cool App

    YAML 列表表示带有 [index] 下标引用的属性键. 例如以下 YAML:

    servers: - dev.example.com - another.example.com

    以上示例将转成以下属性:

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

    要使用 Spring Boot 的 Binder 工具来绑定这样配置到属性 (这是 @ConfigurationProperties 所做的) ,你需要在目标 bean 中有一个 java.util.List (或 Set) 类型的属性,你需要为其提供一个 setter 或者使用可变值初始化它. 例如,以下示例展示将上述的配置与属性绑定:

    @ConfigurationProperties(prefix="my")
    public class Config {
        private List<String> servers = new ArrayList<String>();
        public List<String> getServers() {
            return this.servers;
    

    在前面示例中,如果 development profile 处于激活状态,则 server.address 属性得值为 127.0.0.1. 同样,如果 productioneu-central profile 处于激活状态,则 server.address 属性的值为 192.168.1.120. 如果未激活 developmentproductioneu-central profile,则该属性的值为 192.168.1.100.

    因此,spring.profiles 可以包含一个简单的 profile 名称 (例如 production) 或一个 profile 表达式. profile 表达式允许表达更复杂的 profile 逻辑,例如 production & (eu-central | eu-west). 有关详细信息,请查阅http://docs.jcohy.com/zh-cn/spring-framework/5.2.4.RELEASE/spring-framework-reference/index.htmlcore.html#beans-definition-profiles-java[reference guide].

    2.7.4. YAML 的缺点

    无法使用 @PropertySource 注解加载 YAML 文件. 因此,如果您需要以这种方式加载值,请使用属性文件 (properties) .

    在特定于配置文件的YAML文件中使用多YAML文档语法可能会导致意外行为. 例如,考虑文件中的以下配置:

    application-dev.yml
    server:
      port: 8000
    spring:
      profiles: "!test"
      security:
        user:
          password: "secret"

    如果使用参数 --spring.profiles.active=dev 运行该应用程序,则可能希望将 security.user.password 设置为 “secret”,但事实并非如此.

    嵌套文档将被过滤,因为主文件名为 application-dev.yml. 它已经被认为是特定于配置文件的,并且嵌套文档将被忽略.

    import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties("acme") public class AcmeProperties { private boolean enabled; private InetAddress remoteAddress; private final Security security = new Security(); public boolean isEnabled() { ... } public void setEnabled(boolean enabled) { ... } public InetAddress getRemoteAddress() { ... } public void setRemoteAddress(InetAddress remoteAddress) { ... } public Security getSecurity() { ... } public static class Security { private String username; private String password; private List<String> roles = new ArrayList<>(Collections.singleton("USER")); public String getUsername() { ... } public void setUsername(String username) { ... } public String getPassword() { ... } public void setPassword(String password) { ... } public List<String> getRoles() { ... } public void setRoles(List<String> roles) { ... }

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

    acme.security.username, 内嵌一个 security 对象,其名称由属性名称决定. 特别是,返回类型根本没有使用,可能是 SecurityProperties.

    acme.security.password.

    acme.security.roles, String 集合. 默认为 USER.

    Spring Boot自动配置大量使用 @ConfigurationProperties 来轻松配置自动配置的bean. 与自动配置类相似,Spring Boot中可用的 @ConfigurationProperties 类仅供内部使用. 通过属性文件,YAML文件,环境变量等配置的映射到该类的属性是公共API, 但是该类本身的内容并不意味着可以直接使用.

    集合和数组可以通过一个索引 (通常使用 YAML) 或使用单个逗号分隔值 (属性) 进行访问. 最后一种情况必须使用 setter. 我们建议始终为此类型添加 setter. 如果初始化集合,请确保它是可变的 (如上例所示) .

    如果初始化嵌套的 POJO 属性 (如前面示例中的 Security 字段) ,则不需要 setter. 如果您希望 binder 使用其默认构造函数动态创建实例,则需要一个 setter.

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

    最后,考虑到标准 Java Bean 属性,不支持对静态属性的绑定.

    import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConstructorBinding; import org.springframework.boot.context.properties.DefaultValue; @ConstructorBinding @ConfigurationProperties("acme") public class AcmeProperties { private final boolean enabled; private final InetAddress remoteAddress; private final Security security; public AcmeProperties(boolean enabled, InetAddress remoteAddress, Security security) { this.enabled = enabled; this.remoteAddress = remoteAddress; this.security = security; public boolean isEnabled() { ... } public InetAddress getRemoteAddress() { ... } public Security getSecurity() { ... } public static class Security { private final String username; private final String password; private final List<String> roles; public Security(String username, String password, @DefaultValue("USER") List<String> roles) { this.username = username; this.password = password; this.roles = roles; public String getUsername() { ... } public String getPassword() { ... } public List<String> getRoles() { ... }

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

    @ConstructorBinding 类的嵌套成员 (例如上例中的 Security ) 也将通过其构造函数进行绑定.

    可以使用 @DefaultValue 指定默认值,并且将应用相同的转换服务将 String 值强制为缺少属性的目标类型.

    2.8.3. 启用 @ConfigurationProperties 注解的类型

    Spring Boot提供了绑定 @ConfigurationProperties 类型并将其注册为Bean的基础架构. 您可以逐类启用配置属性,也可以启用与组件扫描类似的方式进行配置属性扫描.

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

    @Configuration(proxyBeanMethods = false)
    @EnableConfigurationProperties(AcmeProperties.class)
    public class MyConfiguration {
    

    要使用配置属性扫描,请将 @ConfigurationPropertiesScan 注解 添加到您的应用程序. 通常,它被添加到使用 @SpringBootApplication 注解的主应用程序类中,但可以将其添加到任何 @Configuration 类中. 默认情况下,将从声明注解的类的包中进行扫描. 如果要定义要扫描的特定程序包,可以按照以下示例所示进行操作:

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

    当以这种方式注册 @ConfigurationProperties bean 时,bean 具有一个固定格式的名称: <prefix>-<fqn>,其中 <prefix> 是 @ConfigurationProperties 注解中指定的环境 key 前缀,<fqn> 是 bean 的完全限定类名. 如果注解未提供任何前缀,则仅使用 bean 的完全限定类名.

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

    即使前面的配置为 AcmeProperties 创建了一个 bean,我们也建议 @ConfigurationProperties 只处理环境 (environment) ,特别是不要从上下文中注入其他 bean. 对于极端情况,可以使用setter注入或框架提供的任何 *Aware 接口 (例如,需要访问 EnvironmentEnvironmentAware) . 如果仍然想使用构造函数注入其他bean,则必须使用 @Component 注解配置属性bean,并使用基于JavaBean的属性绑定.

    2.8.4. 使用 @ConfigurationProperties 注解类型

    这种配置样式与 SpringApplication 外部YAML配置特别有效,如以下示例所示:

    # application.yml
    acme:
        remote-address: 192.168.1.1
        security:
            username: admin
            roles:
              - USER
              - ADMIN
    # additional configuration as required

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

    @Service
    public class MyService {
        private final AcmeProperties properties;
        @Autowired
        public MyService(AcmeProperties properties) {
            this.properties = properties;
        //...
        @PostConstruct
        public void openConnection() {
            Server server = new Server(this.properties.getRemoteAddress());
            // ...
    

    2.8.5. 第三方配置

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

    要使用 Environment 属性配置 bean,请将 @ConfigurationProperties 添加到 bean 注册上,如下所示:

    @ConfigurationProperties(prefix = "another")
    @Bean
    public AnotherComponent anotherComponent() {
    

    使用 another 前缀定义的所有属性都使用与前面的 AcmeProperties 示例类似的方式映射到 AnotherComponent bean.

    2.8.6. 宽松绑定

    Spring Boot 使用一些宽松的规则将 Environment 属性绑定到 @ConfigurationProperties bean,因此 Environment 属性名不需要和 bean 属性名精确匹配. 常见的示例包括使用了 - 符号分割的环境属性 (例如,context-path 绑定到 contextPath) 和大写环境属性 (例如,PORT 绑定到 port) .

    如下 @ConfigurationProperties 类:

    @ConfigurationProperties(prefix="acme.my-project.person")
    public class OwnerProperties {
        private String firstName;
        public String getFirstName() {
            return this.firstName;
        public void setFirstName(String firstName) {
            this.firstName = firstName;
    

    在上述示例中,同样可以使用以下属性名称:

    Table 2. 宽松绑定

    如果 dev 配置文件未激活,则 AcmeProperties.list 只包含一条 MyPojo 条目,如之前所述. 但是,如果激活了 dev 配置文件,列表集合仍然只包含一个条目 (name 属性值为 my another name,description 为 null) . 此配置不会向列表集合中添加第二个 MyPojo 实例,也不会合并条目.

    在多个配置文件中指定一个 List 时,最高优先级 (并且只有一个) 的列表集合将被使用. 可做如下配置:

    acme:
      list:
        - name: my name
          description: my description
        - name: another name
          description: another description
    spring:
      profiles: dev
    acme:
      list:
        - name: my another name

    在前面示例中,如果 dev 配置文件处于 active 状态,则 AcmeProperties.list 包含一个 MyPojo 条目 (name 为 my another name,description 为 null) . 对于 YAML 而言,逗号分隔的列表和YAML 列表同样会完全覆盖列表集合的内容.

    对于 Map 属性,您可以绑定来自多个源中提取的属性值. 但是,对于多个源中的相同属性,则使用高优先级最高的属性. 以下示例从 AcmeProperties 暴露了一个 Map<String, MyPojo>:

    @ConfigurationProperties("acme")
    public class AcmeProperties {
        private final Map<String, MyPojo> map = new HashMap<>();
        public Map<String, MyPojo> getMap() {
            return this.map;
    

    可以考虑以下配置:

    acme:
        key1:
          name: my name 1
          description: my description 1
    spring:
      profiles: dev
    acme:
        key1:
          name: dev name 1
        key2:
          name: dev name 2
          description: dev description 2

    如果 dev 配置文件未激活,则 AcmeProperties.map 只包含一个带 key1 key 的条目 (name 为 my name 1,description 为 my description 1) . 如果激活了 dev 配置文件,则 map 将包含两个条目, key 分别为 key1 (name 为 dev name 1 和 description 为 my description 1) 和 key2 (name 为 dev name 2 和 description 为 dev description 2) .

    @DurationUnit(ChronoUnit.SECONDS) private Duration sessionTimeout = Duration.ofSeconds(30); private Duration readTimeout = Duration.ofMillis(1000); public Duration getSessionTimeout() { return this.sessionTimeout; public void setSessionTimeout(Duration sessionTimeout) { this.sessionTimeout = sessionTimeout; public Duration getReadTimeout() { return this.readTimeout; public void setReadTimeout(Duration readTimeout) { this.readTimeout = readTimeout;

    指定一个会话超时时间为 30 秒,使用 30PT30S30s 等形式都是可以的. 读取超时时间设置为 500ms,可以采用以下任何一种形式: 500PT0.5S500ms.

    您也可以使用任何支持的单位来标识:

    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 兆字节的缓冲大小,使用 1010MB 是等效的. 256 字节的大小可以指定为 256256B.

    您也可以使用任何支持的单位:

    您还可以通过创建一个名为 configurationPropertiesValidator 的 bean 定义来添加自定义 Spring Validator. 应该将 @Bean 方法声明为 static. 配置属性验证器在应用程序生命周期的早期创建,将 @Bean 方法声明为 static 可以无需实例化 @Configuration 类来创建 bean. 这样做可以避免早期实例化可能导致的意外问题. 这里有一个属性验证示例,讲解了如何设置.

    如果您要为自己的组件定义一组配置 key,我们建议您将它们分组到使用 @ConfigurationProperties 注解的 POJO 中. 您应该知道,由于 @Value 不支持宽松绑定,因此如果您需要通过环境变量来提供值,它并不是一个好的选择.

    最后,虽然您可以在 @Value 中编写 SpEL 表达式,但来自应用程序属性文件的此类表达式并不会被处理.

    @Configuration(proxyBeanMethods = false)
    @Profile("production")
    public class ProductionConfiguration {
        // ...
    如果 @ConfigurationProperties Bean是通过 @EnableConfigurationProperties 而非自动扫描注册的,则需要在 @EnableConfigurationProperties 注解的 @Configuration 类上指定 @Profile 注解.
    在扫描 @ConfigurationProperties 的情况下,可以在 @ConfigurationProperties 类本身上指定 @Profile.
    

    3.1. 添加激活 Profile

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

    有时,将特定 profile 的属性添加到激活配置文件而不是替换它们,这种方式也是很有用的. spring.profiles.include 属性可无条件地添加激活配置文件. SpringApplication 入口还有一个 Java API,用于设置其他 profile (即,在 spring.profiles.active 属性激活的 profile 之上) . 请参阅 SpringApplication 中的 setAdditionalProfiles() 方法.

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

    my.property: fromyamlfile spring.profiles: prod spring.profiles.include: - proddb - prodmq

    Spring Boot 使用 Commons Logging 记录所有内部日志,但开放日志的底层实现. 其为 Java Util Logging, Log4J2Logback 提供了默认配置. 在每种情况下,日志记录器都预先配置为使用控制台输出,并且还提供可选的文件输出.

    默认情况下,如果您使用了 Starter,则使用 Logback 进行日志记录. 还包括合适的 Logback 路由,以确保在使用 Java Util Logging、Commons Logging、Log4J 或 SLF4J 的依赖库都能正常工作.

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

    输出以下项:

    启用调试模式后,核心日志记录器 (内嵌容器、Hibernate 和 Spring Boot) 将被配置为输出更多日志信息. 启用调试模式不会将应用程序配置为使用 DEBUG 级别记录所有日志内容.

    或者,您可以通过使用 --trace 标志 (或在 application.properties 中的设置 trace=true) 启动应用程序来启用跟踪模式. 这样做可以为选择的核心日志记录器 (内嵌容器、Hibernate 模式生成和整个 Spring 组合) 启用日志追踪.

    4.2.1. 着色输出

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

    可使用 %clr 转换字配置颜色编码. 最简单形式是,转换器根据日志级别对输出进行着色,如下所示:

    %clr(%5p)

    下表描述日志级别与颜色的映射关系:

    4.3. 文件输出

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

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

    Table 4. Logging 属性

    日志文件在达到 10MB 时会轮转,并且与控制台输出一样,默认情况下会记录 ERRORWARNINFO 级别的内容. 可以使用 logging.file.max-size 属性更改大小限制. 除非已设置 logging.file.max-history 属性,否则默认情况下将保留最近7天的轮转日志文件. 可以使用 logging.file.total-size-cap 限制日志归档文件的总大小. 当日志归档的总大小超过该阈值时,将删除备份. 要在应用程序启动时强制清除日志归档文件,请使用 logging.file.clean-history-on-start 属性.

    4.4. 日志等级

    所有受支持的日志记录系统都可以使用 logging.level.<logger-name>=<level> 来设置 Spring Environment 中的记录器等级 (例如,在 application.properties 中) . 其中 level 是 TRACEDEBUGINFOWARNERRORFATALOFF 其中之一. 可以使用 logging.level.root 配置 root 记录器.

    以下示例展示了 application.properties 中默认的日志记录设置:

    logging.level.root=warn
    logging.level.org.springframework.web=debug
    logging.level.org.hibernate=error

    也可以使用环境变量设置日志记录级别. 例如, LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_WEB=DEBUG 会将 org.springframework.web 设置为 DEBUG.

    org.springframework.core.codec, org.springframework.http, org.springframework.web, org.springframework.boot.actuate.endpoint.web, org.springframework.boot.web.servlet.ServletContextInitializerBeans

    org.springframework.jdbc.core, org.hibernate.SQL, org.jooq.tools.LoggerListener

    4.6. 自定义日志配置

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

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

    logging.file.clean-history-on-start

    LOG_FILE_CLEAN_HISTORY_ON_START

    是否在启动时清除存档日志文件 (如果启用了LOG_FILE) . (仅默认的Logback设置受支持. )

    logging.file.name

    LOG_FILE

    如果已定义,则在默认日志配置中使用它.

    logging.file.max-size

    LOG_FILE_MAX_SIZE

    最大日志文件大小 (如果启用了 LOG_FILE) . (仅支持默认的 Logback 设置. )

    logging.file.max-history

    LOG_FILE_MAX_HISTORY

    要保留的归档日志文件最大数量 (如果启用了 LOG_FILE) . (仅支持默认的 Logback 设置. )

    logging.file.path

    LOG_PATH

    如果已定义,则在默认日志配置中使用它.

    logging.file.total-size-cap

    LOG_FILE_TOTAL_SIZE_CAP

    要保留的日志备份的总大小 (如果启用了LOG_FILE) . (仅默认的Logback设置受支持. )

    logging.pattern.console

    CONSOLE_LOG_PATTERN

    要在控制台上使用的日志模式 (stdout) . (仅支持默认的 Logback 设置. )

    logging.pattern.dateformat

    LOG_DATEFORMAT_PATTERN

    日志日期格式的 Appender 模式. (仅支持默认的 Logback 设置. )

    logging.pattern.file

    FILE_LOG_PATTERN

    要在文件中使用的日志模式 (如果启用了 LOG_FILE) . (仅支持默认的 Logback 设置. )

    logging.pattern.level

    LOG_LEVEL_PATTERN

    渲染日志级别时使用的格式 (默认值为 %5p) . (仅支持默认的 Logback 设置. )

    logging.pattern.rolling-file-name

    ROLLING_FILE_NAME_PATTERN

    过渡日志文件名的模式(默认 ${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz).

    当前进程 ID (如果可能,则在未定义为 OS 环境变量时发现) .

    ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:71 - no applicable action for [springProperty], current ElementPath is [[configuration][springProperty]]
    ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:71 - no applicable action for [springProfile], current ElementPath is [[configuration][springProfile]]

    4.7.1. 特定 Profile 配置

    <springProfile> 标签允许您根据激活的 Spring profile 选择性地包含或排除配置部分. 在 <configuration> 元素中的任何位置都支持配置 profile. 使用 name 属性指定哪个 proifle 接受配置. <springProfile> 标记可以包含简单的 proifle 名称 (例如 staging) 或 profile 表达式. profile 表达式允许表达更复杂的 profile 逻辑, 例如 production & (eu-central | eu-west). 有关详细信息,请查阅 参考指南 . 以下清单展示了三个示例 profile:

    <springProfile name="staging">
        <!-- configuration to be enabled when the "staging" profile is active -->
    </springProfile>
    <springProfile name="dev | staging">
        <!-- configuration to be enabled when the "dev" or "staging" profiles are active -->
    </springProfile>
    <springProfile name="!production">
        <!-- configuration to be enabled when the "production" profile is not active -->
    </springProfile>

    4.7.2. 环境属性

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

    <springProperty scope="context" name="fluentHost" source="myapp.fluentd.host"
            defaultValue="localhost"/>
    <appender name="FLUENT" class="ch.qos.logback.more.appenders.DataFluentAppender">
        <remoteHost>${fluentHost}</remoteHost>
    </appender>

    Spring Boot 非常适合用于开发 web 应用程序. 您可以使用嵌入式 Tomcat、Jetty 或者 Undertow 来创建一个独立 (self-contained) 的 HTTP 服务器. 大多数 web 应用程序使用 spring-boot-starter-web 模块来快速搭建和运行,您也可以选择使用 spring-boot-starter-webflux 模块来构建响应式 (reactive) web 应用程序.

    如果您尚未开发过 Spring Boot web 应用程序,则可以按照 入门 章节中的 "Hello World!" 示例进行操作.

    7.1. Spring Web MVC 框架

    Spring Web MVC 框架 (通常简称 "Spring MVC") 是一个富模型-视图-控制器的 web 框架. Spring MVC 允许您创建 @Controller 或者 @RestController bean 来处理传入的 HTTP 请求. 控制器中的方法通过 @RequestMapping 注解映射到 HTTP.

    以下是一个使用了 @RestController 来响应 JSON 数据的典型示例:

    @RestController
    @RequestMapping(value="/users")
    public class MyRestController {
        @RequestMapping(value="/{user}", method=RequestMethod.GET)
        public User getUser(@PathVariable Long user) {
            // ...
        @RequestMapping(value="/{user}/customers", method=RequestMethod.GET)
        List<Customer> getUserCustomers(@PathVariable Long user) {
            // ...
        @RequestMapping(value="/{user}", method=RequestMethod.DELETE)
        public User deleteUser(@PathVariable Long user) {
            // ...
    

    Spring MVC 是 Spring Framework 核心的一部分,详细介绍可参考其 参考文档. spring.io/guides 还提供了几个 Spring MVC 相关的指南.

    7.1.1. Spring MVC 自动配置

    Spring Boot 提供了适用于大多数 Spring MVC 应用的自动配置 (auto-configuration) .

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

    如果您想保留 Spring Boot MVC 的功能,并且需要添加其他 MVC configuration (interceptor、formatter 和视图控制器等) ,可以添加自己的 WebMvcConfigurerAdapter 类型的 @Configuration 类,但不能带 @EnableWebMvc 注解.

    如果您想自定义 RequestMappingHandlerMappingRequestMappingHandlerAdapter 或者 ExceptionHandlerExceptionResolver 实例,可以声明一个 WebMvcRegistrationsAdapter 实例来提供这些组件.

    如果您想完全掌控 Spring MVC,可以添加自定义注解了 @EnableWebMvc@Configuration 配置类. 或者添加自己的 @Configuration 注解的 DelegatingWebMvcConfiguration,如Java文档中的 @EnableWebMvc 所述. .

    7.1.2. HttpMessageConverters

    Spring MVC 使用 HttpMessageConverter 接口来转换 HTTP 的请求和响应. 开箱即用功能包含了合适的默认值,比如对象可以自动转换为 JSON (使用 Jackson 库) 或者 XML (优先使用 Jackson XML 扩展,其次为 JAXB) . 字符串默认使用 UTF-8 编码.

    如果您需要添加或者自定义转换器 (converter) ,可以使用 Spring Boot 的 HttpMessageConverters 类:

    import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
    import org.springframework.context.annotation.*;
    import org.springframework.http.converter.*;
    @Configuration(proxyBeanMethods = false)
    public class MyConfiguration {
        @Bean
        public HttpMessageConverters customConverters() {
            HttpMessageConverter<?> additional = ...
            HttpMessageConverter<?> another = ...
            return new HttpMessageConverters(additional, another);
    

    上下文中的所有 HttpMessageConverter bean 都将被添加到转换器列表中. 您也可以用这种方式来覆盖默认转换器.

    7.1.3. 自定义 JSON Serializer 和 Deserializer

    如果您使用 Jackson 序列化和反序列化 JSON 数据,可能需要自己编写 JsonSerializerJsonDeserializer 类. 自定义序列化器 (serializer) 的做法通常是 通过一个模块来注册 Jackson, 然而 Spring Boot 提供了一个备选的 @JsonComponent 注解,它可以更加容易地直接注册 Spring Bean.

    您可以直接在 JsonSerializer 或者 JsonDeserializer 实现上使用 @JsonComponent 注解. 您也可以在将序列化器/反序列化器 (deserializer) 作为内部类的类上使用. 例如:

    import java.io.*;
    import com.fasterxml.jackson.core.*;
    import com.fasterxml.jackson.databind.*;
    import org.springframework.boot.jackson.*;
    @JsonComponent
    public class Example {
        public static class Serializer extends JsonSerializer<SomeObject> {
            // ...
        public static class Deserializer extends JsonDeserializer<SomeObject> {
            // ...
    

    ApplicationContext 中所有的 @JsonComponent bean 将被自动注册到 Jackson 中,由于 @JsonComponent 使用 @Component 注解标记,因此组件扫描 (component-scanning) 规则将对其生效.

    Spring Boot 还提供了 JsonObjectSerializerJsonObjectDeserializer 基类, 它们在序列化对象时为标准的 Jackson 版本提供了有用的替代方案. 有关详细信息,请参阅 Javadoc 中的 JsonObjectSerializerJsonObjectDeserializer.

    7.1.4. MessageCodesResolver

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

    7.1.5. 静态内容

    默认情况下,Spring Boot 将在 classpath 或者 ServletContext 根目录下从名为 /static (/public/resources/META-INF/resources) 目录中服务静态内容. 它使用了 Spring MVC 的 ResourceHttpRequestHandler,因此您可以通过添加自己的 WebMvcConfigurerAdapter 并重写 addResourceHandlers 方法来修改此行为.

    在一个独立的 (stand-alone) web 应用程序中,来自容器的默认 servlet 也是被启用的,并充当一个回退支援,Spring 决定不处理 ServletContext 根目录下的静态资源,容器的默认 servlet 也将会处理. 大多情况下,这是不会发生的 (除非您修改了默认的 MVC 配置) ,因为 Spring 始终能通过 DispatcherServlet 来处理请求.

    默认情况下,资源被映射到 /,但可以通过 spring.mvc.static-path-pattern 属性调整. 比如,将所有资源重定位到 /resources/:

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

    您还可以使用 spring.resources.static-locations 属性来自定义静态资源的位置 (使用一个目录位置列表替换默认值) . 根 Servlet context path / 自动作为一个 location 添加进来.

    除了上述提到的标准静态资源位置之外,还有一种特殊情况是用于 Webjars content. 如果以 Webjar 格式打包,则所有符合 /webjars/** 的资源都将从 jar 文件中服务.

    Spring Boot 还支持 Spring MVC 提供的高级资源处理功能,允许使用例如静态资源缓存清除 (cache busting) 或者 Webjar 版本无关 URL.

    要使用 Webjar 版本无关 URL 功能,只需要添加 webjars-locator-core 依赖. 然后声明您的 Webjar,以 jQuery 为例,添加的 "/webjars/jquery/dist/jquery.min.js" 将变成 "/webjars/jquery/x.y.z/dist/jquery.min.js",其中 x.y.z 是 Webjar 的版本.

    spring.resources.chain.strategy.content.enabled=true
    spring.resources.chain.strategy.content.paths=/**
    spring.resources.chain.strategy.fixed.enabled=true
    spring.resources.chain.strategy.fixed.paths=/js/lib/
    spring.resources.chain.strategy.fixed.version=v12

    使用此配置,JavaScript 模块定位在 "/js/lib/" 下使用固定版本策略 ("/v12/js/lib/mymodule.js") ,而其他资源仍使用内容策略 (<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>) .

    有关更多支持选项,请参阅 ResourceProperties.

    7.1.8. 路径匹配与内容协商

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

    Spring Boot 默认选择禁用后缀模式匹配,这意味着像 "GET /projects/spring-boot.json" 这样的请求将不会与 @GetMapping("/projects/spring-boot") 映射匹配. 这被视为是 Spring MVC 应用程序的最佳实践 . 此功能在过去对于 HTTP 客户端没有发送正确的 Accept 请求头的情况还是很有用的,我们需要确保将正确的内容类型发送给客户端. 如今,内容协商 (Content Negotiation) 更加可靠.

    还有其他方法可以处理 HTTP 客户端发送不一致 Accept 请求头问题. 我们可以使用查询参数来确保像 "GET /projects/spring-boot?format=json" 这样的请求映射到 @GetMapping("/projects/spring-boot"),而不是使用后缀匹配:

    spring.mvc.contentnegotiation.favor-parameter=true
    # We can change the parameter name, which is "format" by default:
    # spring.mvc.contentnegotiation.parameter-name=myparam
    # We can also register additional file extensions/media types with:
    spring.mvc.contentnegotiation.media-types.markdown=text/markdown

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

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

    或者,不打开所有后缀模式,仅打开支持已注册的后缀模式更加安全:

    spring.mvc.contentnegotiation.favor-path-extension=true
    spring.mvc.pathmatch.use-registered-suffix-pattern=true
    # You can also register additional file extensions/media types with:
    # spring.mvc.contentnegotiation.media-types.adoc=text/asciidoc

    7.1.10. 模板引擎

    除了 REST web 服务之外,您还可以使用 Spring MVC 来服务动态 HTML 内容. Spring MVC 支持多种模板技术,包括 Thymeleaf、FreeMarker 和 JSP. 当然,许多其他模板引擎也有自己的 Spring MVC 集成.

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

    7.1.11. 错误处理

    默认情况下,Spring Boot 提供了一个使用了比较合理的方式来处理所有错误的 /error 映射,其在 servlet 容器中注册了一个全局错误页面. 对于机器客户端而言,它将产生一个包含错误、HTTP 状态和异常消息的 JSON 响应. 对于浏览器客户端而言,将以 HTML 格式呈现相同数据的 whitelabel 错误视图 (可添加一个解析到 errorView 进行自定义) . 要完全替换默认行为,您可以实现 ErrorController 并注册该类型的 bean,或者简单地添加一个类型为 ErrorAttributes 的 bean 来替换内容,但继续使用现用机制.

    @ControllerAdvice(basePackageClasses = AcmeController.class)
    public class AcmeControllerAdvice extends ResponseEntityExceptionHandler {
        @ExceptionHandler(YourException.class)
        @ResponseBody
        ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {
            HttpStatus status = getStatus(request);
            return new ResponseEntity<>(new CustomErrorType(status.value(), ex.getMessage()), status);
        private HttpStatus getStatus(HttpServletRequest request) {
            Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
            if (statusCode == null) {
                return HttpStatus.INTERNAL_SERVER_ERROR;
            return HttpStatus.valueOf(statusCode);
    

    以上示例中,如果同包下定义的控制器 AcmeController 抛出了 YourException,则将使用 CustomerErrorType 类型的 POJO 来代替 ErrorAttributes 做 JSON 呈现.

    自定义错误页面

    如果您想在自定义的 HTML 错误页面上显示给定的状态码,请将文件添加到 /error 文件夹中. 错误页面可以是静态 HTML (添加在任意静态资源文件夹下) 或者使用模板构建. 文件的名称应该是确切的状态码或者一个序列掩码.

    例如,要将 404 映射到一个静态 HTML 文件,文件夹结构可以如下:

    +- main/ +- java/ | + <source code> +- resources/ +- public/ +- error/ | +- 404.html +- <other public assets>

    使用 FreeMarker 模板来映射所有 5xx 错误,文件夹的结构如下:

    +- main/ +- java/ | + <source code> +- resources/ +- templates/ +- error/ | +- 5xx.ftlh +- <other templates>

    对于更复杂的映射,您还通过可以添加实现了 ErrorViewResolver 接口的 bean 来处理:

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

    您还可以使用常规的 Spring MVC 功能,比如 @ExceptionHandler methods 方法和 @ControllerAdvice. 之后,ErrorController 将能接收任何未处理的异常.

    映射到 Spring MVC 之外的错误页面

    对于不使用 Spring MVC 的应用程序,您可以使用 ErrorPageRegistrar 接口来直接注册 ErrorPages. 抽象部分直接与底层的内嵌 servlet 容器一起工作,即使您没有 Spring MVC DispatcherServlet 也能使用.

    @Bean
    public ErrorPageRegistrar errorPageRegistrar(){
        return new MyErrorPageRegistrar();
    // ...
    private static class MyErrorPageRegistrar implements ErrorPageRegistrar {
        @Override
        public void registerErrorPages(ErrorPageRegistry registry) {
            registry.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400"));
    
    @Bean
    public FilterRegistrationBean myFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new MyFilter());
        registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
        return registration;
    

    请注意,默认的 FilterRegistrationBean 不包含 ERROR 调度器 (dispatcher) 类型.

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

    7.1.12. Spring HATEOAS

    如果您想开发一个使用超媒体 (hypermedia) 的 RESTful API,Spring Boot 提供的 Spring HATEOAS 自动配置在大多数应用程序都工作得非常好. 自动配置取代了 @EnableHypermediaSupport 的需要, 并注册了一些 bean,以便能轻松构建基于超媒体的应用程序,其包括了一个 LinkDiscoverers (用于客户端支持) 和一个用于配置将响应正确呈现的 ObjectMapper. ObjectMapper 可以通过设置 spring.jackson.* 属性或者 Jackson2ObjectMapperBuilder bean (如果存在) 自定义.

    您可以使用 @EnableHypermediaSupport 来控制 Spring HATEOAS 的配置. 请注意,这使得上述的自定义 ObjectMapper 被禁用.

    7.1.13. CORS 支持

    Cross-origin resource sharing 跨域资源共享 (Cross-origin resource sharing,CORS) 是 most browsers实现的一个 W3C specification ,其可允许您以灵活的方式指定何种跨域请求可以被授权,而不是使用一些不太安全和不太强大的方式 (比如 IFRAME 或者 JSONP) .

    Spring MVC 从 4.2 版本起开始 支持 CORS. 您可在 Spring Boot 应用程序中使用 @CrossOrigin 注解 配置控制器方法启用 CORS. 还可以通过注册一个 WebMvcConfigurer bean 并自定义 addCorsMappings(CorsRegistry) 方法来定义 全局 CORS 配置 :

    @Configuration(proxyBeanMethods = false)
    public class MyConfiguration {
        @Bean
        public WebMvcConfigurer corsConfigurer() {
            return new WebMvcConfigurer() {
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/api/**");
        @GetMapping("/{user}/customers")
        public Flux<Customer> getUserCustomers(@PathVariable Long user) {
            // ...
        @DeleteMapping("/{user}")
        public Mono<User> deleteUser(@PathVariable Long user) {
            // ...
    

    “WebFlux.fn” 为函数式调用方式,它将路由配置与请求处理分开,如下所示:

    @Configuration(proxyBeanMethods = false)
    public class RoutingConfiguration {
        @Bean
        public RouterFunction<ServerResponse> monoRouterFunction(UserHandler userHandler) {
            return route(GET("/{user}").and(accept(APPLICATION_JSON)), userHandler::getUser)
                    .andRoute(GET("/{user}/customers").and(accept(APPLICATION_JSON)), userHandler::getUserCustomers)
                    .andRoute(DELETE("/{user}").and(accept(APPLICATION_JSON)), userHandler::deleteUser);
    @Component
    public class UserHandler {
        public Mono<ServerResponse> getUser(ServerRequest request) {
            // ...
        public Mono<ServerResponse> getUserCustomers(ServerRequest request) {
            // ...
        public Mono<ServerResponse> deleteUser(ServerRequest request) {
            // ...
    

    WebFlux 是 Spring Framework 的一部分,详细信息可查看其 参考文档.

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

    如果你要保留 Spring Boot WebFlux 功能并且想要添加其他 WebFlux 配置,可以添加自己的 @Configuration 类,类型为 WebFluxConfigurer,但不包含 @EnableWebFlux.

    如果您想完全控制 Spring WebFlux,可以将 @EnableWebFlux 注解到自己的 @Configuration.

    7.2.2. 使用 HttpMessageReader 和 HttpMessageWriter 作为 HTTP 编解码器

    Spring WebFlux 使用 HttpMessageReaderHttpMessageWriter 接口来转换 HTTP 的请求和响应. 它们通过检测 classpath 中可用的类库,配置了 CodecConfigurer 生成合适的默认值.

    Spring Boot 通过使用 CodecCustomizer 实例加强定制. 例如,spring.jackson.* 配置 key 应用于 Jackson 编解码器.

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

    import org.springframework.boot.web.codec.CodecCustomizer;
    @Configuration(proxyBeanMethods = false)
    public class MyConfiguration {
        @Bean
        public CodecCustomizer myCodecCustomizer() {
            return codecConfigurer -> {
                // ...
    

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

    7.2.3. 静态内容

    默认情况下,Spring Boot 将在 classpath 或者 ServletContext 根目录下从名为 /static (/public/resources/META-INF/resources) 目录中服务静态内容. 它使用了 Spring WebFlux 的 ResourceWebHandler,因此您可以通过添加自己的 WebFluxConfigurer 并重写 addResourceHandlers 方法来修改此行为.

    默认情况下,资源被映射到 /,但可以通过 spring.webflux.static-path-pattern 属性调整. 比如,将所有资源重定位到 /resources/:

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

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

    除了上述提到的标准静态资源位置之外,还有一种特殊情况是用于 Webjars 内容 . 如果以 Webjar 格式打包,则所有符合 /webjars/** 的资源都将从 jar 文件中服务.

    7.2.4. 模板引擎

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

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

    7.2.5. Error Handling

    Spring Boot 提供了一个 WebExceptionHandler,它以合理的方式处理所有错误. 它在处理顺序中的位置紧接在 WebFlux 提供的处理程序之前,这些处理器排序是最后的. 对于机器客户端,它会生成一个 JSON 响应,其中包含错误详情、HTTP 状态和异常消息. 对于浏览器客户端,有一个 whitelabel 错误处理程序,它以 HTML 格式呈现同样的数据. 您还可以提供自己的 HTML 模板来显示错误 (请参阅下一节) .

    自定义此功能的第一步通常会沿用现有机制,但替换或扩充了错误内容. 为此,您可以添加 ErrorAttributes 类型的 bean.

    想要更改错误处理行为,可以实现 ErrorWebExceptionHandler 并注册该类型的 bean. 因为 WebExceptionHandler 是一个非常底层的异常处理器,所以 Spring Boot 还提供了一个方便的 AbstractErrorWebExceptionHandler 来让你以 WebFlux 的方式处理错误,如下所示:

    public class CustomErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
        // Define constructor here
        @Override
        protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
            return RouterFunctions
                    .route(aPredicate, aHandler)
                    .andRoute(anotherPredicate, anotherHandler);
    

    要获得更完整的功能,您还可以直接继承 DefaultErrorWebExceptionHandler 并覆盖相关方法.

    自定义错误页面

    如果您想在自定义的 HTML 错误页面上显示给定的状态码,请将文件添加到 /error 文件夹中. 错误页面可以是静态 HTML (添加在任意静态资源文件夹下) 或者使用模板构建. 文件的名称应该是确切的状态码或者一个序列掩码.

    例如,要将 404 映射到一个静态 HTML 文件,文件夹结构可以如下:

    +- main/ +- java/ | + <source code> +- resources/ +- public/ +- error/ | +- 404.html +- <other public assets>

    使用 Mustache 模板来映射所有 5xx 错误,文件夹的结构如下:

    +- main/ +- java/ | + <source code> +- resources/ +- templates/ +- error/ | +- 5xx.mustache +- <other templates>

    7.2.6. Web 过滤器

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

    如果过滤器的执行顺序很重要,则可以实现 Ordered 接口或使用 @Order 注解来指定顺序. Spring Boot 自动配置可能为您配置了几个 Web 过滤器. 执行此操作时,将使用下表中的顺序:

    7.3. JAX-RS 与 Jersey

    如果您喜欢 JAX-RS 编程模型的 REST 端点,则可以使用一个实现来替代 Spring MVC. JerseyApache CXF 都能开箱即用. CXF 要求在应用程序上下文中以 @Bean 的方式将它注册为一个 Servlet 或者 Filter. Jersey 有部分原生 Spring 支持,所以我们也在 starter 中提供了与 Spring Boot 整合的自动配置支持.

    要使用 Jersey,只需要将 spring-boot-starter-jersey 作为依赖引入,然后您需要一个 ResourceConfig 类型的 @Bean,您可以在其中注册所有端点:

    @Component
    public class JerseyConfig extends ResourceConfig {
        public JerseyConfig() {
            register(Endpoint.class);
    

    由于 Endpoint 是一个 Spring @Component,它的生命周期由 Spring 管理,您可以使用 @Autowired 注入依赖并使用 @Value 注入外部配置. 默认情况下,Jersey servlet 将被注册并映射到 /*. 您可以通过将 @ApplicationPath 添加到 ResourceConfig 来改变此行为.

    默认情况下,Jersey 在 ServletRegistrationBean 类型的 @Bean 中被设置为一个名为 jerseyServletRegistration 的 Servlet. 默认情况下,该 servlet 将被延迟初始化,您可以使用 spring.jersey.servlet.load-on-startup 自定义. 您可以禁用或通过创建一个自己的同名 bean 来覆盖该 bean. 您还可以通过设置 spring.jersey.type=filter 使用过滤器替代 servlet (该情况下, 替代或覆盖 @Bean 的为 jerseyFilterRegistration) . 该过滤器有一个 @Order,您可以使用 spring.jersey.filter.order 设置. 可以使用 spring.jersey.init.* 指定一个 map 类型的 property 以给定 servlet 和过滤器的初始化参数.

    这里有一个 Jersey 示例,您可以解如何设置.

    7.4. 内嵌 Servlet 容器支持

    Spring Boot 包含了对内嵌 Tomcat, Jetty, 和 Undertow 服务器的支持. 大部分开发人员只需简单地使用对应的 Starter 来获取完整的配置实例. 默认情况下,内嵌服务器将监听 8080 上的 HTTP 请求.

    7.4.1. Servlets, Filters, 与 listeners

    使用内嵌 servlet 容器时,您可以使用 Spring bean 或者扫描方式来注册 Servlet 规范中的 Servlet、Filter 和所有监听器 (比如 HttpSessionListener) .

    将 Servlet、Filter 和 Listener 注册为 Spring

    任何 ServletFilter*Listener 的 Spring bean 实例都将被注册到内嵌容器中. 如果您想引用 application.properties 中的某个值,这可能会特别方便.

    默认情况下,如果上下文只包含单个 Servlet,它将映射到 /. 在多个 Servlet bean 的情况下,bean 的名称将用作路径的前缀. Filter 将映射到 /*.

    如果基于约定配置的映射不够灵活,您可以使用 ServletRegistrationBeanFilterRegistrationBeanServletListenerRegistrationBean 类来完全控制.

    通常把过滤器 bean 无序是安全的. 如果需要特定的顺序,则应使用 @Order 注解 Filter 或使其实现 Ordered. 您不能通过使用 @Order 注解 Filter 的bean方法来配置 Filter 的顺序. 如果您不能更改 Filter 类以添加 @Order 或实现 Ordered,则必须为 Filter 定义一个 FilterRegistrationBean 并使用 setOrder(int) 方法设置注册bean的顺序. 则应避免在 Ordered.HIGHEST_PRECEDENCE 顺序点配置读取请求体的过滤器,因为它的字符编码可能与应用程序的字符编码配置不一致. 如果一个 Servlet 过滤器包装了请求,则应使用小于或等于 OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER 的顺序点对其进行配置.

    7.4.2. Servlet 上下文初始化

    内嵌 servlet 容器不会直接执行 Servlet 3.0+ 的 javax.servlet.ServletContainerInitializer 接口或 Spring 的 org.springframework.web.WebApplicationInitializer 接口. 这是一个有意的设计决策,旨在降低在 war 内运行时第三方类库产生的风险,防止破坏 Sring Boot 应用程序.

    如果您需要在 Spring Boot 应用程序中执行 servlet 上下文初始化,则应注册一个实现了 org.springframework.boot.context.embedded.ServletContextInitializer 接口的 bean. onStartup 方法提供了针对 ServletContext 的访问入口,如果需要,它可以容易作为现有 WebApplicationInitializer 的适配器.

    扫描 Servlet、Filter 和 Listener

    使用内嵌容器时,可以使用 @ServletComponentScan 启用带 @WebServlet@WebFilter@WebListener 注解的类自动注册.

    7.4.4. 自定义内嵌 Servlet 容器

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

    常用服务器设置包括:

    会话设置: 是否持久会话 (server.session.persistence) 、session 超时 (server.session.timeout) 、会话数据存放位置 (server.session.store-dir) 和 session-cookie 配置 (server.session.cookie.*) .

    错误管理: 错误页面位置 (server.error.path) 等.

    HTTP 压缩

    import org.springframework.boot.web.server.WebServerFactoryCustomizer;
    import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
    import org.springframework.stereotype.Component;
    @Component
    public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
        @Override
        public void customize(ConfigurableServletWebServerFactory server) {
            server.setPort(9000);
    
    @Bean
    public ConfigurableServletWebServerFactory webServerFactory() {
        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
        factory.setPort(9000);
        factory.setSessionTimeout(10, TimeUnit.MINUTES);
        factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notfound.html"));
        return factory;
    

    Setter 方法提供了许多配置选项. 还有几个 hook 保护方法供您深入定制. 有关详细信息,请参阅 源码文档.

    如果您使用 war 打包,在 Jetty 和 Tomcat 中可以正常工作,使用 java -jar 启动时,可执行的 war 可正常使用,并且还可以部署到任何标准容器. 使用可执行 jar 时不支持 JSP.

    Undertow 不支持 JSP.

    创建自定义的 error.jsp 页面不会覆盖默认错误处理视图,应该使用自定义错误页面来代替. .

    7.6. 响应式服务器资源配置

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

    默认情况下,这些资源也将与 Reactor Netty 和 Jetty 客户端共享以获得最佳性能,具体如下:

    开发人员可以通过提供自定义的 ReactorResourceFactoryJettyResourceFactory bean 来重写 Jetty 和 Reactor Netty 的资源配置 —— 将应用于客户端和服务器.

    您可以在 WebClient Runtime 章节中了解有关客户端资源配置的更多内容.

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

    8.1. RSocket策略自动配置

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

    8.2. RSocket服务器自动配置

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

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

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

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

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

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

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

    @Service
    public class MyService {
        private final Mono<RSocketRequester> rsocketRequester;
        public MyService(RSocketRequester.Builder rsocketRequesterBuilder) {
            this.rsocketRequester = rsocketRequesterBuilder
                    .connectTcp("example.org", 9898).cache();
        public Mono<User> someRSocketCall(String name) {
            return this.rsocketRequester.flatMap(req ->
                        req.route("user").data(name).retrieveMono(User.class));
    

    默认情况下,如果 Spring Security 在 classpath 上,则 Web 应用程序是受保护的. Spring Boot 依赖 Spring Security 的内容协商策略来确定是使用 httpBasic 还是 formLogin. 要给 Web 应用程序添加方法级别的安全保护,可以使用 @EnableGlobalMethodSecurity 注解设置. 有关更多其他信息,您可以在 Spring Security 参考指南中找到.

    默认的 UserDetailsService 只有一个用户. 用户名为 user,密码是随机的,在应用程序启动时会以 INFO 级别打印出来,如下所示:

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

    一个 UserDetailsService (或 WebFlux 应用程序中的 ReactiveUserDetailsService) bean,采用内存存储形式,有一个自动生成密码的用户 (有关用户属性,请参阅 SecurityProperties.User ) .

    用于整个应用程序 (如果 actuator 在 classpath 上,则包括 actuator 端点) 基于表单登录或 HTTP Basic 认证 (取决于 Content-Type) .

    一个用于发布身份验证事件的 DefaultAuthenticationEventPublisher.

    9.1. MVC 安全

    默认的安全配置在 SecurityAutoConfigurationUserDetailsServiceAutoConfiguration 中实现. SecurityAutoConfiguration 导入用于 Web 安全的 SpringBootWebSecurityConfiguration,UserDetailsServiceAutoConfiguration 配置身份验证,这同样适用于非 Web 应用程序. 要完全关闭默认的 Web 应用程序安全配置,可以添加 WebSecurityConfigurerAdapter 类型的 bean (这样做不会禁用 UserDetailsService 配置或 Actuator 的安全保护) .

    要同时关闭 UserDetailsService 配置,您可以添加 UserDetailsServiceAuthenticationProviderAuthenticationManager 类型的 bean. Spring Boot 示例中有几个使用了安全保护的应用程序,他们或许可以帮助到您.

    可以通过添加自定义 WebSecurityConfigurerAdapter 来重写访问规则. Spring Boot 提供了便捷方法,可用于重写 actuator 端点和静态资源的访问规则. EndpointRequest 可用于创建一个基于 management.endpoints.web.base-path 属性的 RequestMatcher. PathRequest 可用于为常用位置中的资源创建一个 RequestMatcher.

    9.2. WebFlux 安全

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

    要同时关闭 UserDetailsService 配置,您可以添加 ReactiveUserDetailsServiceReactiveAuthenticationManager 类型的 bean.

    可以通过添加自定义 SecurityWebFilterChain 来重写访问规则. Spring Boot 提供了便捷方法,可用于重写 actuator 端点和静态资源的访问规则. EndpointRequest 可用于创建一个基于 management.endpoints.web.base-path 属性的 ServerWebExchangeMatcher.

    PathRequest 可用于为常用位置中的资源创建一个 ServerWebExchangeMatcher.

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

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        return http
            .authorizeExchange()
                .matchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
                .pathMatchers("/foo", "/bar")
                    .authenticated().and()
                .formLogin().and()
            .build();
    

    9.3.1. 客户端

    如果您的 classpath 上有 spring-security-oauth2-client,则可以利用一些自动配置来轻松设置 OAuth2/Open ID Connect 客户端. 该配置使用 OAuth2ClientProperties 的属性. 相同的属性适用于 servlet 和响应式应用程序.

    您可以在 spring.security.oauth2.client 前缀下注册多个 OAuth2 客户端和提供者 (provider) ,如下所示:

    spring.security.oauth2.client.registration.my-client-1.client-id=abcd
    spring.security.oauth2.client.registration.my-client-1.client-secret=password
    spring.security.oauth2.client.registration.my-client-1.client-name=Client for user scope
    spring.security.oauth2.client.registration.my-client-1.provider=my-oauth-provider
    spring.security.oauth2.client.registration.my-client-1.scope=user
    spring.security.oauth2.client.registration.my-client-1.redirect-uri=https://my-redirect-uri.com
    spring.security.oauth2.client.registration.my-client-1.client-authentication-method=basic
    spring.security.oauth2.client.registration.my-client-1.authorization-grant-type=authorization_code
    spring.security.oauth2.client.registration.my-client-2.client-id=abcd
    spring.security.oauth2.client.registration.my-client-2.client-secret=password
    spring.security.oauth2.client.registration.my-client-2.client-name=Client for email scope
    spring.security.oauth2.client.registration.my-client-2.provider=my-oauth-provider
    spring.security.oauth2.client.registration.my-client-2.scope=email
    spring.security.oauth2.client.registration.my-client-2.redirect-uri=https://my-redirect-uri.com
    spring.security.oauth2.client.registration.my-client-2.client-authentication-method=basic
    spring.security.oauth2.client.registration.my-client-2.authorization-grant-type=authorization_code
    spring.security.oauth2.client.provider.my-oauth-provider.authorization-uri=https://my-auth-server/oauth/authorize
    spring.security.oauth2.client.provider.my-oauth-provider.token-uri=https://my-auth-server/oauth/token
    spring.security.oauth2.client.provider.my-oauth-provider.user-info-uri=https://my-auth-server/userinfo
    spring.security.oauth2.client.provider.my-oauth-provider.user-info-authentication-method=header
    spring.security.oauth2.client.provider.my-oauth-provider.jwk-set-uri=https://my-auth-server/token_keys
    spring.security.oauth2.client.provider.my-oauth-provider.user-name-attribute=name

    对于支持 OpenID Connect discovery 的 OpenID Connect 提供者,可以进一步简化配置. 需要使用 issuer-uri 配置提供者,issuer-uri 是其 Issuer Identifier 的 URI. 例如,如果提供的 issuer-uri 是 "https://example.com", 则将对 "https://example.com/.well-known/openid-configuration" 发起一个 OpenID Provider Configuration Request. 期望结果是一个 OpenID Provider Configuration Response. 以下示例展示了如何使用 issuer-uri 配置一个 OpenID Connect Provider:

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

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

    public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
                .authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                .oauth2Login()
                    .redirectionEndpoint()
                        .baseUri("/custom-callback");
    
    OAuth2 客户端注册常见的提供者

    对于常见的 OAuth2 和 OpenID 提供者 (provider) ,包括 Google、Github、Facebook 和 Okta,我们提供了一组提供者默认设置 (分别是 google、github、facebook 和 okta) .

    如果您不需要自定义这些提供者,则可以将 provider 属性设置为您需要推断默认值的属性. 此外,如果客户端注册的 key 与默认支持的提供者匹配,则 Spring Boot 也会推断出来.

    换而言之,以下示例中的两个配置使用了 Google 提供者:

    spring.security.oauth2.client.registration.my-client.client-id=abcd
    spring.security.oauth2.client.registration.my-client.client-secret=password
    spring.security.oauth2.client.registration.my-client.provider=google
    spring.security.oauth2.client.registration.google.client-id=abcd
    spring.security.oauth2.client.registration.google.client-secret=password
    spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://example.com/check-token
    spring.security.oauth2.resourceserver.opaquetoken.client-id=my-client-id
    spring.security.oauth2.resourceserver.opaquetoken.client-secret=my-client-secret

    同样,相同的属性适用于servlet和反应式应用程序.

    另外,您可以为Servlet应用程序定义自己的 OpaqueTokenIntrospector Bean,或者为反应性应用程序定义 ReactiveOpaqueTokenIntrospector.

    9.3.3. 授权服务器

    目前,Spring Security 没有提供 OAuth 2.0 授权服务器实现. 但此功能可从 Spring Security OAuth 项目获得,该项目最终会被 Spring Security 所取代. 在此之前,您可以使用 spring-security-oauth2-autoconfigure 模块轻松设置 OAuth 2.0 授权服务器,请参阅 其文档以获取详细信息.

    9.4.1. 依赖方

    如果您在类路径中具有 spring-security-saml2-service-provider,则可以利用一些自动配置功能来轻松设置SAML 2.0依赖方. 此配置利用 Saml2RelyingPartyProperties 下的属性.

    依赖方注册代表身份提供商IDP和服务提供商SP之间的配对配置. 您可以在 spring.security.saml2.relyingparty 前缀下注册多个依赖方,如以下示例所示:

    spring.security.saml2.relyingparty.registration.my-relying-party1.signing.credentials[0].private-key-location=path-to-private-key
    spring.security.saml2.relyingparty.registration.my-relying-party1.signing.credentials[0].certificate-location=path-to-certificate
    spring.security.saml2.relyingparty.registration.my-relying-party1.identityprovider.verification.credentials[0].certificate-location=path-to-verification-cert
    spring.security.saml2.relyingparty.registration.my-relying-party1.identityprovider.entity-id=remote-idp-entity-id1
    spring.security.saml2.relyingparty.registration.my-relying-party1.identityprovider.sso-url=https://remoteidp1.sso.url
    spring.security.saml2.relyingparty.registration.my-relying-party2.signing.credentials[0].private-key-location=path-to-private-key
    spring.security.saml2.relyingparty.registration.my-relying-party2.signing.credentials[0].certificate-location=path-to-certificate
    spring.security.saml2.relyingparty.registration.my-relying-party2.identityprovider.verification.credentials[0].certificate-location=path-to-other-verification-cert
    spring.security.saml2.relyingparty.registration.my-relying-party2.identityprovider.entity-id=remote-idp-entity-id2
    spring.security.saml2.relyingparty.registration.my-relying-party2.identityprovider.sso-url=https://remoteidp2.sso.url

    9.5. Actuator 安全

    出于安全考虑,默认情况下禁用除 /health/info 之外的所有 actuator. 可用 management.endpoints.web.exposure.include 属性启用 actuator.

    如果 Spring Security 位于 classpath 上且没有其他 WebSecurityConfigurerAdapter,则除了 /health/info 之外的所有 actuator 都由 Spring Boot 自动配置保护. 如果您定义了自定义 WebSecurityConfigurerAdapter,则 Spring Boot 自动配置将不再生效,您可以完全控制 actuator 的访问规则.

    Spring Framework 为 SQL 数据库提供了广泛的支持. 从直接使用 JdbcTemplate 进行 JDBC 访问到完全的对象关系映射 (object relational mapping) 技术,比如 Hibernate. Spring Data提供了更多级别的功能,直接从接口创建的 Repository 实现,并使用了约定从方法名生成查询.

    10.1. 配置数据源

    Java 的 javax.sql.DataSource 接口提供了一个使用数据库连接的标准方法. 通常,数据源使用 URL 和一些凭据信息来建立数据库连接.

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.hsqldb</groupId>
        <artifactId>hsqldb</artifactId>
        <scope>runtime</scope>
    </dependency>
    spring.datasource.url=jdbc:mysql://localhost/test
    spring.datasource.username=dbuser
    spring.datasource.password=dbpass
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver

    有关更多支持选项,请参阅 DataSourceProperties . 这些都是标准选项,与实际的实现无关. 还可以使用各自的前缀 (spring.datasource.hikari.spring.datasource.tomcat.spring.datasource.dbcp2.*) 微调实现特定的设置. 请参考您现在使用的连接池实现的文档来获取更多信息.

    例如,如果你使用 Tomcat connection pool,则可以自定义许多其他设置,如下:

    # Number of ms to wait before throwing an exception if no connection is available.
    spring.datasource.tomcat.max-wait=10000
    # Maximum number of active connections that can be allocated from this pool at the same time.
    spring.datasource.tomcat.max-active=50
    # Validate the connection before borrowing it from the pool.
    spring.datasource.tomcat.test-on-borrow=true

    10.1.3. 连接 JNDI 数据源

    如果要将 Spring Boot 应用程序部署到应用服务器 (Application Server) 上,您可能想使用应用服务器的内置功能和 JNDI 访问方式来配置和管理数据源.

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

    spring.datasource.jndi-name=java:jboss/datasources/customers
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Component;
    @Component
    public class MyBean {
        private final JdbcTemplate jdbcTemplate;
        @Autowired
        public MyBean(JdbcTemplate jdbcTemplate) {
            this.jdbcTemplate = jdbcTemplate;
        // ...
    

    您可以使用 spring.jdbc.template.* 属性来自定义一些 template 的属性,如下:

    spring.jdbc.template.max-rows=500

    10.3.1. 实体类

    通常,JPA Entity (实体) 类是在 persistence.xml 文件中指定的. 使用了 Spring Boot,该文件将不是必需的,可以使用 Entity Scanning (实体扫描) 来代替. 默认情况下,将搜索主配置类 (使用了 @EnableAutoConfiguration@SpringBootApplication 注解) 下面的所有包.

    任何用了 @Entity@Embeddable 或者 @MappedSuperclass 注解的类将被考虑. 一个典型的实体类如下:

    package com.example.myapp.domain;
    import java.io.Serializable;
    import javax.persistence.*;
    @Entity
    public class City implements Serializable {
        @GeneratedValue
        private Long id;
        @Column(nullable = false)
        private String name;
        @Column(nullable = false)
        private String state;
        // ... additional members, often include @OneToMany mappings
        protected City() {
            // no-args constructor required by JPA spec
            // this one is protected since it shouldn't be used directly
        public City(String name, String state) {
            this.name = name;
            this.state = state;
        public String getName() {
            return this.name;
        public String getState() {
            return this.state;
        // ... etc
    

    10.3.2. Spring Data JPA 资源库

    Spring Data JPA 资源库 (repository) 是接口,您可以定义用于访问数据. JAP 查询是根据您的方法名自动创建. 例如,CityRepository 接口可以声明 findAllByState(String state) 方法来查找指定状态下的所有城市.

    对于更加复杂的查询,您可以使用 Spring Data 的 Query 注解

    Spring Data 资源库通常继承自 Repository 或者 CrudRepository 接口. 如果您使用了自动配置,则将从包含主配置类 (使用了 @EnableAutoConfiguration@SpringBootApplication 注解) 的包中搜索资源库:

    以下是一个典型的 Spring Data 资源库接口定义:

    package com.example.myapp.domain;
    import org.springframework.data.domain.*;
    import org.springframework.data.repository.*;
    public interface CityRepository extends Repository<City, Long> {
        Page<City> findAll(Pageable pageable);
        City findByNameAndStateAllIgnoringCase(String name, String state);
    

    Spring Data JPA 资源库支持三种不同的引导模式: defaultdeferredlazy. 要启用延迟或懒惰引导,请将 spring.data.jpa.repositories.bootstrap-mode 分别设置为 deferredlazy. 使用延迟或延迟引导时,自动配置的 EntityManagerFactoryBuilder 将使用上下文的 AsyncTaskExecutor (如果有) 作为 applicationTaskExecutor.

    10.4. Spring Data JDBC

    Spring Data 包含了对 JDBC 资源库的支持,并将自动为 CrudRepository 上的方法生成 SQL. 对于更高级的查询,它提供了 @Query 注解.

    当 classpath 下存在必要的依赖时,Spring Boot 将自动配置 Spring Data 的 JDBC 资源库. 可以通过添加单个 spring-boot-starter-data-jdbc 依赖引入到项目中. 如有必要,可通过在应用程序中添加 @EnableJdbcRepositories 注解或 JdbcConfiguration 子类来控制 Spring Data JDBC 的配置.

    10.6. 使用 jOOQ

    Java 面向对象查询 (Java Object Oriented Querying, jOOQ) 是一款广受欢迎的产品,出自 Data Geekery,它可以通过数据库生成 Java 代码,并允许您使用流式 API 来构建类型安全的 SQL 查询. 商业版和开源版都可以与 Spring Boot 一起使用.

    10.6.1. 代码生成

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

    <plugin>
        <groupId>org.jooq</groupId>
        <artifactId>jooq-codegen-maven</artifactId>
        <executions>
        </executions>
        <dependencies>
            <dependency>
                <groupId>com.h2database</groupId>
                <artifactId>h2</artifactId>
                <version>${h2.version}</version>
            </dependency>
        </dependencies>
        <configuration>
                <driver>org.h2.Driver</driver>
                <url>jdbc:h2:~/yourdatabase</url>
            </jdbc>
            <generator>
            </generator>
        </configuration>
    </plugin>
    public List<GregorianCalendar> authorsBornAfter1980() {
        return this.create.selectFrom(AUTHOR)
            .where(AUTHOR.DATE_OF_BIRTH.greaterThan(new GregorianCalendar(1980, 0, 1)))
            .fetch(AUTHOR.DATE_OF_BIRTH);
    

    Spring Boot为Redis,MongoDB,Neo4j,Elasticsearch,Solr Cassandra,Couchbase和LDAP提供自动配置. 您可以使用其他项目,但必须自己进行配置. 请参阅 spring.io/projects/spring-data 中的相应参考文档.

    11.1. Redis

    Redis 是一个集缓存、消息代理和键值存储等丰富功能的数据库. Spring Boot 为 LettuceJedis 客户端类库提供了基本自动配置, Spring Data Redis 为他们提供了上层抽象.

    使用 spring-boot-starter-data-redis starter 可方便地引入相关依赖. 默认情况下,它使用 Lettuce. 该 starter 可处理传统应用程序和响应式应用程序.

    11.2. MongoDB

    MongoDB 是一个开源的 NoSQL 文档数据库,其使用了类似 JSON 的模式 (schema) 来替代传统基于表的关系数据. Spring Boot 为 MongoDB 提供了几种便利的使用方式,包括 spring-boot-starter-data-mongodbspring-boot-starter-data-mongodb-reactive starter.

    11.2.1. 连接 MongoDB 数据库

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

    import org.springframework.data.mongodb.MongoDbFactory;
    import com.mongodb.DB;
    @Component
    public class MyBean {
        private final MongoDbFactory mongo;
        @Autowired
        public MyBean(MongoDbFactory mongo) {
            this.mongo = mongo;
        // ...
        public void example() {
            DB db = mongo.getDb();
            // ...
    

    您可以通过设置 spring.data.mongodb.uri 属性来更改 URL 和配置其他设置,如副本集 (replica set) :

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

    另外,只要您使用了 Mongo 2.x,请指定 host/port. 比如,您可能要在 application.properties 中声明以下内容:

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

    如果您已经定义了自己的 MongoClient,它将被用于自动配置合适的 MongoDbFactory. 支持 com.mongodb.MongoClientcom.mongodb.client.MongoClient.

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.mongodb.core.MongoTemplate;
    import org.springframework.stereotype.Component;
    @Component
    public class MyBean {
        private final MongoTemplate mongoTemplate;
        @Autowired
        public MyBean(MongoTemplate mongoTemplate) {
            this.mongoTemplate = mongoTemplate;
        // ...
    

    更多详细信息,参照 MongoOperations Javadoc .

    11.2.3. Spring Data MongoDB Repositories

    Spring Data 包含了对 MongoDB 资源库 (repository) 的支持. 与之前讨论的 JPA 资源库一样,基本原理是根据方法名称自动构建查询.

    事实上,Spring Data JPA 和 Spring Data MongoDB 共享通用的底层代码,因此你可以拿之前提到的 JPA 示例作为基础,假设 City 现在是一个 Mongo 数据类,而不是一个 JPA @Entity,他们方式工作相同:

    package com.example.myapp.domain;
    import org.springframework.data.domain.*;
    import org.springframework.data.repository.*;
    public interface CityRepository extends Repository<City, Long> {
        Page<City> findAll(Pageable pageable);
        City findByNameAndStateAllIgnoringCase(String name, String state);
    

    11.2.4. 内嵌 Mongo

    Spring Boot 提供了 内嵌 Mongo的自动配置. 要在 Spring Boot 应用程序中使用它,请添加依赖 de.flapdoodle.embed:de.flapdoodle.embed.mongo.

    可以使用 spring.data.mongodb.port 属性来配置 Mongo 的监听端口. 如果想随机分配空闲端口,请把值设置为 0. MongoAutoConfiguration 创建的 MongoClient 将自动配置随机分配的端口.

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

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

    可以通过声明 DownloadConfigBuilderCustomizer bean来定制下载配置.

    11.3. Neo4j

    Neo4j 是一个开源的 NoSQL 图形数据库,它使用了一个节点由关系连接的富数据模型,比传统 RDBMS 的方式更适合连接大数据. Spring Boot 为 Neo4j 提供了便捷引入方式,包括 spring-boot-starter-data-neo4j starter.

    11.3.1. 连接 Neo4j 数据库

    您可以像任何 Spring Bean 一样注入一个自动配置的 org.neo4j.ogm.session.Session. 默认情况下, 该实例将尝试使用在 localhost:7687 上使用 Bolt 协议连接到 Neo4j 服务器,以下示例展示了如何注入 一个 Neo4j Session:

    @Component
    public class MyBean {
        private final Session session;
        @Autowired
        public MyBean(Session session) {
            this.session = session;
        // ...
    

    您可以通过配置 spring.data.neo4j.* 属性来设置 uri 和凭据:

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

    您可以通过添加自己的 org.neo4j.ogm.config.Configuration Bean 来完全控制 session 创建. 此外,添加 SessionFactory 类型的 Bean 会禁用自动配置,因此您可以掌控所有.

    11.3.2. 使用内嵌模式

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

    import org.springframework.data.neo4j.repository.*; public interface CityRepository extends Neo4jRepository<City, Long> { Optional<City> findOneByNameAndState(String name, String state);

    spring-boot-starter-data-neo4j starter 支持资源库和事务管理. 您可以在 @Configuration bean 上分别使用 @EnableNeo4jRepositories@EntityScan 来自定义位置以查找资源库和实体.

    11.4. Solr

    Apache Solr 是一个搜素引擎. Spring Boot 为 Solr 5 客户端类库提供了基本的自动配置,并且 Spring Data Solr 为其提供给了顶层抽象. 相关的依赖包含在了 spring-boot-starter-data-solr starter 中.

    11.4.1. 连接 Solr

    您可以像其他 Spring Bean 一样注入一个自动配置的 SolrClient 实例. 默认情况下,该实例将尝试通过 localhost:8983/solr 连接到服务器,以下示例展示了如何注入一个 Solr bean:

    @Component
    public class MyBean {
        private SolrClient solr;
        @Autowired
        public MyBean(SolrClient solr) {
            this.solr = solr;
        // ...
    

    如果您添加了自己的 SolrClient 类型的 @Bean,它将替换掉默认配置.

    11.4.2. Spring Data Solr 资源库

    Spring Data 包含了对 Apache Solr 资源库的支持. 与之前讨论的 JPA 资源库一样,基本原理是根据方法名称自动构造查询.

    事实上,Spring Data JPA 和 Spring Data Solr 共享了相同的通用底层代码,因此您可以使用之前的 JPA 示例作为基础,假设 City 现在是一个 @SolrDocument 类,而不是一个 JPA @Entity,它的工作方式相同.

    11.5. Elasticsearch

    Elasticsearch 是一个开源、分布式、RESTful 的实时搜索分析引擎. Spring Boot 为 Elasticsearch 提供了基本的自动配置.

    Spring Boot 支持以下 HTTP 客户端:

    Spring Boot 支持以下 HTTP 客户端:

    Spring Data Elasticsearch 依旧使用传输客户端,但是Spring Data Elasticsearch和Elasticsearch本身已弃用了它的支持. 它将在将来的版本中删除. 您可以使用 spring-boot-starter-data-elasticsearch starter 引入使用它.

    由于Elasticsearch和Spring Data Elasticsearch为REST客户端提供了官方支持,因此 Jest 客户端也已被弃用.

    11.5.1. 使用 REST 客户端连接 Elasticsearch

    Elasticsearch 提供了 两个可用于查询集群的 REST 客户端 : Low Level (低级) 和 High Level (高级) .

    如果您的 classpath 上存在 org.elasticsearch.client:elasticsearch-rest-client 依赖,则 Spring Boot 将自动配置并注册默认目标为 localhost:9200RestClient bean. 您可以进一步调整 RestClient 的配置,如下所示:

    spring.elasticsearch.rest.uris=https://search.example.com:9200
    spring.elasticsearch.rest.read-timeout=10s
    spring.elasticsearch.rest.username=user
    spring.elasticsearch.rest.password=secret

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

    如果你 classpath 上有 org.elasticsearch.client:elasticsearch-rest-high-level-client 依赖,Spring Boot 将自动配置一个 RestHighLevelClient,它包装了所有现有的 RestClient bean,重用其 HTTP 配置.

    11.5.2. 使用 Reactive REST 客户端连接

    Spring Data Elasticsearch 提供了 ReactiveElasticsearchClient,用于以响应式查询 Elasticsearch 实例. 它基于 WebFlux的WebClient 构建,因此 spring-boot-starter-elasticsearchspring-boot-starter-webflux 依赖.

    默认情况下,Spring Boot将自动配置并注册一个针对 localhost:9200ReactiveElasticsearchClient bean. 您可以进一步调整其配置,如以下示例所示:

    spring.data.elasticsearch.client.reactive.endpoints=search.example.com:9200
    spring.data.elasticsearch.client.reactive.use-ssl=true
    spring.data.elasticsearch.client.reactive.socket-timeout=10s
    spring.data.elasticsearch.client.reactive.username=user
    spring.data.elasticsearch.client.reactive.password=secret

    如果配置属性不够,并且您想完全控制客户端配置,则可以注册自定义 ClientConfiguration bean.

    11.5.3. 使用 Jest 连接 Elasticsearch

    现在,Spring Boot支持官方的 RestHighLevelClient,不再支持 Jest.

    如果您的 classpath 上存在 Jest,则可以注入一个默认目标为 localhost:9200. 的自动配置 JestClient. 您还可以进一步调整客户端配置:

    spring.elasticsearch.jest.uris=https://search.example.com:9200
    spring.elasticsearch.jest.read-timeout=10000
    spring.elasticsearch.jest.username=user
    spring.elasticsearch.jest.password=secret

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

    static class HttpSettingsCustomizer implements HttpClientConfigBuilderCustomizer {
        @Override
        public void customize(HttpClientConfig.Builder builder) {
            builder.maxTotalConnection(100).defaultMaxTotalConnectionPerRoute(5);
    

    要完全控制注册流程,请定义一个 JestClient bean.

    11.5.4. 使用 Spring Data 连接 Elasticsearch

    要连接 Elasticsearch,必须定义由Spring Boot自动配置或由应用程序手动提供的 RestHighLevelClient bean (请参阅前面的部分) . 有了此配置后,可以像其他任何Spring bean一样注入 ElasticsearchRestTemplate,如以下示例所示:

    @Component
    public class MyBean {
        private final ElasticsearchRestTemplate template;
        public MyBean(ElasticsearchRestTemplate template) {
            this.template = template;
        // ...
    

    如果存在 spring-data-elasticsearch 和使用 WebClient 所需的依赖关系 (通常是 spring-boot-starter-webflux) 的情况下,Spring Boot还可以将 ReactiveElasticsearchClientReactiveElasticsearchTemplate 自动配置为bean. 它们与其他REST客户端是等效的.

    11.5.5. Spring Data Elasticsearch 资源库

    Spring Data 包含了对 Elasticsearch 资源库的支持,与之前讨论的 JPA 资源库一样,其原理是根据方法名称自动构造查询.

    事实上,Spring Data JPA 与 Spring Data Elasticsearch 共享了相同的通用底层代码,因此您可以使用之前的 JPA 示例作为基础,假设 City 此时是一个 Elasticsearch @Document 类,而不是一个 JPA @Entity,它以相同的方式工作.

    Spring Boot使用 ElasticsearchRestTemplateReactiveElasticsearchTemplate bean支持经典和响应式式 Elasticsearch 资源库. 给定所需的依赖,最有可能由Spring Boot自动配置这些bean.

    如果您希望使用自己的模板来支持Elasticsearch存储库,则可以添加自己的 ElasticsearchRestTemplateElasticsearchOperations @Bean,只要它名为 "elasticsearchTemplate" 即可. 同样适用于 ReactiveElasticsearchTemplateReactiveElasticsearchOperations,其bean名称为 "reactiveElasticsearchTemplate".

    您可以选择使用以下属性禁用存储库支持:

    spring.data.elasticsearch.repositories.enabled=false

    11.6. Cassandra

    Cassandra 是一个开源的分布式数据库管理系统,旨在处理商用服务器上的大量数据. Spring Boot 为 Cassandra 提供了自动配置,且 Spring Data Cassandra 为其提供了顶层抽象. 相关依赖包含在 spring-boot-starter-data-cassandra starter 中.

    11.6.1. 连接 Cassandra

    您可以像其他 Spring Bean 一样注入一个自动配置的 CassandraTemplate 或 Cassandra Session 实例. spring.data.cassandra.* 属性可用于自定义连接. 通常,您会提供 keyspace-namecontact-points 属性:

    spring.data.cassandra.keyspace-name=mykeyspace
    spring.data.cassandra.contact-points=cassandrahost1,cassandrahost2

    您还可以注册任意数量实现了 ClusterBuilderCustomizer 的 bean,以进行更高级的自定义.

    以下代码展示了如何注入一个 Cassandra bean:

    @Component
    public class MyBean {
        private CassandraTemplate template;
        public MyBean(CassandraTemplate template) {
            this.template = template;
        // ...
    

    如果您添加了自己的类的为 @CassandraTemplate@Bean,则其将替代默认值.

    11.6.2. Spring Data Cassandra 资源库

    Spring Data 包含了基本的 Cassandra 资源库支持. 目前,其限制要比之前讨论的 JPA 资源库要多,并且需要在 finder 方法上使用 @Query 注解.

    11.7. Couchbase

    Couchbase 是一个开源、分布式多模型的 NoSQL 面向文档数据库,其针对交互式应用程序做了优化. Spring Boot 为 Couchbase 提供了自动配置, 且 Spring Data Couchbase 为其提供了顶层抽象. 相关的依赖包含在了 spring-boot-starter-data-couchbase starter 中.

    11.7.1. 连接 Couchbase

    您可以通过添加 Couchbase SDK 和一些配置来轻松获取 BucketCluster. spring.couchbase.* 属性可用于自定义连接. 通常您会配置 bootstrap host、bucket name 和 password:

    spring.couchbase.bootstrap-hosts=my-host-1,192.168.1.123
    spring.couchbase.bucket.name=my-bucket
    spring.couchbase.bucket.password=secret
    spring.couchbase.env.timeouts.connect=3000
    spring.couchbase.env.ssl.key-store=/location/of/keystore.jks
    spring.couchbase.env.ssl.key-store-password=secret

    查看 spring.couchbase.env.* 获取更多详细内容.

    11.7.2. Spring Data Couchbase 资源库

    Spring Data 包含了 Couchbase 资源库支持. 有关 Spring Data Couchbase 的完整详细信息,请参阅其 参考文档.

    您可以像使用其他 Spring Bean 一样注入自动配置的 CouchbaseTemplate 实例,前提是有一个默认的 CouchbaseConfigurer (当您启用 Couchbase 支持时会发生这种情况,如之前所述) .

    以下示例展示了如何注入一个 Couchbase bean:

    @Component
    public class MyBean {
        private final CouchbaseTemplate template;
        @Autowired
        public MyBean(CouchbaseTemplate template) {
            this.template = template;
        // ...
    

    您可以在自己的配置中定义以下几个 bean,以覆盖自动配置提供的配置:

    @Bean(BeanNames.COUCHBASE_CUSTOM_CONVERSIONS) public CustomConversions myCustomConversions() { return new CustomConversions(...); // ...

    11.8. LDAP

    LDAP (Lightweight Directory Access Protocol,轻量级目录访问协议) 是一个开放、厂商中立的行业标准应用协议,其通过 IP 网络访问和维护分布式目录信息服务. Spring Boot 为兼容 LDAP 服务器提供了自动配置,以及支持从 UnboundID 内嵌内存式 LDAP 服务器.

    Spring Data LDAP 提供了 LDAP 抽象. 相关依赖包含在了 spring-boot-starter-data-ldap starter 中.

    11.8.1. 连接 LDAP 服务器

    要连接 LDAP 服务器,请确保您已经声明了 spring-boot-starter-data-ldap starter 或者 spring-ldap-core 依赖,然后在 application.properties 声明服务器的 URL:

    spring.ldap.urls=ldap://myserver:1235
    spring.ldap.username=admin
    spring.ldap.password=secret

    如果需要自定义连接设置,您可以使用 spring.ldap.basespring.ldap.base-environment 属性.

    LdapContextSource 将根据这些设置自动配置. 如果您需要自定义它,例如使用一个 PooledContextSource,则仍然可以注入自动配置的 LdapContextSource. 确保将自定义的 ContextSource 标记为 @Primary,以便自动配置的 LdapTemplate 能使用它.

    11.8.2. Spring Data LDAP 资源库

    Spring Data 包含了 LDAP 资源库支持. 有关 Spring Data LDAP 的完整详细信息,请参阅其 参考文档.

    您还可以像其他 Spring Bean 一样注入一个自动配置的 LdapTemplate 实例:

    @Component
    public class MyBean {
        private final LdapTemplate template;
        @Autowired
        public MyBean(LdapTemplate template) {
            this.template = template;
        // ...
    

    如果您的 classpath 上存在一个 schema.ldif 文件,其将用于初始化服务器. 如果您想从不同的资源中加载脚本,可以使用 spring.ldap.embedded.ldif 属性.

    默认情况下,将使用一个标准模式 (schema) 来校验 LDIF 文件. 您可以使用 spring.ldap.embedded.validation.enabled 属性来关闭所有校验. 如果您有自定义的属性,则可以使用 spring.ldap.embedded.validation.schema 来定义自定义属性类型或者对象类.

    11.9. InfluxDB

    InfluxDB 是一个开源时列数据库,其针对运营监控、应用程序指标、物联网传感器数据和实时分析等领域中的时间序列数据在速度、高可用存储和检索方面进行了优化.

    11.9.1. 连接 InfluxDB

    Spring Boot 自动配置 InfluxDB 实例,前提是 Influxdb-java 客户端在 classpath 上并且设置了数据库的 URL,如下所示:

    spring.influx.url=https://172.0.0.1:8086

    如果与 InfluxDB 的连接需要用户和密码,则可以相应地设置 spring.influx.userspring.influx.password 属性.

    InfluxDB 依赖于 OkHttp. 如果你需要调整 InfluxDB 在底层使用的 http 客户端,则可以注册一个 InfluxDbOkHttpClientBuilderProvider bean.

    import org.springframework.cache.annotation.Cacheable;
    import org.springframework.stereotype.Component;
    @Component
    public class MathService {
        @Cacheable("piDecimals")
        public int computePiDecimal(int i) {
            // ...
    

    此示例展示了如何在代价可能高昂的操作上使用缓存. 在调用 computePiDecimal 之前,缓存支持会在 piDecimals 缓存中查找与 i 参数匹配的项. 如果找到,则缓存中的内容会立即返回给调用者,并不会调用该方法. 否则,将调用该方法,并在返回值之前更新缓存.

    如果您不添加任何指定的缓存库,Spring Boot 会自动配置一个使用并发 map 的 simple provider . 当需要缓存时 (例如前面示例中的 piDecimals) ,该 simple provider 会为您创建缓存. 不推荐将 simple provider 用于生产环境,但它非常适合入门并帮助您了解这些功能. 当您决定使用缓存提供者时,请务必阅读其文档以了解如何配置应用程序. 几乎所有提供者都要求您显式配置应用程序中使用的每个缓存. 有些提供了自定义 spring.cache.cache-names 属性以定义默认缓存.

    12.1. 支持的缓存提供者

    缓存抽象不提供存储实现,其依赖于 org.springframework.cache.Cacheorg.springframework.cache.CacheManager 接口实现的抽象.

    如果您未定义 CacheManager 类型的 bean 或名为 cacheResolverCacheResolver (请参阅 CachingConfigurer) ,则 Spring Boot 会尝试检测以下提供者 (按序号顺序) :

    @Bean
    public CacheManagerCustomizer<ConcurrentMapCacheManager> cacheManagerCustomizer() {
        return new CacheManagerCustomizer<ConcurrentMapCacheManager>() {
            @Override
            public void customize(ConcurrentMapCacheManager cacheManager) {
                cacheManager.setAllowNullValues(false);
    

    12.1.2. JCache (JSR-107)

    JCache 通过 classpath 上的 javax.cache.spi.CachingProvider (即 classpath 上存在符合 JSR-107 的缓存库) 来引导,jCacheCacheManagerspring-boot-starter-cache starter 提供. 您可以使用各种兼容库,Spring Boot 为 Ehcache 3、Hazelcast 和 Infinispan 提供依赖管理. 您还可以添加任何其他兼容库.

    可能存在多个提供者,在这种情况下必须明确指定提供者. 即使 JSR-107 标准没有强制规定一个定义配置文件位置的标准化方法,Spring Boot 也会尽其所能设置一个包含实现细节的缓存,如下所示:

    # Only necessary if more than one provider is present
    spring.cache.jcache.provider=com.acme.MyCachingProvider
    spring.cache.jcache.config=classpath:acme.xml

    可以通过设置 spring.cache.cache-names 属性在启动时创建缓存. 如果定义了自定义 javax.cache.configuration.Configuration bean,则会使用它来自定义.

    使用 CacheManager 的引用调用 org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer bean 以进行完全自定义.

    12.1.6. Couchbase

    如果 Couchbase Java 客户端和 couchbase-spring-cache 实现可用且已经配置Couchbase,则应用程序会自动配置一个 CouchbaseCacheManager. 也可以通过设置 spring.cache.cache-names 属性在启动时创建其他缓存. 这些缓存在自动配置的 Bucket 上操作. 您还可以使用 customizer 在其他 Bucket 上创建缓存. 假设您需要在 main Bucket 上有两个缓存 (cache1cache2) ,并且 “another” Bucket 有一个过期时间为 2 秒的缓存 (cache3) . 您可以通过配置创建这两个缓存,如下所示:

    spring.cache.cache-names=cache1,cache2

    然后,您可以定义一个 @Configuration 类来配置其他 Bucketcache3 缓存,如下所示:

    @Configuration(proxyBeanMethods = false)
    public class CouchbaseCacheConfiguration {
        private final Cluster cluster;
        public CouchbaseCacheConfiguration(Cluster cluster) {
            this.cluster = cluster;
        @Bean
        public Bucket anotherBucket() {
            return this.cluster.openBucket("another", "secret");
        @Bean
        public CacheManagerCustomizer<CouchbaseCacheManager> cacheManagerCustomizer() {
            return c -> {
                c.prepareCache("cache3", CacheBuilder.newInstance(anotherBucket())
                        .withExpiration(2));
    

    此示例配置复用了通过自动配置创建的 Cluster.

    12.1.7. Redis

    如果 Redis 可用并已经配置,则应用程序会自动配置一个 RedisCacheManager. 通过设置 spring.cache.cache-names 属性可以在启动时创建其他缓存,并且可以使用 spring.cache.redis.* 属性配置缓存默认值. 例如,以下配置创建 cache1cache2 缓存,他们的有效时间为 10 分钟:

    spring.cache.cache-names=cache1,cache2
    spring.cache.redis.time-to-live=600000

    如果您需要控制更多的配置,请考虑注册 RedisCacheManagerBuilderCustomizer bean. 以下示例显示了一个自定义的配置,该定制器配置了 cache1cache2 的特定生存时间 The following example shows a customizer that configures a specific time to live for cache1 and cache2:

    @Bean
    public RedisCacheManagerBuilderCustomizer myRedisCacheManagerBuilderCustomizer() {
        return (builder) -> builder
                .withCacheConfiguration("cache1",
                        RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(10)))
                .withCacheConfiguration("cache2",
                        RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(1)));
    

    12.1.8. Caffeine

    Caffeine 是一个使用了 Java 8 重写 Guava 缓存,用于取代 Guava 支持的缓存库. 如果 Caffeine 存在,则应用程序会自动配置一个 CaffeineCacheManager (由 spring-boot-starter-cache starter 提供) . 可以通过设置 spring.cache.cache-names 属性在启动时创建缓存,并且可以通过以下方式之一 (按序号顺序) 自定义缓存:

    Spring Framework 为消息传递系统集成提供了广泛的支持,从使用 JmsTemplate 简化 JMS API 的使用到异步接收消息的完整基础设施. Spring AMQP 为高级消息队列协议 (Advanced Message Queuing Protocol,AMQP) 提供了类似的功能集合. Spring Boot 还为 RabbitTemplate 和 RabbitMQ 提供自动配置选项. Spring WebSocket 本身包含了对 STOMP 消息传递的支持,Spring Boot 通过 starter 和少量自动配置即可支持它. Spring Boot 同样支持 Apache Kafka.

    13.1. JMS

    javax.jms.ConnectionFactory 接口提供了一种创建 javax.jms.Connection 的标准方法,可与 JMS broker (代理) 进行交互. 虽然 Spring 需要一个 ConnectionFactory 来与 JMS 一同工作,但是您通常不需要自己直接使用它,而是可以依赖更高级别的消息传递抽象. (有关详细信息,请参阅 Spring Framework 参考文档的相关部分. ) Spring Boot 还会自动配置发送和接收消息所需的基础设施.

    13.1.1. ActiveMQ 支持

    ActiveMQ 在 classpath 上可用时,Spring Boot 也可以配置一个 ConnectionFactory. 如果 broker 存在,则会自动启动并配置一个内嵌式 broker (前提是未通过配置指定 broder URL) .

    13.1.2. Artemis 支持

    Spring Boot 可以在检测到 Artemis 在 classpath 上可用时自动配置一个 ConnectionFactory. 如果存在 broker,则会自动启动并配置一个内嵌 broker (除非已明确设置 mode 属性) . 支持的 mode 为 embedded (明确表示需要一个内嵌 broker,如果 broker 在 classpath 上不可用则发生错误) 和 native (使用 netty 传输协议连接到 broker) . 配置后者后,Spring Boot 会使用默认设置配置一个 ConnectionFactory,该 ConnectionFactory 连接到在本地计算机上运行的 broker.

    内嵌 broker 时,您可以选择是否要启用持久化并列出应该可用的 destination. 可以将这些指定为以逗号分隔的列表,以使用默认选项创建它们,也可以定义类型为 org.apache.activemq.artemis.jms.server.config.JMSQueueConfigurationorg.apache.activemq.artemis.jms.server.config.TopicConfiguration 的 bean,分别用于高级队列和 topic (主题) 配置.

    默认情况下,CachingConnectionFactory 将原生的 ConnectionFactory 使用可由 spring.jms.* 中的外部配置属性控制的合理设置包装起来:

    spring.jms.cache.session-cache-size=5

    如果您更愿意使用原生池,则可以通过向 org.messaginghub:pooled-jms 添加一个依赖并相应地配置 JmsPoolConnectionFactory 来实现,如下所示:

    spring.artemis.pool.enabled=true
    spring.artemis.pool.max-connections=50

    有关更多支持的选项,请参阅 ArtemisProperties .

    不涉及 JNDI 查找,使用 Artemis 配置中的 name 属性或通过配置提供的名称来解析目标 (destination) 名称.

    13.1.3. 使用 JNDI ConnectionFactory

    如果您在应用程序服务器中运行应用程序,Spring Boot 会尝试使用 JNDI 找到 JMS ConnectionFactory. 默认情况下,将检查 java:/JmsXAjava:/XAConnectionFactory 这两个位置. 如果需要指定其他位置,可以使用 spring.jms.jndi-name 属性,如下所示:

    spring.jms.jndi-name=java:/MyConnectionFactory
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jms.core.JmsTemplate;
    import org.springframework.stereotype.Component;
    @Component
    public class MyBean {
        private final JmsTemplate jmsTemplate;
        @Autowired
        public MyBean(JmsTemplate jmsTemplate) {
            this.jmsTemplate = jmsTemplate;
        // ...
    

    13.1.5. 接收消息

    当存在 JMS 基础设施时,可以使用 @JmsListener 对任何 bean 进行注解以创建监听器 (listener) 端点. 如果未定义 JmsListenerContainerFactory,则会自动配置一个默认的 (factory) . 如果定义了 DestinationResolverMessageConverter bean,它将自动关联到默认的 factory.

    默认情况下,默认 factory 是具有事务特性的. 如果您在存在有 JtaTransactionManager 的基础设施中运行,则默认情况下它与监听器容器相关联. 如果不是,则 sessionTransacted flag 将为启用 (enabled) . 在后一种情况下,您可以通过在监听器方法 (或其委托) 上添加 @Transactional,将本地数据存储事务与传入消息的处理相关联. 这确保了在本地事务完成后传入消息能被告知. 这还包括了发送已在同一 JMS 会话上执行的响应消息.

    以下组件在 someQueue destination 上创建一个监听器端点:

    @Component
    public class MyBean {
        @JmsListener(destination = "someQueue")
        public void processMessage(String content) {
            // ...
    

    如果需要创建更多 JmsListenerContainerFactory 实例或覆盖默认值,Spring Boot 会提供一个 DefaultJmsListenerContainerFactoryConfigurer,您可以使用它来初始化 DefaultJmsListenerContainerFactory,其设置与自动配置的 factory 设置相同.

    例如,以下示例暴露了另一个使用特定 MessageConverter 的 factory:

    @Configuration(proxyBeanMethods = false)
    static class JmsConfiguration {
        @Bean
        public DefaultJmsListenerContainerFactory myFactory(
                DefaultJmsListenerContainerFactoryConfigurer configurer) {
            DefaultJmsListenerContainerFactory factory =
                    new DefaultJmsListenerContainerFactory();
            configurer.configure(factory, connectionFactory());
            factory.setMessageConverter(myMessageConverter());
            return factory;
    

    然后,您可以在任何 @JmsListener 注解的方法中使用该 factory,如下所示:

    @Component
    public class MyBean {
        @JmsListener(destination = "someQueue", containerFactory="myFactory")
        public void processMessage(String content) {
            // ...
    

    13.2. AMQP

    高级消息队列协议 (Advanced Message Queuing Protocol,AMQP) 是一个平台无关,面向消息中间件的连接级协议. Spring AMQP 项目将核心 Spring 概念应用于基于 AMQP 消息传递解决方案的开发. Spring Boot 为通过 RabbitMQ 使用 AMQP 提供了一些快捷方法,包括 spring-boot-starter-amqp starter.

    13.2.1. RabbitMQ 支持

    RabbitMQ 是一个基于 AMQP 协议的轻量级、可靠、可扩展且可移植的消息代理. Spring 使用 RabbitMQ 通过 AMQP 协议进行通信.

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

    spring.rabbitmq.host=localhost
    spring.rabbitmq.port=5672
    spring.rabbitmq.username=admin
    spring.rabbitmq.password=secret

    另外,您可以配置相同 addresses 属性的连接:

    spring.rabbitmq.addresses=amqp://admin:secret@localhost

    如果上下文中存在 ConnectionNameStrategy bean,它将自动用于命名由自动配置的 ConnectionFactory 所创建的连接. 有关更多支持的选项,请参阅 RabbitProperties .

    import org.springframework.amqp.core.AmqpAdmin;
    import org.springframework.amqp.core.AmqpTemplate;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    @Component
    public class MyBean {
        private final AmqpAdmin amqpAdmin;
        private final AmqpTemplate amqpTemplate;
        @Autowired
        public MyBean(AmqpAdmin amqpAdmin, AmqpTemplate amqpTemplate) {
            this.amqpAdmin = amqpAdmin;
            this.amqpTemplate = amqpTemplate;
        // ...
    

    13.2.3. 接收消息

    当 Rabbit 基础设施存在时,可以使用 @RabbitListener 注解任何 bean 以创建监听器端点. 如果未定义 RabbitListenerContainerFactory,则会自动配置一个默认的 SimpleRabbitListenerContainerFactory,您可以使用 spring.rabbitmq.listener.type 属性切换到一个直接容器. 如果定义了 MessageConverterMessageRecoverer bean,它将自动与默认 factory 关联.

    以下示例组件在 someQueue 队列上创建一个监听监听器端点:

    @Component
    public class MyBean {
        @RabbitListener(queues = "someQueue")
        public void processMessage(String content) {
            // ...
        @Bean
        public SimpleRabbitListenerContainerFactory myFactory(
                SimpleRabbitListenerContainerFactoryConfigurer configurer) {
            SimpleRabbitListenerContainerFactory factory =
                    new SimpleRabbitListenerContainerFactory();
            configurer.configure(factory, connectionFactory);
            factory.setMessageConverter(myMessageConverter());
            return factory;
    

    然后,您可以在任何 @RabbitListener 注解的方法中使用该 factory,如下所示:

    @Component
    public class MyBean {
        @RabbitListener(queues = "someQueue", containerFactory="myFactory")
        public void processMessage(String content) {
            // ...
    

    您可以启用重试机制来处理监听器的异常抛出情况. 默认情况下使用 RejectAndDontRequeueRecoverer,但您可以定义自己的 MessageRecoverer. 如果 broker 配置了重试机制,当重试次数耗尽时,则拒绝消息并将其丢弃或路由到死信 (dead-letter) exchange 中. 默认情况下重试机制为禁用. 您还可以通过声明 RabbitRetryTemplateCustomizer bean 以编程方式自定义 RetryTemplate.

    @Autowired public MyBean(KafkaTemplate kafkaTemplate) { this.kafkaTemplate = kafkaTemplate; // ...

    13.3.2. 接收消息

    当存在 Apache Kafka 基础设施时,可以使用 @KafkaListener 注解任何 bean 以创监听器端点. 如果未定义 KafkaListenerContainerFactory,则会使用 spring.kafka.listener.* 中定义的 key 自动配置一个默认的 factory.

    以下组件在 someTopic topic 上创建一个监听器端点:

    @Component
    public class MyBean {
        @KafkaListener(topics = "someTopic")
        public void processMessage(String content) {
            // ...
    

    如果定义了 KafkaTransactionManager bean,它将自动关联到容器 factory. 同样,如果定义了 RecordMessageConverterErrorHandlerAfterRollbackProcessor bean,它将自动关联到默认的 factory.

    根据监听器类型,将 RecordMessageConverterBatchMessageConverter bean与默认工厂关联. 如果对于批处理监听器仅存在一个 RecordMessageConverter bean,则将其包装在 BatchMessageConverter 中.

    13.3.3. Kafka Streams

    Spring for Apache Kafka 提供了一个工厂 bean 来创建 StreamsBuilder 对象并管理其 stream (流) 的生命周期. 只要 kafka-streams 在 classpath 上并且通过 @EnableKafkaStreams 注解启用了 Kafka Stream,Spring Boot 就会自动配置所需的 KafkaStreamsConfiguration bean.

    启用 Kafka Stream 意味着必须设置应用程序 id 和引导服务器 (bootstrap server) . 可以使用 spring.kafka.streams.application-id 配置前者,如果未设置则默认为 spring.application.name. 后者可以全局设置或专门为 stream 而重写.

    使用专用 properties 可以设置多个其他属性,可以使用 spring.kafka.streams.properties 命名空间设置其他任意 Kafka 属性. 有关更多信息,另请参见 Kafka 属性 .

    要使用 factory bean,只需将 StreamsBuilder 装配到您的 @Bean 中,如下所示:

    @Configuration(proxyBeanMethods = false)
    @EnableKafkaStreams
    public static class KafkaStreamsExampleConfiguration {
        @Bean
        public KStream<Integer, String> kStream(StreamsBuilder streamsBuilder) {
            KStream<Integer, String> stream = streamsBuilder.stream("ks1In");
            stream.map((k, v) -> new KeyValue<>(k, v.toUpperCase())).to("ks1Out",
                    Produced.with(Serdes.Integer(), new JsonSerde<>()));
            return stream;
    

    默认情况下,由其创建的 StreamBuilder 对象管理的流会自动启动. 您可以使用 spring.kafka.streams.auto-startup 属性自定义此行为.

    13.3.4. 其他 Kafka 属性

    自动配置支持的属性可在常见应用程序属性常见应用程序属性中找到. 请注意,在大多数情况下,这些属性 (连接符或驼峰命名) 直接映射到 Apache Kafka 点连形式属性. 有关详细信息,请参阅 Apache Kafka 文档.

    这些属性中的前几个适用于所有组件 (生产者 [producer] 、使用者 [consumer] 、管理者 [admin] 和流 [stream] ) ,但如果您希望使用不同的值,则可以在组件级别指定. Apache Kafka 重要性 (优先级) 属性设定为 HIGH、MEDIUM 或 LOW. Spring Boot 自动配置支持所有 HIGH 重要性属性,一些选择的 MEDIUM 和 LOW 属性,以及所有没有默认值的属性.

    只有 Kafka 支持的属性的子集可以直接通过 KafkaProperties 类获得. 如果您希望使用不受支持的其他属性配置生产者或消费者,请使用以下属性:

    spring.kafka.properties.prop.one=first
    spring.kafka.admin.properties.prop.two=second
    spring.kafka.consumer.properties.prop.three=third
    spring.kafka.producer.properties.prop.four=fourth
    spring.kafka.streams.properties.prop.five=fifth

    这将常见的 prop.one Kafka 属性设置为 first (适用于生产者、消费者和管理者) ,prop.two 管理者属性为 second,prop.three 消费者属性为 third,prop.four 生产者属性为 fourth,prop.five 流属性为 fifth.

    您还可以按如下方式配置 Spring Kafka JsonDeserializer:

    spring.kafka.consumer.value-deserializer=org.springframework.kafka.support.serializer.JsonDeserializer
    spring.kafka.consumer.properties.spring.json.value.default.type=com.example.Invoice
    spring.kafka.consumer.properties.spring.json.trusted.packages=com.example,org.acme

    同样,您可以禁用 JsonSerializer 在 header 中发送类型信息的默认行为:

    spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer
    spring.kafka.producer.properties.spring.json.add.type.headers=false

    13.3.5. 使用嵌入式 Kafka 进行测试

    Spring 为 Apache Kafka 提供了一种使用嵌入式Apache Kafka代理测试项目的便捷方法. 要使用此功能,请在 spring-kafka-test 模块中使用 @EmbeddedKafka 注解测试类. 有关更多信息,请参阅Spring for Apache Kafka 参考手册.

    要使Spring Boot自动配置与上述嵌入式Apache Kafka代理一起使用,您需要将嵌入式代理地址 (由 EmbeddedKafkaBroker 填充) 的系统属性重新映射到Apache Kafka的Spring Boot配置属性中. 有几种方法可以做到这一点:

    static {
        System.setProperty(EmbeddedKafkaBroker.BROKER_LIST_PROPERTY, "spring.kafka.bootstrap-servers");
    

    如果您的应用程序需要调用远程 REST 服务,这可以使用 Spring Framework 的 RestTemplate 类. 由于 RestTemplate 实例在使用之前通常需要进行自定义,因此 Spring Boot 不提供任何自动配置的 RestTemplate bean. 但是, 它会自动配置 RestTemplateBuilder,可在需要时创建 RestTemplate 实例. 自动配置的 RestTemplateBuilder 确保将合适的 HttpMessageConverters 应用于 RestTemplate 实例.

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

    @Service
    public class MyService {
        private final RestTemplate restTemplate;
        public MyService(RestTemplateBuilder restTemplateBuilder) {
            this.restTemplate = restTemplateBuilder.build();
        public Details someRestCall(String name) {
            return this.restTemplate.getForObject("/{name}/details", Details.class, name);
    

    要想自定义的作用域尽可能地窄,请注入自动配置的 RestTemplateBuilder,然后根据需要调用其方法. 每个方法调用都返回一个新的 RestTemplateBuilder 实例,因此自定义只会影响当前构建器.

    要在应用程序作用域内添加自定义配置,请使用 RestTemplateCustomizer bean. 所有这些 bean 都会自动注册到自动配置的 RestTemplateBuilder,并应用于使用它构建的所有模板.

    以下示例展示了一个 customizer,它为除 192.168.0.5 之外的所有主机配置代理:

    static class ProxyCustomizer implements RestTemplateCustomizer {
        @Override
        public void customize(RestTemplate restTemplate) {
            HttpHost proxy = new HttpHost("proxy.example.com");
            HttpClient httpClient = HttpClientBuilder.create().setRoutePlanner(new DefaultProxyRoutePlanner(proxy) {
                @Override
                public HttpHost determineProxy(HttpHost target, HttpRequest request, HttpContext context)
                        throws HttpException {
                    if (target.getHostName().equals("192.168.0.5")) {
                        return null;
                    return super.determineProxy(target, request, context);
            }).build();
            restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
    

    最后,最极端 (也很少使用) 的选择是创建自己的 RestTemplateBuilder bean. 这样做会关闭 RestTemplateBuilder 的自动配置,并阻止使用任何 RestTemplateCustomizer bean.

    如果在 classpath 上存在 Spring WebFlux,则还可以选择使用 WebClient 来调用远程 REST 服务. 与 RestTemplate 相比,该客户端更具函数式风格并且完全响应式. 您可以在 Spring Framework 文档的相关部分中了解有关 WebClient 的更多信息.

    Spring Boot 为您创建并预配置了一个 WebClient.Builder. 强烈建议将其注入您的组件中并使用它来创建 WebClient 实例. Spring Boot 配置该构建器以共享 HTTP 资源,以与服务器相同的方式反射编解码器设置 (请参阅 WebFlux HTTP 编解码器自动配置) 等.

    以下代码是一个典型示例:

    @Service
    public class MyService {
        private final WebClient webClient;
        public MyService(WebClient.Builder webClientBuilder) {
            this.webClient = webClientBuilder.baseUrl("https://example.org").build();
        public Mono<Details> someRestCall(String name) {
            return this.webClient.get().uri("/{name}/details", name)
                            .retrieve().bodyToMono(Details.class);
    

    15.1. WebClient 运行时

    Spring Boot 将自动检测用于驱动 WebClientClientHttpConnector,具体取决于应用程序 classpath 上可用的类库. 目前支持 Reactor Netty 和 Jetty RS 客户端.

    默认情况下 spring-boot-starter-webflux starter 依赖于 io.projectreactor.netty:reactor-netty,它包含了服务器和客户端的实现. 如果您选择将 Jetty 用作响应式服务器,则应添加 Jetty Reactive HTTP 客户端库依赖 org.eclipse.jetty:jetty-reactive-httpclient. 服务器和客户端使用相同的技术具有一定优势,因为它会自动在客户端和服务器之间共享 HTTP 资源.

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

    如果您只希望覆盖客户端选项,则可以定义自己的 ClientHttpConnector bean 并完全控制客户端配置.

    您可以在 Spring Framework 参考文档中了解有关 WebClient 配置选项的更多信息.

    15.2. 自定义 WebClient

    WebClient 自定义有三种主要方法,具体取决于您希望自定义的程度.

    要想自定义的作用域尽可能地窄,请注入自动配置的 WebClient.Builder,然后根据需要调用其方法. WebClient.Builder 实例是有状态的: 构建器上的任何更改都会影响到之后所有使用它创建的客户端. 如果要使用相同的构建器创建多个客户端,可以考虑使用 WebClient.Builder other = builder.clone(); 的方式克隆构建器.

    要在应用程序作用域内对所有 WebClient.Builder 实例添加自定义,可以声明 WebClientCustomizer bean 并在注入点局部更改 WebClient.Builder.

    最后,您可以回退到原始 API 并使用 WebClient.create(). 在这种情况下,不会应用自动配置或 WebClientCustomizer.

    只要 classpath 上存在 JSR-303 实现 (例如 Hibernate 验证器) ,就会自动启用 Bean Validation 1.1 支持的方法验证功能. 这允许 bean 方法在其参数和/或返回值上使用 javax.validation 约束进行注解. 带有此类注解方法的目标类需要在类级别上使用 @Validated 进行注解,以便搜索其内联约束注解的方法.

    例如,以下服务触发第一个参数的验证,确保其大小在 8 到 10 之间:

    @Service
    @Validated
    public class MyBean {
        public Archive findByCodeAndAuthor(@Size(min = 8, max = 10) String code,
                Author author) {
    

    如果 spring.mail.host 和相关库 (由 spring-boot-starter-mail 定义) 可用,则创建默认的 JavaMailSender (如果不存在) . 可以通过 spring.mail 命名空间中的配置项进一步自定义发件人. 有关更多详细信息,请参阅 MailProperties.

    特别是,某些默认超时时间的值是无限的,您可能想更改它以避免线程被无响应的邮件服务器阻塞,如下示例所示:

    spring.mail.properties.mail.smtp.connectiontimeout=5000
    spring.mail.properties.mail.smtp.timeout=3000
    spring.mail.properties.mail.smtp.writetimeout=5000

    也可以使用 JNDI 中的现有 Session 配置一个 JavaMailSender:

    spring.mail.jndi-name=mail/Session

    设置 jndi-name 时,它优先于所有其他与 Session 相关的设置.

    Spring Boot 通过使用 AtomikosBitronix 嵌入式事务管理器来支持跨多个 XA 资源的分布式 JTA 事务. 部署在某些 Java EE 应用服务器 (Application Server) 上也支持 JTA 事务.

    当检测到 JTA 环境时,Spring 的 JtaTransactionManager 将用于管理事务. 自动配置的 JMS、DataSource 和 JPA bean 已升级为支持 XA 事务. 您可以使用标准的 Spring 方式 (例如 @Transactional) 来使用分布式事务. 如果您处于 JTA 环境中并且仍想使用本地事务,则可以将 spring.jta.enabled 属性设置为 false 以禁用 JTA 自动配置.

    18.1. 使用 Atomikos 事务管理器

    Atomikos 是一个流行的开源事务管理器,可以嵌入到 Spring Boot 应用程序中. 您可以使用 spring-boot-starter-jta-atomikos starter 来获取相应的 Atomikos 库. Spring Boot 自动配置 Atomikos 并确保将合适的依赖设置应用于 Spring bean,以确保启动和关闭顺序正确.

    默认情况下,Atomikos 事务日志将写入应用程序主目录 (应用程序 jar 文件所在的目录) 中的 transaction-logs 目录. 您可以通过在 application.properties 文件中设置 spring.jta.log-dir 属性来自定义此目录的位置. 也可用 spring.jta.atomikos.properties 开头的属性来自定义 Atomikos UserTransactionServiceImp. 有关完整的详细信息,请参阅 AtomikosProperties Javadoc.

    18.2. 使用 Bitronix 事务管理器

    Bitronix 是一个流行的开源 JTA 事务管理器实现. 您可以使用 spring-boot-starter-jta-bitronix starter 为您的项目添加合适的 Bitronix 依赖. 与 Atomikos 一样,Spring Boot 会自动配置 Bitronix 并对 bean 进行后处理 (post-processes) ,以确保启动和关闭顺序正确.

    默认情况下,Bitronix 事务日志文件 (part1.btmpart2.btm) 将写入应用程序主目录中的 transaction-logs 目录. 您可以通过设置 spring.jta.log-dir 属性来自定义此目录的位置. 以 spring.jta.bitronix.properties 开头的属性绑定到了 bitronix.tm.Configuration bean,允许完全自定义. 有关详细信息,请参阅 Bitronix 文档.

    18.3. 使用 Java EE 管理的事务管理器

    如果将 Spring Boot 应用程序打包为 warear 文件并将其部署到 Java EE 应用程序服务器,则可以使用应用程序服务器的内置事务管理器. Spring Boot 尝试通过查找常见的 JNDI 位置 (java:comp/UserTransactionjava:comp/TransactionManager 等) 来自动配置事务管理器. 如果使用应用程序服务器提供的事务服务, 通常还需要确保所有资源都由服务器管理并通过 JNDI 暴露. Spring Boot 尝试通过在 JNDI 路径 (java:/JmsXAjava:/JmsXA) 中查找 ConnectionFactory 来自动配置 JMS,并且可以使用 spring.datasource.jndi-name 属性 属性来配置 DataSource.

    18.4. 混合使用 XA 与非 XA JMS 连接

    使用 JTA 时,主 JMS ConnectionFactory bean 可识别 XA 并参与分布式事务. 在某些情况下,您可能希望使用非 XA ConnectionFactory 处理某些 JMS 消息. 例如,您的 JMS 处理逻辑可能需要比 XA 超时时间更长的时间.

    如果要使用非 XA ConnectionFactory,可以注入 nonXaJmsConnectionFactory bean 而不是 @Primary jmsConnectionFactory bean. 为了保持一致性,提供的 jmsConnectionFactory bean 还需要使用 xaJmsConnectionFactory 别名.

    以下示例展示了如何注入 ConnectionFactory 实例:

    // Inject the primary (XA aware) ConnectionFactory
    @Autowired
    private ConnectionFactory defaultConnectionFactory;
    // Inject the XA aware ConnectionFactory (uses the alias and injects the same as above)
    @Autowired
    @Qualifier("xaJmsConnectionFactory")
    private ConnectionFactory xaConnectionFactory;
    // Inject the non-XA aware ConnectionFactory
    @Autowired
    @Qualifier("nonXaJmsConnectionFactory")
    private ConnectionFactory nonXaConnectionFactory;

    18.5. 支持嵌入式事务管理器

    XAConnectionFactoryWrapperXADataSourceWrapper 接口可用于支持其他嵌入式事务管理器. 接口负责包装 XAConnectionFactoryXADataSource bean,并将它们暴露为普通的 ConnectionFactoryDataSource bean,它们透明地加入分布式事务. DataSource 和 JMS 自动配置使用 JTA 变体,前提是您需要有一个 JtaTransactionManager bean 和在 ApplicationContext 中注册有的相应 XA 包装器 (wrapper) bean.

    BitronixXAConnectionFactoryWrapperBitronixXADataSourceWrapper 为如何编写 XA 包装器提供了很好示例.

    如果定义了 com.hazelcast.config.Config bean,则 Spring Boot 会使用它. 如果您的配置定义了实例名称,Spring Boot 会尝试查找现有的实例,而不是创建新实例.

    您还可以指定通过配置使用的 Hazelcast 配置文件,如以下示例所示:

    spring.hazelcast.config=classpath:config/my-hazelcast.xml

    否则,Spring Boot 会尝试从默认位置查找 Hazelcast 配置: 工作目录或 classpath 根目录中的 hazelcast.xml,或相同位置中的 .yaml 文件. 我们还检查是否设置了 hazelcast.config 系统属性. 有关更多详细信息,请参见 Hazelcast documentation. 如果 classpath 中存在 hazelcast-client,则 Spring Boot 会首先尝试通过检查以下配置项来创建客户端:

    Spring Boot 提供了几种使用 Quartz 调度器的便捷方式,它们来自 spring-boot-starter-quartz starter. 如果 Quartz 可用,则 Spring Boot 将自动配置 Scheduler (通过 SchedulerFactoryBean 抽象) .

    自动选取以下类型的 Bean 并将其与 Scheduler 关联起来:

    要让 Quartz 使用除应用程序主 DataSource 之外的 DataSource,请声明一个 DataSource bean,使用 @QuartzDataSource 注解其 @Bean 方法. 这样做可确保 SchedulerFactoryBean 和 schema 初始化都使用 Quartz 指定的 DataSource.

    默认情况下,配置创建的 job 不会覆盖已从持久 job 存储读取的已注册的 job. 要启用覆盖现有的 job 定义,请设置 spring.quartz.overwrite-existing-jobs 属性.

    Quartz 调取器配置可以使用 spring.quartz 属性和 SchedulerFactoryBeanCustomizer bean 进行自定义,它们允许以编程方式的 SchedulerFactoryBean 自定义. 可以使用 spring.quartz.properties.* 自定义高级 Quartz 配置属性.

    public void setMyService(MyService myService) { ... } // Inject the "name" job data property public void setName(String name) { ... } @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException {

    如果您在上下文中定义了自定义 Executor,则常规任务执行 (即 @EnableAsync) 将透明地使用它,但不会配置 Spring MVC 支持,因为它需要 AsyncTaskExecutor 实现 (名为 applicationTaskExecutor) . 根据您的目标安排,您可以将 Executor 更改为 ThreadPoolTaskExecutor,或者定义 ExecutorThreadPoolTaskExecutorAsyncConfigurer 来包装自定义的 Executor.

    您可以使用自动配置的 TaskExecutorBuilder 来轻松创建实例,以复制默认的自动配置.

    这会将线程池更改为使用有界队列,在队列满 (100 个任务) 时,线程池将增加到最多 16 个线程. 当线程在闲置10 秒 (而不是默认的 60 秒) 时回收线程,池的收缩更为明显.

    如果需要与调度任务执行 (@EnableScheduling) 相关联,可以自动配置一个 ThreadPoolTaskScheduler. 默认情况下,线程池使用一个线程,可以使用 spring.task.scheduling 命名空间对这些设置进行微调.

    如果需要创建自定义 Actuator 或调度器,则在上下文中可以使用 TaskExecutorBuilder bean 和 TaskSchedulerBuilder bean.

    Spring Boot 为 Spring Integration 提供了一些便捷的使用方式,它们包含在 spring-boot-starter-integration starter 中. Spring Integration 为消息传递以及其他传输 (如 HTTP、TCP 等) 提供了抽象. 如果 classpath 上存在 Spring Integration,则 Spring Boot 会通过 @EnableIntegration 注解对其进行初始化.

    Spring Boot 还配置了一些由其他 Spring Integration 模块触发的功能. 如果 spring-integration-jmx 也在 classpath 上,则消息处理统计信息将通过 JMX 发布. 如果 spring-integration-jdbc 可用,则可以在启动时创建默认数据库模式,如下所示:

    spring.integration.jdbc.initialize-schema=always

    有关更多详细信息,请参阅 IntegrationAutoConfigurationIntegrationProperties 类.

    默认情况下,如果存在 Micrometer meterRegistry bean,则 Micrometer 将管理 Spring Integration 的指标. 如果您希望使用旧版 Spring Integration 指标,请将 DefaultMetricsFactory bean 添加到应用程序上下文中.

    Java Management Extensions (JMX,Java 管理扩展) 提供了一种监视和管理应用程序的标准机制. 默认情况下,Spring Boot 会创建一个 ID 为 mbeanServerMBeanServer bean,并暴露使用 Spring JMX 注解 (@ManagedResource@ManagedAttribute@ManagedOperation) 的 bean.

    有关更多详细信息,请参阅 JmxAutoConfiguration 类.

    Spring Boot提供了许多工具类和注解,可以在测试应用程序时提供帮助. 主要由两个模块提供: spring-boot-test 包含核心项,spring-boot-test-autoconfigure 支持测试的自动配置.

    大多数开发人员都使用 spring-boot-starter-test “Starter”,它会导入Spring Boot 测试模块以及 JUnit Jupiter,AssertJ,Hamcrest和许多其他有用的库.

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    25.2. 测试 Spring 应用程序

    依赖注入的主要优点之一是,它应该使您的代码更易于进行单元测试. 您可以使用 new 运算符实例化对象,甚至无需使用 Spring. 您还可以使用模拟对象而不是实际的依赖.

    通常,您需要超越单元测试并开始集成测试 (使用Spring ApplicationContext) . 能够进行集成测试而无需部署应用程序或连接到其他基础结构是很有用的.

    Spring框架包括用于此类集成测试的专用测试模块. 您可以直接向 org.springframework: spring-test 声明依赖,也可以使用 spring-boot-starter-test “Starter” 将其传递.

    如果您以前没有使用过 spring-test 模块,则应先阅读 Spring Framework参考文档的相关部分 .

    25.3. 测试 Spring Boot 应用程序

    Spring Boot应用程序是Spring ApplicationContext,因此除了对普通Spring上下文进行常规测试以外,无需执行任何其他特殊操作即可对其进行测试.

    Spring Boot提供了 @SpringBootTest 注解,当您需要Spring Boot功能时,可以将其用作标准 spring-test @ContextConfiguration 注解的替代方法. 注解通过创建 SpringApplication 在测试中使用的 ApplicationContext 来起作用. 除了 @SpringBootTest 之外,还提供了许多其他注解来测试应用程序的特定的部分.

    MOCK(默认) : 加载Web ApplicationContext 并提供模拟Web环境. 使用此注解时,不会启动嵌入式服务器. 如果您的类路径上没有Web环境,则此模式将透明地退回到创建常规的非Web ApplicationContext. 它可以与 @AutoConfigureMockMvc@AutoConfigureWebTestClient 结合使用,以对Web应用程序进行基于模拟的测试.

    RANDOM_PORT: 加载 WebServerApplicationContext 并提供真实的Web环境. 在随机的端口启动并监听嵌入式服务器.

    DEFINED_PORT: 加载 WebServerApplicationContext 并提供真实的Web环境. 在定义的端口(来自 application.properties) 或 8080 端口启动并监听嵌入式服务器

    NONE: 使用 SpringApplication 加载 ApplicationContext,但不提供任何Web环境 (模拟或其他方式) .

    25.3.1. 检测 Web 应用程序类型

    如果Spring MVC可用,则配置基于常规MVC的应用程序上下文. 如果您只有Spring WebFlux,我们将检测到该情况并配置基于WebFlux的应用程序上下文.

    如果两者都存在,则Spring MVC优先. 如果要在这种情况下测试反应式Web应用程序,则必须设置 spring.main.web-application-type 属性:

    @SpringBootTest(properties = "spring.main.web-application-type=reactive")
    class MyWebFluxTests { ... }

    25.3.2. 检测测试配置

    如果您熟悉Spring Test Framework,则可能习惯于使用 @ContextConfiguration(classes=…​) 以指定要加载哪个Spring @Configuration. 另外,您可能经常在测试中使用嵌套的 @Configuration 类.

    在测试Spring Boot应用程序时,通常不需要这样做. 只要您没有明确定义,Spring Boot的 @*Test 注解就会自动搜索您的主要配置.

    搜索算法从包含测试的程序包开始工作,直到找到带有 @SpringBootApplication@SpringBootConfiguration 注解的类. 只要您以合理的方式对代码进行结构化 ,通常就可以找到您的主要配置.

    25.3.3. 排除测试配置

    如果您的应用程序使用组件扫描 (例如,如果使用 @SpringBootApplication@ComponentScan ) ,则可能会发现偶然为各地创建的仅为特定测试创建的顶级配置类.

    如前所述,@TestConfiguration 可以用于测试的内部类以自定义主要配置. 当放置在顶级类上时, @TestConfiguration 指示不应通过扫描选择 src/test/java 中的类. 然后,可以在需要的位置显式导入该类,如以下示例所示:

    @SpringBootTest
    @Import(MyTestsConfiguration.class)
    class MyTests {
        @Test
        void exampleTest() {
        @Test
        void applicationArgumentsPopulated(@Autowired ApplicationArguments args) {
            assertThat(args.getOptionNames()).containsOnly("app.test");
            assertThat(args.getOptionValues("app.test")).containsOnly("one");
    
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.web.servlet.MockMvc;
    import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
    @SpringBootTest
    @AutoConfigureMockMvc
    class MockMvcExampleTests {
        @Test
        void exampleTest(@Autowired MockMvc mvc) throws Exception {
            mvc.perform(get("/")).andExpect(status().isOk()).andExpect(content().string("Hello World"));
    
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.web.reactive.server.WebTestClient;
    @SpringBootTest
    @AutoConfigureWebTestClient
    class MockWebTestClientExampleTests {
        @Test
        void exampleTest(@Autowired WebTestClient webClient) {
            webClient.get().uri("/").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo("Hello World");
    

    在模拟环境中进行测试通常比在完整的Servlet容器中运行更快. 但是,由于模拟发生在Spring MVC层,因此无法使用MockMvc直接测试依赖于较低级别Servlet容器行为的代码.

    例如,Spring Boot的错误处理基于Servlet容器提供的 “error page” 支持. 这意味着,尽管您可以按预期测试MVC层引发并处理异常,但是您无法直接测试是否呈现了特定的自定义错误页面. 如果需要测试这些较低级别的问题,则可以按照下一节中的描述启动一个完全运行的服务器.

    25.3.6. 使用正在运行的服务器进行测试

    如果需要启动完全运行的服务器,建议您使用随机端口. 如果使用 @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT),则每次运行测试时都会随机选择一个可用端口.

    @LocalServerPort 注解可用于将 将实际使用的端口注入 测试中. 为了方便起见,需要对已启动的服务器进行REST调用的测试可以 @Autowire 附加地使用 WebTestClient, 该 WebTestClient 解析到正在运行的服务器的相对链接,并带有用于验证响应的专用API,如以下示例所示:

    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
    import org.springframework.test.web.reactive.server.WebTestClient;
    @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
    class RandomPortWebTestClientExampleTests {
        @Test
        void exampleTest(@Autowired WebTestClient webClient) {
            webClient.get().uri("/").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo("Hello World");
    

    这种设置需要在类路径上使用 spring-webflux. 如果您无法或不会添加webflux,则Spring Boot还提供了 TestRestTemplate 工具: If you can’t or won’t add webflux, Spring Boot also provides a TestRestTemplate facility:

    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
    import org.springframework.boot.test.web.client.TestRestTemplate;
    import static org.assertj.core.api.Assertions.assertThat;
    @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
    class RandomPortTestRestTemplateExampleTests {
        @Test
        void exampleTest(@Autowired TestRestTemplate restTemplate) {
            String body = restTemplate.getForObject("/", String.class);
            assertThat(body).isEqualTo("Hello World");
    
    @ExtendWith(SpringExtension.class)
    @SpringBootTest(properties = "spring.jmx.enabled=true")
    @DirtiesContext
    class SampleJmxTests {
        @Autowired
        private MBeanServer mBeanServer;
        @Test
        void exampleTest() {
            // ...
    

    25.3.9. 模拟和检测 Bean

    运行测试时,有时有必要在应用程序上下文中模拟某些组件. 例如,您可能在开发过程中无法使用某些远程服务的外观. 当您要模拟在实际环境中可能难以触发的故障时,模拟也很有用.

    Spring Boot包含一个 @MockBean 注解,可用于为 ApplicationContext 中的bean定义 Mockito 模拟. 您可以使用注解添加新bean或替换单个现有bean定义. 注解可以直接用于测试类,测试中的字段或 @Configuration 类和字段. 在字段上使用时,还将注入创建的模拟的实例. 每种测试方法后,模拟 Bean 都会自动重置.

    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.*;
    import org.springframework.boot.test.context.*;
    import org.springframework.boot.test.mock.mockito.*;
    import static org.assertj.core.api.Assertions.*;
    import static org.mockito.BDDMockito.*;
    @SpringBootTest
    class MyTests {
        @MockBean
        private RemoteService remoteService;
        @Autowired
        private Reverser reverser;
        @Test
        void exampleTest() {
            // RemoteService has been injected into the reverser bean
            given(this.remoteService.someCall()).willReturn("mock");
            String reverse = reverser.reverseSomeCall();
            assertThat(reverse).isEqualTo("kcom");
    

    25.3.10. 自动配置测试

    Spring Boot的自动配置系统适用于应用程序,但有时对测试来说可能有点过多. 它通常仅有助于加载测试应用程序 "切片" 所需的配置部分. 例如,您可能想要测试Spring MVC控制器是否正确映射了URL,并且您不想在这些测试中涉及数据库调用,或者您想要测试JPA实体,并且对那些JPA实体不感兴趣. 测试运行.

    spring-boot-test-autoconfigure 模块包括许多注解,可用于自动配置此类 "切片". 它们中的每一个都以相似的方式工作,提供了一个 @…​Test 注解 (该注解加载了 ApplicationContext) 以及一个或多个 @AutoConfigure…​ (可用于自定义自动配置设置的注解) .

    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.*;
    import org.springframework.boot.test.autoconfigure.json.*;
    import org.springframework.boot.test.context.*;
    import org.springframework.boot.test.json.*;
    import static org.assertj.core.api.Assertions.*;
    @JsonTest
    class MyJsonTests {
        @Autowired
        private JacksonTester<VehicleDetails> json;
        @Test
        void testSerialize() throws Exception {
            VehicleDetails details = new VehicleDetails("Honda", "Civic");
            // Assert against a `.json` file in the same package as the test
            assertThat(this.json.write(details)).isEqualToJson("expected.json");
            // Or use JSON path based assertions
            assertThat(this.json.write(details)).hasJsonPathStringValue("@.make");
            assertThat(this.json.write(details)).extractingJsonPathStringValue("@.make")
                    .isEqualTo("Honda");
        @Test
        void testDeserialize() throws Exception {
            String content = "{\"make\":\"Ford\",\"model\":\"Focus\"}";
            assertThat(this.json.parse(content))
                    .isEqualTo(new VehicleDetails("Ford", "Focus"));
            assertThat(this.json.parseObject(content).getMake()).isEqualTo("Ford");
    
    import org.junit.jupiter.api.*;
    import org.springframework.beans.factory.annotation.*;
    import org.springframework.boot.test.autoconfigure.web.servlet.*;
    import org.springframework.boot.test.mock.mockito.*;
    import static org.assertj.core.api.Assertions.*;
    import static org.mockito.BDDMockito.*;
    import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
    @WebMvcTest(UserVehicleController.class)
    class MyControllerTests {
        @Autowired
        private MockMvc mvc;
        @MockBean
        private UserVehicleService userVehicleService;
        @Test
        void testExample() throws Exception {
            given(this.userVehicleService.getVehicleDetails("sboot"))
                    .willReturn(new VehicleDetails("Honda", "Civic"));
            this.mvc.perform(get("/sboot/vehicle").accept(MediaType.TEXT_PLAIN))
                    .andExpect(status().isOk()).andExpect(content().string("Honda Civic"));
    
    import com.gargoylesoftware.htmlunit.*;
    import org.junit.jupiter.api.*;
    import org.springframework.beans.factory.annotation.*;
    import org.springframework.boot.test.autoconfigure.web.servlet.*;
    import org.springframework.boot.test.mock.mockito.*;
    import static org.assertj.core.api.Assertions.*;
    import static org.mockito.BDDMockito.*;
    @WebMvcTest(UserVehicleController.class)
    class MyHtmlUnitTests {
        @Autowired
        private WebClient webClient;
        @MockBean
        private UserVehicleService userVehicleService;
        @Test
        void testExample() throws Exception {
            given(this.userVehicleService.getVehicleDetails("sboot"))
                    .willReturn(new VehicleDetails("Honda", "Civic"));
            HtmlPage page = this.webClient.getPage("/sboot/vehicle.html");
            assertThat(page.getBody().getTextContent()).isEqualTo("Honda Civic");
    

    25.3.13. 自动配置的 Spring WebFlux 测试

    要测试 Spring WebFlux 控制器是否按预期工作,可以使用 @WebFluxTest 注解. @WebFluxTest 自动配置Spring WebFlux基础结构, 并将扫描的bean限制为 @Controller, @ControllerAdvice, @JsonComponent, Converter, GenericConverter, WebFilterWebFluxConfigurer. 使用 @WebFluxTest 注解时,不扫描常规 @Component bean.

    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
    import org.springframework.http.MediaType;
    import org.springframework.test.web.reactive.server.WebTestClient;
    @WebFluxTest(UserVehicleController.class)
    class MyControllerTests {
        @Autowired
        private WebTestClient webClient;
        @MockBean
        private UserVehicleService userVehicleService;
        @Test
        void testExample() throws Exception {
            given(this.userVehicleService.getVehicleDetails("sboot"))
                    .willReturn(new VehicleDetails("Honda", "Civic"));
            this.webClient.get().uri("/sboot/vehicle").accept(MediaType.TEXT_PLAIN)
                    .exchange()
                    .expectStatus().isOk()
                    .expectBody(String.class).isEqualTo("Honda Civic");
    @WebFluxTest 无法检测通过 SecurityWebFilterChain 类型的 @Bean 注册的自定义安全配置.  要将其包括在测试中,您将需要通过 @Import 导入或使用 @SpringBootTest 导入用于注册bean的配置.
    To include that in your test, you will need to import the configuration that registers the bean via @Import or use @SpringBootTest.
    
    import org.junit.jupiter.api.Test;
    import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
    @DataJpaTest
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    class ExampleNonTransactionalTests {
    

    数据JPA测试也可以注入 TestEntityManager bean,它为专门为测试设计的标准JPA EntityManager 提供了替代方法. 如果要在 @DataJpaTest 实例之外使用 TestEntityManager,也可以使用 @AutoConfigureTestEntityManager 注解. 如果需要,还可以使用 JdbcTemplate. 以下示例显示了正在使用的 @DataJpaTest 注解:

    import org.junit.jupiter.api.Test;
    import org.springframework.boot.test.autoconfigure.orm.jpa.*;
    import static org.assertj.core.api.Assertions.*;
    @DataJpaTest
    class ExampleRepositoryTests {
        @Autowired
        private TestEntityManager entityManager;
        @Autowired
        private UserRepository repository;
        @Test
        void testExample() throws Exception {
            this.entityManager.persist(new User("sboot", "1234"));
            User user = this.repository.findByUsername("sboot");
            assertThat(user.getUsername()).isEqualTo("sboot");
            assertThat(user.getVin()).isEqualTo("1234");
    

    内存嵌入式数据库通常运行良好,不需要任何安装,因此通常可以很好地进行测试. 但是,如果您希望对真实数据库运行测试,则可以使用 @AutoConfigureTestDatabase 注解,如以下示例所示:

    @DataJpaTest
    @AutoConfigureTestDatabase(replace=Replace.NONE)
    class ExampleRepositoryTests {
        // ...
    
    import org.junit.jupiter.api.Test;
    import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
    @JdbcTest
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    class ExampleNonTransactionalTests {
    

    如果您希望测试针对真实数据库运行,则可以使用 @AutoConfigureTestDatabase 注解,其方式与DataJpaTest相同. (请参阅自动配置的 Data JPA 测试. )

    25.3.16. 自动配置的 Data JDBC 测试

    @DataJdbcTest@JdbcTest 相似,但适用于使用Spring Data JDBC存储库的测试. 默认情况下,它配置一个内存嵌入式数据库,一个 JdbcTemplate 和Spring Data JDBC存储库. 常规 @Component bean未加载到 ApplicationContext 中.

    默认情况下,Data JDBC测试是事务性的,并在每个测试结束时回滚. 有关更多详细信息,请参见《 Spring Framework参考文档》中的 相关部分. 如果这不是您想要的,则可以禁用测试或整个测试类的事务管理,如JDBC示例所示.

    如果您希望测试针对真实数据库运行,则可以使用 @AutoConfigureTestDatabase 注解,其方式与 DataJpaTest 相同. (请参阅自动配置的 Data JPA测试. )

    25.3.17. 自动配置的 jOOQ Tests

    您可以以与 @JdbcTest 类似的方式使用 @JooqTest,但可以用于与jOOQ相关的测试. 由于jOOQ严重依赖与数据库模式相对应的基于Java的模式,因此将使用现有的 DataSource. 如果要将其替换为内存数据库,则可以使用 @AutoConfigureTestDatabase 覆盖这些设置. (有关在Spring Boot中使用jOOQ的更多信息,请参阅本章前面的 "使用 jOOQ". ) 常规 @Component Bean未加载到 ApplicationContext 中.

    import org.jooq.DSLContext;
    import org.junit.jupiter.api.Test;
    import org.springframework.boot.test.autoconfigure.jooq.JooqTest;
    @JooqTest
    class ExampleJooqTests {
        @Autowired
        private DSLContext dslContext;
    

    JOOQ测试是事务性的,默认情况下会在每个测试结束时回滚. 如果这不是您想要的,则可以禁用测试或整个测试类的事务管理,如JDBC示例所示.

    25.3.18. 自动配置的 Data MongoDB 测试

    您可以使用 @DataMongoTest 测试MongoDB应用程序. 默认情况下,它配置内存嵌入式MongoDB (如果可用) ,配置 MongoTemplate,扫描 @Document 类,并配置Spring Data MongoDB存储库. 常规 @Component bean未加载到 ApplicationContext 中. (有关将MongoDB与Spring Boot结合使用的更多信息,请参阅本章前面的 "MongoDB")

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
    import org.springframework.data.mongodb.core.MongoTemplate;
    @DataMongoTest
    class ExampleDataMongoTests {
        @Autowired
        private MongoTemplate mongoTemplate;
    

    内存嵌入式MongoDB通常运行良好,并且不需要任何开发人员安装,因此通常可以很好地用于测试. 但是,如果您希望对真实的MongoDB服务器运行测试,则应排除嵌入式MongoDB自动配置,如以下示例所示:

    import org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration;
    import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
    @DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class)
    class ExampleDataMongoNonEmbeddedTests {
    

    25.3.19. 自动配置的 Data Neo4j 测试

    您可以使用 @DataNeo4jTest 来测试Neo4j应用程序. 默认情况下,它使用内存中嵌入式Neo4j (如果有嵌入式驱动程序可用) ,扫描 @NodeEntity 类,并配置Spring Data Neo4j存储库. 常规 @Component bean未加载到 ApplicationContext 中. (有关将Neo4J与Spring Boot结合使用的更多信息,请参阅本章前面的 "Neo4j". )

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest;
    @DataNeo4jTest
    class ExampleDataNeo4jTests {
        @Autowired
        private YourRepository repository;
    

    默认情况下,Data Neo4j测试是事务性的,并在每次测试结束时回滚. 有关更多详细信息,请参见《 Spring Framework参考文档》中的http://docs.jcohy.com/zh-cn/spring-framework/5.2.4.RELEASE/spring-framework-reference/index.htmltesting.html#testcontext-tx-enabling-transactions[相关部分] . 如果这不是您想要的,则可以为测试或整个类禁用事务管理,如下所示:

    import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
    @DataNeo4jTest
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    class ExampleNonTransactionalTests {
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest;
    @DataRedisTest
    class ExampleDataRedisTests {
        @Autowired
        private YourRepository repository;
    

    25.3.21. 自动配置的 Data LDAP 测试

    您可以使用 @DataLdapTest 来测试LDAP应用程序. 默认情况下,它配置内存嵌入式LDAP (如果可用) ,配置 LdapTemplate,扫描 @Entry 类,并配置Spring Data LDAP存储库. 常规 @Component bean未加载到 ApplicationContext 中. (有关将LDAP与Spring Boot结合使用的更多信息,请参阅本章前面的 "LDAP". )

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest;
    import org.springframework.ldap.core.LdapTemplate;
    @DataLdapTest
    class ExampleDataLdapTests {
        @Autowired
        private LdapTemplate ldapTemplate;
    

    内存嵌入式LDAP通常非常适合测试,因为它速度快并且不需要安装任何开发人员. 但是,如果您希望针对真实的LDAP服务器运行测试,则应排除嵌入式LDAP自动配置,如以下示例所示:

    import org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration;
    import org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest;
    @DataLdapTest(excludeAutoConfiguration = EmbeddedLdapAutoConfiguration.class)
    class ExampleDataLdapNonEmbeddedTests {
        void getVehicleDetailsWhenResultIsSuccessShouldReturnDetails()
                throws Exception {
            this.server.expect(requestTo("/greet/details"))
                    .andRespond(withSuccess("hello", MediaType.TEXT_PLAIN));
            String greeting = this.service.callRestService();
            assertThat(greeting).isEqualTo("hello");
    

    25.3.23. 自动配置的 Spring REST Docs 测试

    您可以使用 @AutoConfigureRestDocs 注解在Mock MVC,REST Assured或 WebTestClient 的测试中使用 Spring REST Docs. 它消除了Spring REST Docs中对JUnit扩展的需求.

    @AutoConfigureRestDocs 可用于覆盖默认输出目录 (如果使用Maven,则为 target/generated-snippets 如果使用Gradle,则为 build/generated-snippets ) . 它也可以用于配置出现在任何记录的URI中的主机,方案和端口.

    使用 Mock MVC 自动配置的Spring REST Docs测试

    @AutoConfigureRestDocs 自定义 MockMvc bean以使用Spring REST Docs. 您可以使用 @Autowired 注入它,并像通常使用Mock MVC和Spring REST Docs一样,在测试中使用它,如以下示例所示:

    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
    import org.springframework.http.MediaType;
    import org.springframework.test.web.servlet.MockMvc;
    import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
    import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
    @WebMvcTest(UserController.class)
    @AutoConfigureRestDocs
    class UserDocumentationTests {
        @Autowired
        private MockMvc mvc;
        @Test
        void listUsers() throws Exception {
            this.mvc.perform(get("/users").accept(MediaType.TEXT_PLAIN))
                    .andExpect(status().isOk())
                    .andDo(document("list-users"));
    

    如果需要对Spring REST Docs配置进行更多控制,而不是 @AutoConfigureRestDocs 属性提供的控制,则可以使用 RestDocsMockMvcConfigurationCustomizer bean,如以下示例所示:

    @TestConfiguration
    static class CustomizationConfiguration
            implements RestDocsMockMvcConfigurationCustomizer {
        @Override
        public void customize(MockMvcRestDocumentationConfigurer configurer) {
            configurer.snippets().withTemplateFormat(TemplateFormats.markdown());
    

    如果要使用Spring REST Docs对参数化输出目录的支持,可以创建 RestDocumentationResultHandler bean. 自动配置使用此结果处理程序调用 alwaysDo,从而使每个 MockMvc 调用自动生成默认片段. 以下示例显示了定义的 RestDocumentationResultHandler:

    @TestConfiguration(proxyBeanMethods = false)
    static class ResultHandlerConfiguration {
        @Bean
        public RestDocumentationResultHandler restDocumentation() {
            return MockMvcRestDocumentation.document("{method-name}");
    
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
    import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
    import org.springframework.test.web.reactive.server.WebTestClient;
    import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;
    @WebFluxTest
    @AutoConfigureRestDocs
    class UsersDocumentationTests {
        @Autowired
        private WebTestClient webTestClient;
        @Test
        void listUsers() {
            this.webTestClient.get().uri("/").exchange().expectStatus().isOk().expectBody()
                    .consumeWith(document("list-users"));
    

    如果需要对Spring REST Docs配置进行更多控制,而不是 @AutoConfigureRestDocs 属性提供的控制,则可以使用 RestDocsWebTestClientConfigurationCustomizer bean,如以下示例所示:

    @TestConfiguration(proxyBeanMethods = false)
    public static class CustomizationConfiguration implements RestDocsWebTestClientConfigurationCustomizer {
        @Override
        public void customize(WebTestClientRestDocumentationConfigurer configurer) {
            configurer.snippets().withEncoding("UTF-8");
    
    import io.restassured.specification.RequestSpecification;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
    import org.springframework.boot.web.server.LocalServerPort;
    import static io.restassured.RestAssured.given;
    import static org.hamcrest.Matchers.is;
    import static org.springframework.restdocs.restassured3.RestAssuredRestDocumentation.document;
    @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
    @AutoConfigureRestDocs
    class UserDocumentationTests {
        @Test
        void listUsers(@Autowired RequestSpecification documentationSpec, @LocalServerPort int port) {
            given(documentationSpec).filter(document("list-users")).when().port(port).get("/").then().assertThat()
                    .statusCode(is(200));
    

    如果您需要对Spring REST Docs配置进行更多控制,而不是 @AutoConfigureRestDocs 属性所提供的控制,则可以使用 RestDocsRestAssuredConfigurationCustomizer bean,如以下示例所示:

    @TestConfiguration(proxyBeanMethods = false)
    public static class CustomizationConfiguration implements RestDocsRestAssuredConfigurationCustomizer {
        @Override
        public void customize(RestAssuredRestDocumentationConfigurer configurer) {
            configurer.snippets().withTemplateFormat(TemplateFormats.markdown());
    
    @JdbcTest
    @ImportAutoConfiguration(IntegrationAutoConfiguration.class)
    class ExampleJdbcTests {
    

    25.3.26. 使用Spock测试Spring Boot应用程序

    如果您希望使用Spock来测试Spring Boot应用程序,则应在应用程序的构建中添加对Spock的 spock-spring 模块的依赖. spock-spring 将Spring的测试框架集成到了Spock中. 建议您使用Spock 1.2或更高版本,以受益于Spock的Spring Framework和Spring Boot集成的许多改进. 有关更多详细信息,请参见 Spock的Spring模块的文档.

    void testName(CapturedOutput output) { System.out.println("Hello World!"); assertThat(output).contains("World"); @Test public void testRequest() throws Exception { HttpHeaders headers = this.template.getForEntity( "https://myhost.example.com/example", String.class).getHeaders(); assertThat(headers.getLocation()).hasHost("other.example.com");

    或者,如果将 @SpringBootTest 注解与 WebEnvironment.RANDOM_PORTWebEnvironment.DEFINED_PORT 一起使用,则可以注入完全配置的 TestRestTemplate 并开始使用它. 如有必要,可以通过 RestTemplateBuilder bean应用其他定制. 未指定主机和端口的所有URL都会自动连接到嵌入式服务器,如以下示例所示:

    @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
    class SampleWebClientTests {
        @Autowired
        private TestRestTemplate template;
        @Test
        void testRequest() {
            HttpHeaders headers = this.template.getForEntity("/example", String.class).getHeaders();
            assertThat(headers.getLocation()).hasHost("other.example.com");
        @TestConfiguration(proxyBeanMethods = false)
        static class Config {
            @Bean
            RestTemplateBuilder restTemplateBuilder() {
                return new RestTemplateBuilder().setConnectTimeout(Duration.ofSeconds(1))
                        .setReadTimeout(Duration.ofSeconds(1));
    

    Spring Boot 为内嵌式 Tomcat、Jetty 和 Undertow 提供了 WebSocket 自动配置. 如果将 war 文件部署到独立容器,则 Spring Boot 假定容器负责配置其 WebSocket 支持.

    Spring Framework 为 MVC Web 应用程序提供了 丰富的 WebSocket 支持 ,可以通过 spring-boot-starter-websocket 模块轻松访问.

    WebSocket 支持也可用于 响应式 Web 应用程序 ,并且引入 WebSocket API 以及 spring-boot-starter-webflux:

    <dependency>
        <groupId>javax.websocket</groupId>
        <artifactId>javax.websocket-api</artifactId>
    </dependency>

    27.1. 使用 WebServiceTemplate 调用 Web Service

    如果您需要从应用程序调用远程 Web 服务,则可以使用 WebServiceTemplate 类. 由于 WebServiceTemplate 实例在使用之前通常需要进行自定义,因此 Spring Boot 不提供任何自动配置的 WebServiceTemplate bean. 但是,它会自动配置 WebServiceTemplateBuilder,可在需要创建 WebServiceTemplate 实例时使用.

    以下代码为一个典型示例:

    @Service
    public class MyService {
        private final WebServiceTemplate webServiceTemplate;
        public MyService(WebServiceTemplateBuilder webServiceTemplateBuilder) {
            this.webServiceTemplate = webServiceTemplateBuilder.build();
        public DetailsResp someWsCall(DetailsReq detailsReq) {
             return (DetailsResp) this.webServiceTemplate.marshalSendAndReceive(detailsReq, new SoapActionCallback(ACTION));
    

    默认情况下,WebServiceTemplateBuilder 使用 classpath 上的可用 HTTP 客户端库检测合适的基于 HTTP 的 WebServiceMessageSender. 您还可以按如下方式自定义读取和连接的超时时间:

    @Bean
    public WebServiceTemplate webServiceTemplate(WebServiceTemplateBuilder builder) {
        return builder.messageSenders(new HttpWebServiceMessageSenderBuilder()
                .setConnectTimeout(5000).setReadTimeout(2000).build()).build();
    

    如果您在公司负责开发公共类库,或者如果您在开发一个开源或商业库,您可能希望开发自己的自动配置. 自动配置类可以捆绑在外部 jar 中,他仍然可以被 Spring Boot 获取.

    自动配置可以与提供自动配置代码的 starter 以及您将使用的类库库相关联. 我们首先介绍构建自己的自动配置需要了解的内容,然后我们将继续介绍创建 自定义 starter 所需的步骤.

    28.1. 理解 自动配置的 Beans

    在内部,自动配置使用了标准的 @Configuration 类来实现. @Conditional 注解用于约束何时应用自动配置. 通常,自动配置类使用 @ConditionalOnClass@ConditionalOnMissingBean 注解. 这可确保仅在找到相关类时以及未声明您自己的 @Configuration 时才应用自动配置.

    您可以浏览 spring-boot-autoconfigure 的源代码,以查看 Spring 提供的 @Configuration 类 (请参阅 META-INF/spring.factories 文件) .

    28.2. 找到候选的自动配置

    Spring Boot 会检查已发布 jar 中是否存在 META-INF/spring.factories 文件. 该文件应列出 EnableAutoConfiguration key 下的配置类,如下所示:

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    com.mycorp.libx.autoconfigure.LibXAutoConfiguration,\
    com.mycorp.libx.autoconfigure.LibXWebAutoConfiguration

    如果需要按特定顺序应用配置,则可以使用 @AutoConfigureAfter@AutoConfigureBefore 注解. 例如,如果您提供特定于 Web 的配置,则可能需要在 WebMvcAutoConfiguration 之后应用您的类.

    如果您想排序某些不应该彼此直接了解的自动配置,您也可以使用 @AutoConfigureOrder. 该注解与常规 @Order 注解有相同的语义,但它为自动配置类提供了专用顺序.

    28.3. 条件注解

    您几乎总希望在自动配置类中包含一个或多个 @Conditional 注解. @ConditionalOnMissingBean 是一个常用的注解,其允许开发人员在对您的默认值不满意用于覆盖自动配置.

    Spring Boot 包含许多 @Conditional 注解,您可以通过注解 @Configuration 类或单独的 @Bean 方法在您自己的代码中复用它们. 这些注解包括:

    28.3.1. 类条件

    @ConditionalOnClass@ConditionalOnMissingClass 注解允许根据特定类的是否存在来包含 @Configuration 类. 由于使用 ASM 解析注解元数据,您可以使用 value 属性来引用真实类,即使该类实际上可能不会出现在正在运行的应用程序的 classpath 中. 如果您希望使用 String 值来指定类名,也可以使用 name 属性.

    此机制不会以相同的方式应用于返回类型是条件的目标的 @Bean 方法: 在方法上的条件应用之前,JVM 将加载类和可能处理的方法引用,如果找不到类,将发生失败.

    要处理这种情况,可以使用单独的 @Configuration 类来隔离条件,如下所示:

    @Configuration(proxyBeanMethods = false)
    // Some conditions
    public class MyAutoConfiguration {
        // Auto-configured beans
        @Configuration(proxyBeanMethods = false)
        @ConditionalOnClass(EmbeddedAcmeService.class)
        static class EmbeddedConfiguration {
            @Bean
            @ConditionalOnMissingBean
            public EmbeddedAcmeService embeddedAcmeService() { ... }
    

    28.3.2. Bean 条件

    @ConditionalOnBean@ConditionalOnMissingBean 注解允许根据特定 bean 是否存在来包含 bean. 您可以使用 value 属性按类型或使用 name 来指定 bean. search 属性允许您限制在搜索 bean 时应考虑的 ApplicationContext 层次结构.

    放置在 @Bean 方法上时,目标类型默认为方法的返回类型,如下所示:

    @Configuration(proxyBeanMethods = false)
    public class MyAutoConfiguration {
        @Bean
        @ConditionalOnMissingBean
        public MyService myService() { ... }
    

    在前面的示例中,如果 ApplicationContext 中不包含 MyService 类型的 bean,则将创建 myService bean.

    28.4. 测试自动配置

    自动配置可能受许多因素的影响: 用户配置 (@Bean 定义和 Environment 自定义) 、条件评估 (存在特定的类库) 等. 具体而言,每个测试都应该创建一个定义良好的 ApplicationContext,它表示这些自定义的组合. ApplicationContextRunner 提供了一个好的实现方法.

    ApplicationContextRunner 通常被定义为测试类的一个字段,用于收集基本的通用配置. 以下示例确保始终调用 UserServiceAutoConfiguration:

    private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
            .withConfiguration(AutoConfigurations.of(UserServiceAutoConfiguration.class));
    @Test
    void defaultServiceBacksOff() {
        this.contextRunner.withUserConfiguration(UserConfiguration.class).run((context) -> {
            assertThat(context).hasSingleBean(UserService.class);
            assertThat(context).getBean("myUserService").isSameAs(context.getBean(UserService.class));
    @Configuration(proxyBeanMethods = false)
    static class UserConfiguration {
        @Bean
        UserService myUserService() {
            return new UserService("mine");
    

    也可以轻松自定义 Environment,如下所示:

    @Test
    void serviceNameCanBeConfigured() {
        this.contextRunner.withPropertyValues("user.name=test123").run((context) -> {
            assertThat(context).hasSingleBean(UserService.class);
            assertThat(context.getBean(UserService.class).getName()).isEqualTo("test123");
    

    runner 还可用于展示 ConditionEvaluationReport. 报告可以在 INFODEBUG 级别下打印. 以下示例展示如何使用 ConditionEvaluationReportLoggingListener 在自动配置测试中打印报表.

    @Test
    public void autoConfigTest {
        ConditionEvaluationReportLoggingListener initializer = new ConditionEvaluationReportLoggingListener(
                LogLevel.INFO);
        ApplicationContextRunner contextRunner = new ApplicationContextRunner()
                .withInitializer(initializer).run((context) -> {
                        // Do something...
    

    28.4.1. 模拟一个 Web 上下文

    如果需要测试一个仅在 Servlet 或响应式 Web 应用程序上下文中运行的自动配置,请分别使用 WebApplicationContextRunnerReactiveWebApplicationContextRunner.

    28.4.2. 覆盖 Classpath

    还可以测试在运行时不存在特定类和/或包时发生的情况. Spring Boot附带了一个可以由跑步者轻松使用的 FilteredClassLoader. 在以下示例中,我们声明如果 UserService 不存在,则会正确禁用自动配置:

    @Test
    void serviceIsIgnoredIfLibraryIsNotPresent() {
        this.contextRunner.withClassLoader(new FilteredClassLoader(UserService.class))
                .run((context) -> assertThat(context).doesNotHaveBean("userService"));
    

    28.5.1. 命名

    您应该确保为您的 starter 提供一个合适的命名空间. 即使您使用其他 Maven groupId,也不要使用 spring-boot 作为模块名称的开头. 我们可能会为您以后自动配置的内容提供官方支持.

    根据经验,您应该在 starter 后命名一个组合模块. 例如,假设您正在为 acme 创建一个 starter,并且您将自动配置模块命名为 acme-spring-boot-autoconfigure,将 starter 命名为 acme-spring-boot-starter. 如果您只有一个组合这两者的模块,请将其命名为 acme-spring-boot-starter.

    28.5.2. 配置 keys

    此外,如果您的 starter 提供配置 key,请为它们使用唯一的命名空间. 尤其是,不要将您的 key 包含在 Spring Boot 使用的命名空间中 (例如 servermanagementspring 等) . 如果您使用了相同的命名空间,我们将来可能会以破坏您的模块的方式来修改这些命名空间. 根据经验,所有 key 都必须拥有自己的命名空间 (例如 acme) .

    确保触发元数据生成,以便为您的 key 提供 IDE 帮助. 您可能想查看生成的元数据 (META-INF/spring-configuration-metadata.json) 以确保您的 key 记录是否正确.

    通过为每个属性添加字段javadoc来确保记录了配置 keys,如以下示例所示:

    @ConfigurationProperties("acme")
    public class AcmeProperties {
         * Whether to check the location of acme resources.
        private boolean checkLocation = true;
         * Timeout for establishing a connection to the acme server.
        private Duration loginTimeout = Duration.ofSeconds(3);
        // getters & setters
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-autoconfigure-processor</artifactId>
        <optional>true</optional>
    </dependency>

    使用 Gradle 4.5 及更早版本时,应在 compileOnly 配置中声明依赖,如下所示:

    dependencies {
        compileOnly "org.springframework.boot:spring-boot-autoconfigure-processor"
    

    With Gradle 4.6 and later, the dependency should be declared in the annotationProcessor configuration, as shown in the following example:

    dependencies {
        annotationProcessor "org.springframework.boot:spring-boot-autoconfigure-processor"
    

    Spring Boot 通过利用其他 Spring 项目 (如 Spring Framework、Spring Data 和 Reactor) 的支持来提供 Kotlin 支持. 有关更多信息,请参阅 Spring Framework Kotlin 支持文档 .

    开始学习 Spring Boot 和 Kotlin 最简单方法是遵循这个 全面教程. 您可以通过 start.spring.io 创建新的 Kotlin 项目. 如果您需要支持,请免费加入 Kotlin Slack 的 #spring 频道或使用 Stack Overflow 上的 springkotlin 标签提问.

    29.1. 要求

    Spring Boot 支持 Kotlin 1.3.x. 要使用 Kotlin,classpath 下必须存在 org.jetbrains.kotlin:kotlin-stdliborg.jetbrains.kotlin:kotlin-reflect. 也可以使用 kotlin-stdlib 的变体 kotlin-stdlib-jdk7kotlin-stdlib-jdk8.

    由于 Kotlin 类默认为 final,因此您可能需要配置 kotlin-spring 插件以自动打开 Spring-annotated 类,以便可以代理它们.

    在 Kotlin 中序列化/反序列化 JSON 数据需要使用 Jackson 的 Kotlin 模块. 在 classpath 中找到它时会自动注册. 如果 Jackson 和 Kotlin 存在但 Jackson Kotlin 模块不存在,则会记录警告消息.

    29.2. Null 安全

    Kotlin 的一个关键特性是 null-safety. 它在编译时处理空值,而不是将问题推迟到运行时并遇到 NullPointerException. 这有助于消除常见的错误来源,而无需支付像 Optional 这样的包装器的成本. Kotlin 还允许使用有可空值的,如 Kotlin null 安全综合指南中所述.

    虽然 Java 不允许在其类型系统中表示 null 安全,但 Spring Framework、Spring Data 和 Reactor 现在通过易于使用的工具的注解提供其 API 的安全性. 默认情况下,Kotlin 中使用的 Java API 类型被识别为放宽空检查的 平台类型. Kotlin 对 JSR 305 注解 的支持与可空注解相结合,为 Kotlin 中 Spring API 相关的代码提供了空安全.

    可以通过使用以下选项添加 -Xjsr305 编译器标志来配置 JSR 305 检查: -Xjsr305={strict|warn|ignore}. 默认行为与 -Xjsr305=warn 相同. 在从 Spring API 推断出的 Kotlin 类型中需要考虑 null 安全的 strict 值,但是应该使用 Spring API 可空声明甚至可以在次要版本之间发展并且将来可能添加更多检查的方案.

    import org.springframework.boot.autoconfigure.SpringBootApplication
    import org.springframework.boot.runApplication
    @SpringBootApplication
    class MyApplication
    fun main(args: Array<String>) {
        runApplication<MyApplication>(*args)
    

    这是 SpringApplication.run(MyApplication::class.java, *args) 的替代方式. 它还允许自定义应用程序,如下所示:

    runApplication<MyApplication>(*args) {
        setBannerMode(OFF)
    

    29.3.2. 扩展

    Kotlin 扩展 提供了使用附加功能扩展现有类的能力. Spring Boot Kotlin API 利用这些扩展为现有 API 添加新的 Kotlin 特定便利.

    提供的 TestRestTemplate 扩展类似于 Spring Framework 为 RestOperations 提供的. 除此之外,扩展使得利用 Kotlin reified 类型参数变为可能.

    使用Maven,可以通过 kotlin.version 属性自定义Kotlin版本,并且为 kotlin-maven-plugin 提供了插件管理. 使用Gradle,Spring Boot插件会自动将 kotlin.version 与Kotlin插件的版本保一致.

    Spring Boot还通过导入Kotlin Coroutines BOM管理Coroutines依赖的版本. 可以通过 kotlin-coroutines.version 属性自定义版本.

    29.5. @ConfigurationProperties

    @ConfigurationProperties 目前仅适用于 lateinit 或可空的 var 属性 (建议使用前者) ,因为尚不支持由构造函数初始化的不可变类. 与 @ConstructorBinding 结合使用时,@ConfigurationProperties 支持具有不变 val 属性的类,如以下示例所示:

    @ConstructorBinding
    @ConfigurationProperties("example.kotlin")
    data class KotlinExampleProperties(
            val name: String,
            val description: String,
            val myService: MyService) {
        data class MyService(
                val apiToken: String,
                val uri: URI
    

    29.6. 测试

    虽然可以使用 JUnit 4 来测试 Kotlin 代码,但建议使用 JUnit 5. JUnit 5 允许测试类实例化一次,并在所有类的测试中复用. 这使得可以在非静态方法上使用 @BeforeAll@AfterAll 注解,这非常适合 Kotlin.

    JUnit 5是默认的,并且提供了vintage引擎与JUnit 4向后兼容. 如果不使用它,请排除 org.junit.vintange: junit-vintage-engine. 您还需要将 测试实例生命周期切换为 "per-class".

    要模拟Kotlin类,建议使用MockK. 如果您需要与Mockito特定的@MockBean和@SpyBean注解相对应的Mockk,则可以使用SpringMockK,它提供类似的@MockkBean和@SpykBean注解.

    要使用 JUnit 5,请从 spring-boot-starter-test 中排除 junit:junit 依赖,然后添加 JUnit 5 依赖,并相应地配置 Maven 或 Gradle 插件. 有关更多详细信息,请参阅 JUnit 5 文档. 您还需要将测试实例生命周期切换为 per-class.

    为了模拟 Kotlin 类,建议使用 Mockk. 如果需要 MockK 等效的 Mockito 特定的 @MockBean@SpyBean 注解,则可以使用 SpringMockK,它提供类似的 @MockkBean@SpykBean 注解.

    29.7. 资源

    29.7.1. 进阶阅读

    Kotlin 语言参考

    Kotlin Slack (有专用的 #spring 频道)

    Stackoverflow 上 springkotlin 标签

    在浏览器中尝试 Kotlin

    Kotlin 博客

    Awesome Kotlin

    教程: 使用 Spring Boot 和 Kotlin 构建 Web 应用程序

    使用 Kotlin 开发 Spring Boot 应用程序

    使用 Kotlin、Spring Boot 和 PostgreSQL 开发地理信使

    在 Spring Framework 5.0 中引入 Kotlin 支持

    Spring Framework 5 Kotlin API 实现函数式