本文介绍: Spring Boot “How-to” Guides官方文档中文版。解答了在使用 Spring Boot 时经常出现的 “我该怎么做…… “的问题。虽然没有面面俱到,但也涵盖了不少内容。

本文为官方文档直译版本。原文链接
篇幅较长,遂分两篇

Spring Boot “How-to” 指南中文文档-下

Jersey

利用 Spring Security 保护 Jersey 端点的安全

Spring Security可用于保护基于Jersey的网络应用程序,其方式与保护基于Spring MVC的网络应用程序的方式基本相同。不过,如果你想在 Jersey 中使用 Spring Security 的方法级安全性,就必须将 Jersey 配置为使用 setStatus(int) 而不是 sendError(int)。这样,Jersey 就不会在 Spring Security 有机会向客户端报告身份验证或授权失败之前提交响应。
在应用程序的 ResourceConfig Bean 上,jersey.config.server.response.setStatusOverSendError 属性必须设置为 true,如下例所示:

import java.util.Collections;

import org.glassfish.jersey.server.ResourceConfig;

import org.springframework.stereotype.Component;

@Component
public class JerseySetStatusOverSendErrorConfig extends ResourceConfig {

    public JerseySetStatusOverSendErrorConfig() {
        register(Endpoint.class);
        setProperties(Collections.singletonMap("jersey.config.server.response.setStatusOverSendError", true));
    }

}

与其他网络框架一起使用Jersey

若要将 Jersey 与 Spring MVC 等其他网络框架一起使用,则应对其进行配置,以便允许其他框架处理自己无法处理的请求。首先,将 Spring.jersey.type 应用程序属性的值配置为 filter,从而将 Jersey 配置为使用过滤器而非 servlet。其次,配置 ResourceConfig 以转发会导致 404 的请求,如下例所示。

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletProperties;

import org.springframework.stereotype.Component;

@Component
public class JerseyConfig extends ResourceConfig {

    public JerseyConfig() {
        register(Endpoint.class);
        property(ServletProperties.FILTER_FORWARD_ON_404, true);
    }

}

HTTP Clients

Spring Boot 提供了许多与 HTTP 客户端协同工作的启动器。本节将回答与使用它们相关的问题。

配置 RestTemplate 以使用代理

io.html 中所述,您可以使用 RestTemplateCustomizerRestTemplateBuilder 来创建自定义的 RestTemplate。这是创建配置为使用代理的 RestTemplate 的推荐方法。
代理配置的具体细节取决于所使用的底层客户端请求工厂。

配置基于 Reactor Netty 的 WebClient 使用的 TcpClient

当 Reactor Netty 位于类路径上时,基于 Reactor Netty 的 WebClient 就会自动配置。要自定义客户端对网络连接的处理,请提供一个 ClientHttpConnector Bean。下面的示例配置了 60 秒的连接超时,并添加了一个 ReadTimeoutHandler

import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
import reactor.netty.http.client.HttpClient;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ReactorResourceFactory;
import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;

@Configuration(proxyBeanMethods = false)
public class MyReactorNettyClientConfiguration {

    @Bean
    ClientHttpConnector clientHttpConnector(ReactorResourceFactory resourceFactory) {
        HttpClient httpClient = HttpClient.create(resourceFactory.getConnectionProvider())
                .runOn(resourceFactory.getLoopResources())
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 60000)
                .doOnConnected((connection) -> connection.addHandlerLast(new ReadTimeoutHandler(60)));
        return new ReactorClientHttpConnector(httpClient);
    }

}

请注意,连接提供程序和事件循环资源使用了 ReactorResourceFactory。这可确保接收请求的服务器和发出请求的客户端有效共享资源。

Logging

除了通常由 Spring Framework 的 spring-jcl 模块提供的 Commons Logging API 之外,Spring Boot 没有强制依赖日志记录。要使用 Logback,需要在类路径中包含它和 spring-jcl。推荐的方法是通过启动器,这些启动器都依赖于 spring-boot-starter-logging。对于网络应用程序,你只需要 spring-boot-starter-web,因为它直接依赖于日志启动器。如果使用 Maven,以下依赖关系会为你添加日志记录:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Spring Boot 有一个 LoggingSystem 抽象,它试图根据类路径的内容配置日志记录。如果 Logback 可用,它将是首选。
如果您需要对日志记录进行的唯一更改是设置各种日志记录器的级别,您可以在 application.properties 中使用 “logging.level” 前缀来完成,如下例所示:

logging:
  level:
    org.springframework.web: "debug"
    org.hibernate: "error"

您还可以使用 logging.file.name 设置日志(除控制台外)写入文件的位置。
要配置LoggingSystem更精细的设置,需要使用相关日志系统支持的本地配置格式。默认情况下,Spring Boot 会从系统的默认位置(如 Logback 的 classpath:logback.xml)获取本地配置,但您可以使用 logging.config 属性设置配置文件的位置。

配置 Logback 以记录日志

如果需要对 logback 进行 application.properties 以外的自定义,则需要添加一个标准的 logback 配置文件。您可以在类路径根目录下添加 logback.xml 文件,以便 logback 查找。如果想使用 Spring Boot Logback 扩展,也可以使用 logback-spring.xml

Logback 文档中有专门章节详细介绍了配置。

Spring Boot 提供了许多可包含在您自己的配置中的日志回溯配置。这些包含旨在允许重新应用某些常见的 Spring Boot 约定。
org/springframework/boot/logging/logback/ 下提供了以下文件:

  • defaults.xml – 提供转换规则、模式属性和常用日志记录器配置。
  • console-appender.xml – 使用 CONSOLE_LOG_PATTERN 添加 ConsoleAppender
  • file-appender.xml – 使用带有适当设置的 FILE_LOG_PATTERNROLLING_FILE_NAME_PATTERN 添加 RollingFileAppender

此外,还提供了一个传统的 base.xml 文件,以便与早期版本的 Spring Boot 兼容。
典型的自定义 logback.xml 文件如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    <include resource="org/springframework/boot/logging/logback/console-appender.xml" />
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
    </root>
    <logger name="org.springframework.web" level="DEBUG"/>
</configuration>

您的 logback 配置文件还可以使用 LoggingSystem 为您创建的系统属性:

  • ${PID}: 当前进程 ID。
  • ${LOG_FILE}: 是否在 Boot 的外部配置中设置了 logging.file.name
  • ${LOG_PATH}: 是否在 Boot 的外部配置中设置了logging.file.path(代表日志文件所在目录)。
  • ${log_exception_conversion_word}: 是否在 Boot 的外部配置中设置了 logging.exception-conversion-word
  • ${rolling_file_name_pattern}: 是否在 Boot 的外部配置中设置了 logging.pattern.rolling-file-name

通过使用自定义 Logback 转换器,Spring Boot 还能在控制台上提供一些漂亮的 ANSI 颜色终端输出(但不是在日志文件中)。示例请参见 defaults.xml 配置中的 CONSOLE_LOG_PATTERN
如果类路径上有 Groovy,也可以使用 logback.groovy 配置 Logback。如果存在,则优先使用此设置。

Groovy 配置不支持 Spring 扩展。任何 logback-spring.groovy 文件都不会被检测到。

配置 Logback 仅用于文件输出

如果要禁用控制台日志,只将输出写入文件,则需要自定义 logback-spring.xml,该文件应导入 file-appender.xml,而不是 console-appender.xml,如下例所示:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
    <property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
    <include resource="org/springframework/boot/logging/logback/file-appender.xml" />
    <root level="INFO">
        <appender-ref ref="FILE" />
    </root>
</configuration>

您还需要将 logging.file.name 添加到application.propertiesapplication.yaml 中,如下例所示:

logging:
  file:
    name: "myapplication.log"

配置 Log4j 以记录日志

如果 Log4j 2 位于类路径上,Spring Boot 会支持 Log4j 2 进行日志配置。如果使用启动器组装依赖项,则必须排除 Logback,然后包含 Log4j 2。如果不使用启动器,则除 Log4j 2 外,还需要提供(至少)spring-jcl
推荐的路径是通过启动器,尽管这需要一些调整。下面的示例展示了如何在 Maven 中设置启动器:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

Gradle 提供了几种不同的方法来设置启动器。一种是使用模块替换。为此,需要声明对 Log4j 2 启动器的依赖,并告诉 Gradle 任何默认日志启动器都应被 Log4j 2 启动器替换,如下例所示:

dependencies {
    implementation "org.springframework.boot:spring-boot-starter-log4j2"
    modules {
        module("org.springframework.boot:spring-boot-starter-logging") {
            replacedBy("org.springframework.boot:spring-boot-starter-log4j2", "Use Log4j2 instead of Logback")
        }
    }
}

Log4j 启动器汇集了常见日志需求的依赖项(例如,让 Tomcat 使用 java.util.logging,但使用 Log4j 2 配置输出)。

为确保使用 java.util.logging 执行的调试日志被路由到 Log4j 2,请通过将 java.util.logging.manager 系统属性设置为 org.apache.logging.log4j.jul.LogManager 来配置其 JDK 日志适配器

使用 YAML 或 JSON 配置 Log4j 2

除了默认的 XML 配置格式外,Log4j 2 还支持 YAML 和 JSON 配置文件。要将 Log4j 2 配置为使用其他配置文件格式,请在类路径中添加相应的依赖项,并根据所选文件格式命名配置文件,如下例所示:

格式 依赖 文件名
YAML com.fasterxml.jackson.core:jackson-databind +
com.fasterxml.jackson.dataformat:jackson-dataformat-yaml log4j2.yaml + log4j2.yml
JSON com.fasterxml.jackson.core:jackson-databind log4j2.json + log4j2.jsn

使用组合配置来配置 Log4j 2

Log4j 2 支持将多个配置文件组合成一个复合配置。要在 Spring Boot 中使用此支持,可将一个或多个辅助配置文件的位置配置为 logging.log4j2.config.override。二级配置文件将与一级配置合并,无论一级配置的源文件是 Spring Boot 的默认设置、log4j.xml 等标准位置,还是 logging.config 属性配置的位置。

数据访问

Spring Boot 包含许多用于处理数据源的启动器。本节将回答与此相关的问题。

配置自定义数据源

要配置自己的 DataSource,请在配置中定义该类型的 @Bean。Spring Boot 会在任何需要 DataSource 的地方重用它,包括数据库初始化。如果需要将某些设置外部化,可以将 DataSource 与环境绑定(请参阅 “features.html”)。
下面的示例展示了如何在 bean 中定义数据源:

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {

    @Bean
    @ConfigurationProperties(prefix = "app.datasource")
    public SomeDataSource dataSource() {
        return new SomeDataSource();
    }

}

下面的示例展示了如何通过设置属性来定义数据源:

app:
  datasource:
    url: "jdbc:h2:mem:mydb"
    username: "sa"
    pool-size: 30

假设 SomeDataSource 具有 urlusernamepool-size的常规 JavaBean 属性,这些设置会在数据源提供给其他组件之前自动绑定。
Spring Boot 还提供了一个名为 DataSourceBuilder 的实用构建器类,可用于创建标准数据源之一(如果它在类路径上)。构建器可以根据类路径上的可用数据源检测要使用的数据源。它还会根据 JDBC URL 自动检测驱动程序。
下面的示例展示了如何使用 DataSourceBuilder 创建数据源:

import javax.sql.DataSource;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {

    @Bean
    @ConfigurationProperties("app.datasource")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }

}

要使用该数据源运行应用程序,只需提供连接信息即可。还可以提供特定于池的设置。有关详细信息,请查看运行时将使用的实现。
下面的示例展示了如何通过设置属性来定义 JDBC 数据源:

app:
  datasource:
    url: "jdbc:mysql://localhost/test"
    username: "dbuser"
    password: "dbpass"
    pool-size: 30

不过,这也有一个问题。由于连接池的实际类型没有公开,因此不会在自定义数据源的元数据中生成键,也不会在集成开发环境中完成(因为数据源接口不公开属性)。此外,如果您的类路径上恰好有 Hikari,那么这个基本设置也不起作用,因为 Hikari 没有 url 属性(但有 jdbcUrl 属性)。在这种情况下,必须重写配置如下:

app:
  datasource:
    jdbc-url: "jdbc:mysql://localhost/test"
    username: "dbuser"
    password: "dbpass"
    pool-size: 30

您可以通过强制连接池使用并返回专用实现而不是 DataSource 来解决这个问题。您不能在运行时更改实现,但选项列表将是明确的。
下面的示例展示了如何使用 DataSourceBuilder 创建 HikariDataSource

import com.zaxxer.hikari.HikariDataSource;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {

    @Bean
    @ConfigurationProperties("app.datasource")
    public HikariDataSource dataSource() {
        return DataSourceBuilder.create().type(HikariDataSource.class).build();
    }

}

您甚至可以进一步利用 DataSourceProperties 为您提供的功能,即在未提供 URL 的情况下,提供带有合理用户名和密码的默认嵌入式数据库。您可以通过任何 DataSourceProperties 对象的状态轻松初始化 DataSourceBuilder,因此您也可以注入 Spring Boot 自动创建的 DataSource。不过,这样会将配置分成两个命名空间:urlusernamepasswordtypedriver放在 spring.datasource,其余的放在自定义命名空间(app.datasource)。为避免这种情况,您可以在自定义命名空间中重新定义自定义 DataSourceProperties,如下例所示:

import com.zaxxer.hikari.HikariDataSource;

import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {

    @Bean
    @Primary
    @ConfigurationProperties("app.datasource")
    public DataSourceProperties dataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean
    @ConfigurationProperties("app.datasource.configuration")
    public HikariDataSource dataSource(DataSourceProperties properties) {
        return properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
    }

}

除了(在代码中)选择专用连接池并在 app.datasource.configuration 子命名空间中公开其设置外,这种设置与 Spring Boot 默认为您提供的设置保持一致。由于 DataSourceProperties 会为您处理 url/jdbcUrl 转换,因此您可以对其进行如下配置:

app:
  datasource:
    url: "jdbc:mysql://localhost/test"
    username: "dbuser"
    password: "dbpass"
    configuration:
      maximum-pool-size: 30

Spring Boot 会将特定于 Hikari 的设置公开到 spring.datasource.hikari。本示例使用更通用的配置子命名空间,因为本示例不支持多种数据源实现。

由于您的自定义配置选择了 Hikari,因此 app.datasource.type 没有任何作用。在实践中,生成器会使用您在此处设置的任何值进行初始化,然后通过调用 .type() 进行重载。

配置两个数据源

如果需要配置多个数据源,可以采用上一节所述的相同技巧。不过,您必须将其中一个数据源实例标记为 @Primary,因为接下来的各种自动配置都希望能按类型获得其中一个。
如果创建了自己的数据源,自动配置就会退出。在下面的示例中,我们在主数据源上提供了与自动配置完全相同的功能集:

import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.dbcp2.BasicDataSource;

import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

@Configuration(proxyBeanMethods = false)
public class MyDataSourcesConfiguration {

    @Bean
    @Primary
    @ConfigurationProperties("app.datasource.first")
    public DataSourceProperties firstDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean
    @Primary
    @ConfigurationProperties("app.datasource.first.configuration")
    public HikariDataSource firstDataSource(DataSourceProperties firstDataSourceProperties) {
        return firstDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
    }

    @Bean
    @ConfigurationProperties("app.datasource.second")
    public BasicDataSource secondDataSource() {
        return DataSourceBuilder.create().type(BasicDataSource.class).build();
    }

}

firstDataSourceProperties 必须标记为 @Primary,以便数据库初始化功能使用您的副本(如果您使用初始化程序)。

这两个数据源还可以进行高级定制。例如,您可以对它们进行如下配置:

app:
  datasource:
    first:
      url: "jdbc:mysql://localhost/first"
      username: "dbuser"
      password: "dbpass"
      configuration:
        maximum-pool-size: 30

    second:
      url: "jdbc:mysql://localhost/second"
      username: "dbuser"
      password: "dbpass"
      max-total: 30

您也可以将相同的概念应用于二级数据源,如下例所示:

import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.dbcp2.BasicDataSource;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

@Configuration(proxyBeanMethods = false)
public class MyCompleteDataSourcesConfiguration {

    @Bean
    @Primary
    @ConfigurationProperties("app.datasource.first")
    public DataSourceProperties firstDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean
    @Primary
    @ConfigurationProperties("app.datasource.first.configuration")
    public HikariDataSource firstDataSource(DataSourceProperties firstDataSourceProperties) {
        return firstDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
    }

    @Bean
    @ConfigurationProperties("app.datasource.second")
    public DataSourceProperties secondDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean
    @ConfigurationProperties("app.datasource.second.configuration")
    public BasicDataSource secondDataSource(
            @Qualifier("secondDataSourceProperties") DataSourceProperties secondDataSourceProperties) {
        return secondDataSourceProperties.initializeDataSourceBuilder().type(BasicDataSource.class).build();
    }

}

上例在自定义命名空间上配置了两个数据源,其逻辑与 Spring Boot 在自动配置中使用的逻辑相同。请注意,每个configuration子命名空间都会根据所选实现提供高级设置。

使用 Spring Data Repositories

Spring Data 可以创建各种 @Repository 接口的实现。只要这些 @Repository 注解包含在某个自动配置包中,通常是注释了 @SpringBootApplication@EnableAutoConfiguration 的主应用程序类的包(或子包),Spring Boot 就会为你处理所有这些注解。
对于许多应用程序来说,你所需要的只是在类路径中添加正确的 Spring Data 依赖项。针对 JPA 有 spring-boot-starter-data-jpa,针对 Mongodb 有 spring-boot-starter-data-mongodb,还有其他各种支持技术的启动器。要开始使用,请创建一些存储库接口来处理 @Entity 对象。
Spring Boot 会通过扫描自动配置包来确定 @Repository 定义的位置。要获得更多控制权,请使用 Spring Data 的 @Enable...Repositories 注解。
有关 Spring Data 的更多信息,请参阅 Spring Data 项目页面。

从 Spring 配置中分离 @Entity 定义

Spring Boot 通过扫描自动配置包来确定 @Entity 定义的位置。要获得更多控制权,请使用 @EntityScan 注解,如下例所示:

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
@EntityScan(basePackageClasses = City.class)
public class MyApplication {

    // ...

}

配置 JPA 属性

Spring Data JPA 已经提供了一些独立于供应商的配置选项(如用于 SQL 日志的选项),Spring Boot 将这些选项和其他一些用于 Hibernate 的选项作为外部配置属性公开。其中一些选项会根据上下文自动检测,因此无需设置。
spring.jpa.hibernate.ddl-auto 是一个特例,因为根据运行时条件的不同,它有不同的默认值。如果使用的是嵌入式数据库,且没有模式管理器(如 Liquibase 或 Flyway)处理数据源,则默认为create-drop。在所有其他情况下,默认为none
要使用的方言由 JPA 提供者检测。如果希望自己设置方言,请设置 spring.jpa.database-platform 属性。
最常用的设置选项如下例所示:

spring:
  jpa:
    hibernate:
      naming:
        physical-strategy: "com.example.MyPhysicalNamingStrategy"
    show-sql: true

此外,在创建本地 EntityManagerFactory 时,spring.jpa.properties.* 中的所有属性都会作为普通 JPA 属性(去掉前缀)传递。

您需要确保在 spring.jpa.properties.* 下定义的名称与 JPA 提供商期望的名称完全一致。Spring Boot 不会尝试对这些条目进行任何形式的宽松绑定。
例如,如果要配置 Hibernate 的批处理大小,就必须使用 spring.jpa.properties.hibernate.jdbc.batch_size。如果使用其他形式,如 batchSizebatch-size,则 Hibernate 不会应用该设置。

如果需要对 Hibernate 属性进行高级定制,可以考虑注册一个 HibernatePropertiesCustomizer Bean,在创建 EntityManagerFactory 之前调用该 Bean。这将优先于自动配置所应用的任何内容。

配置 Hibernate 命名策略

Hibernate 使用两种不同的命名策略将对象模型中的名称映射到相应的数据库名称。物理策略和隐式策略实现的全限定类名可分别通过设置 spring.jpa.hibernate.naming.physical-strategyspring.jpa.hibernate.naming.implicit-strategy 属性来配置。另外,如果应用程序上下文中有 ImplicitNamingStrategyPhysicalNamingStrategy Bean,Hibernate 将自动配置为使用它们。
默认情况下,Spring Boot 使用 CamelCaseToUnderscoresNamingStrategy 配置物理命名策略。使用该策略时,所有小圆点都会被下划线替换,驼峰字母也会被下划线替换。此外,默认情况下,所有表名都以小写字母生成。例如,TelephoneNumber 实体被映射到 telephone_number 表。如果您的模式需要混合大小写标识符,请定义自定义的 CamelCaseToUnderscoresNamingStrategy Bean,如下例所示:

import org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyHibernateConfiguration {

    @Bean
    public CamelCaseToUnderscoresNamingStrategy caseSensitivePhysicalNamingStrategy() {
        return new CamelCaseToUnderscoresNamingStrategy() {

            @Override
            protected boolean isCaseInsensitive(JdbcEnvironment jdbcEnvironment) {
                return false;
            }

        };
    }

}

如果希望使用 Hibernate 的默认值,请设置以下属性:

spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

或者,您也可以配置以下 bean:

import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
class MyHibernateConfiguration {

    @Bean
    PhysicalNamingStrategyStandardImpl caseSensitivePhysicalNamingStrategy() {
        return new PhysicalNamingStrategyStandardImpl();
    }

}

详见 HibernateJpaAutoConfigurationJpaBaseConfiguration

配置 Hibernate 二级缓存

Hibernate 二级缓存可以为一系列缓存提供者进行配置。与其配置 Hibernate 再次查找缓存提供者,不如尽可能提供上下文中可用的缓存提供者。
要做到这一点,首先要确保类路径上有org.hibernate.orm:hibernate-jcache。然后,添加一个 HibernatePropertiesCustomizer Bean,如下例所示:

import org.hibernate.cache.jcache.ConfigSettings;

import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer;
import org.springframework.cache.jcache.JCacheCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyHibernateSecondLevelCacheConfiguration {

    @Bean
    public HibernatePropertiesCustomizer hibernateSecondLevelCacheCustomizer(JCacheCacheManager cacheManager) {
        return (properties) -> properties.put(ConfigSettings.CACHE_MANAGER, cacheManager.getCacheManager());
    }

}

该自定义器将配置 Hibernate 使用与应用程序相同的 CacheManager。也可以使用单独的 CacheManager 实例。详情请参阅《Hibernate 用户指南》

在 Hibernate 组件中使用依赖注入

默认情况下,Spring Boot 会注册一个使用 BeanFactoryBeanContainer 实现,以便转换器和实体监听器可以使用常规的依赖注入。
通过注册 HibernatePropertiesCustomizer 来删除或更改 hibernate.resource.beans.container 属性,可以禁用或调整这种行为。

使用自定义 EntityManagerFactory

要完全控制 EntityManagerFactory 的配置,您需要添加一个名为 “entityManagerFactory” 的 @Bean。如果存在该类型的 Bean,Spring Boot 的自动配置会关闭实体管理器。

使用多个 EntityManagerFactories

如果您需要针对多个数据源使用 JPA,您可能需要为每个数据源配置一个 EntityManagerFactory。Spring ORM 的 LocalContainerEntityManagerFactoryBean 可让您根据需要配置 EntityManagerFactory。您还可以重复使用 JpaProperties 为每个 EntityManagerFactory 绑定设置,如下例所示:

import javax.sql.DataSource;

import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;

@Configuration(proxyBeanMethods = false)
public class MyEntityManagerFactoryConfiguration {

    @Bean
    @ConfigurationProperties("app.jpa.first")
    public JpaProperties firstJpaProperties() {
        return new JpaProperties();
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean firstEntityManagerFactory(DataSource firstDataSource,
            JpaProperties firstJpaProperties) {
        EntityManagerFactoryBuilder builder = createEntityManagerFactoryBuilder(firstJpaProperties);
        return builder.dataSource(firstDataSource).packages(Order.class).persistenceUnit("firstDs").build();
    }

    private EntityManagerFactoryBuilder createEntityManagerFactoryBuilder(JpaProperties jpaProperties) {
        JpaVendorAdapter jpaVendorAdapter = createJpaVendorAdapter(jpaProperties);
        return new EntityManagerFactoryBuilder(jpaVendorAdapter, jpaProperties.getProperties(), null);
    }

    private JpaVendorAdapter createJpaVendorAdapter(JpaProperties jpaProperties) {
        // ... map JPA properties as needed
        return new HibernateJpaVendorAdapter();
    }

}

上面的示例使用名为 firstDataSource 的数据源 Bean 创建了 EntityManagerFactory。它扫描与 Order 位于同一软件包中的实体。可以使用 app.first.jpa 命名空间映射其他 JPA 属性。

当您自己为 LocalContainerEntityManagerFactoryBean 创建一个 Bean 时,在创建自动配置的 LocalContainerEntityManagerFactoryBean 时应用的任何自定义都将丢失。例如,对于 Hibernate,spring.jpa.hibernate 前缀下的任何属性都不会自动应用到 LocalContainerEntityManagerFactoryBean。如果您依赖这些属性来配置命名策略或 DDL 模式等内容,则需要在创建 LocalContainerEntityManagerFactoryBean Bean 时进行显式配置。

您应该为需要 JPA 访问的任何其他数据源提供类似的配置。为了完成整个配置,您还需要为每个 EntityManagerFactory 配置一个 JpaTransactionManager。或者,你也可以使用一个横跨两者的 JTA 事务管理器。
如果使用 Spring Data,则需要相应地配置 @EnableJpaRepositories,如以下示例所示:

import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(basePackageClasses = Order.class, entityManagerFactoryRef = "firstEntityManagerFactory")
public class OrderConfiguration {

}
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(basePackageClasses = Customer.class, entityManagerFactoryRef = "secondEntityManagerFactory")
public class CustomerConfiguration {

}

使用传统的 persistence.xml 文件

Spring Boot 默认不会搜索或使用 META-INF/persistence.xml。如果希望使用传统的 persistence.xml,则需要定义自己的 @Bean 类型 LocalEntityManagerFactoryBean(ID 为 “entityManagerFactory”),并在其中设置持久化单元名称。
有关默认设置,请参见 JpaBaseConfiguration

使用 Spring Data JPA 和 Mongo Repositories

Spring Data JPA 和 Spring Data Mongo 都能自动为您创建Repository实现。如果它们都出现在类路径上,您可能需要进行一些额外的配置,告诉 Spring Boot 要创建哪些存储库。最明确的方法是使用标准的 Spring Data @EnableJpaRepositories@EnableMongoRepositories 注解,并提供 Repository 接口的位置。
您还可以使用标记(spring.data.*.repositories.enabledspring.data.*.repositories.type)在外部配置中开关自动配置的存储库。例如,当你想关闭 Mongo 资源库,但仍想使用自动配置的 MongoTemplate 时,这样做就很有用。
其他自动配置的 Spring Data 资源库类型(Elasticsearch、Redis 等)也存在同样的障碍和功能。要使用它们,请相应更改注释和标记的名称。

自定义 Spring Data 的 Web 支持

Spring Data 提供网络支持,简化了 Spring Data 存储库在网络应用程序中的使用。Spring Boot 在 spring.data.web 命名空间中提供了用于自定义配置的属性。请注意,如果您使用的是 Spring Data REST,则必须使用 spring.data.rest 命名空间中的属性。

将 Spring Data Repositories 作为 REST 端点公开

只要应用程序启用了 Spring MVC,Spring Data REST 就能将 Repository 实现作为 REST 端点公开。
Spring Boot 公开了一组有用的属性(来自 spring.data.rest 名称空间),用于自定义 RepositoryRestConfiguration。如果需要提供额外的自定义,则应使用 RepositoryRestConfigurer Bean。

如果不在自定义 RepositoryRestConfigurer 上指定任何顺序,它将在 Spring Boot 内部使用的顺序之后运行。如果需要指定顺序,请确保顺序大于 0

配置 JPA 使用的组件

如果要配置 JPA 使用的组件,则需要确保在 JPA 之前初始化该组件。当组件是自动配置的时候,Spring Boot 会帮你处理这个问题。例如,当自动配置 Flyway 时,Hibernate 会被配置为依赖于 Flyway,这样 Flyway 就有机会在 Hibernate 尝试使用它之前初始化数据库。
如果你要自己配置一个组件,可以使用 EntityManagerFactoryDependsOnPostProcessor 子类作为设置必要依赖关系的便捷方法。例如,如果你使用以 Elasticsearch 作为索引管理器的 Hibernate Search,那么任何 EntityManagerFactory Bean 都必须配置为依赖于 elasticsearchClient Bean,如下例所示:

import jakarta.persistence.EntityManagerFactory;

import org.springframework.boot.autoconfigure.orm.jpa.EntityManagerFactoryDependsOnPostProcessor;
import org.springframework.stereotype.Component;

/**
 * {@link EntityManagerFactoryDependsOnPostProcessor} that ensures that
 * {@link EntityManagerFactory} beans depend on the {@code elasticsearchClient} bean.
 */
@Component
public class ElasticsearchEntityManagerFactoryDependsOnPostProcessor
        extends EntityManagerFactoryDependsOnPostProcessor {

    public ElasticsearchEntityManagerFactoryDependsOnPostProcessor() {
        super("elasticsearchClient");
    }

}

使用两个数据源配置 jOOQ

如果需要在多个数据源中使用 jOOQ,则应为每个数据源创建自己的 DSLContext。更多详情,请参阅 JooqAutoConfiguration

特别是,JooqExceptionTranslatorSpringTransactionProvider 可以重复使用,以提供与自动配置在单个数据源上所做的类似功能。

数据库初始化

SQL 数据库的初始化方式各不相同,具体取决于堆栈的类型。当然,也可以手动初始化,前提是数据库是一个独立的进程。建议使用单一机制生成模式。

使用 JPA 初始化数据库

JPA 具有生成 DDL 的功能,这些功能可以设置为在启动时针对数据库运行。这可以通过两个外部属性来控制:

  • spring.jpa.generate-ddl(布尔值)用于开关该功能,与供应商无关。
  • spring.jpa.hibernate.ddl-auto(枚举)是 Hibernate 的一项功能,能以更精细的方式控制行为。本指南稍后将详细介绍该功能。

使用 Hibernate 初始化数据库

您可以显式设置 spring.jpa.hibernate.ddl-auto,标准的 Hibernate 属性值为 nonevalidateupdatecreatecreate-drop。Spring Boot 会根据它是否认为你的数据库是嵌入式的,为你选择一个默认值。如果没有检测到模式管理器,则默认值为create-drop,或者在其他情况下,则默认值为nonehsqldbh2derby 是候选数据库,而其他数据库则不是。从内存数据库切换到 “真实” 数据库时要小心,不要假设新平台中存在表和数据。要么明确设置 ddl-auto,要么使用其他机制初始化数据库。

通过启用 org.hibernate.SQL 日志,可以输出模式创建过程。如果启用调试模式,日志会自动输出。

此外,如果 Hibernate 从头开始创建模式(即 ddl-auto 属性设置为 createcreate-drop),类路径根目录下名为 import.sql 的文件会在启动时被执行。如果你小心谨慎,这对演示和测试可能很有用,但在生产过程中,你可能不希望类路径中出现这种情况。这是 Hibernate 的一项功能(与 Spring 无关)。

使用基本 SQL 脚本初始化数据库

Spring Boot 可以自动创建 JDBC DataSource 或 R2DBC ConnectionFactory 的模式(DDL 脚本)并初始化其数据(DML 脚本)。
默认情况下,它会从optional:classpath*:schema.sql 加载模式脚本,从optional:classpath*:data.sql 加载数据脚本。这些模式和数据脚本的位置可分别使用 spring.sql.init.schema-locationsspring.sql.init.data-locations 进行自定义。optional:前缀表示应用程序将在文件不存在时启动。要使应用程序在文件不存在时无法启动,请移除optional:前缀。
此外,Spring Boot 还会处理optional:classpath*:schema-${platform}.sqloptional:classpath*:data-${platform}.sql 文件(如果存在),其中 ${platform}spring.sql.init.platform 的值。这样,您就可以在必要时切换到特定于数据库的脚本。例如,可以将其设置为数据库的供应商名称(hsqldbh2oraclemysqlpostgresql 等)。
默认情况下,只有在使用嵌入式内存数据库时才会执行 SQL 数据库初始化。要始终初始化 SQL 数据库(无论其类型如何),请将 spring.sql.init.mode 设为always。同样,要禁用初始化,请将 spring.sql.init.mode 设为 never。默认情况下,Spring Boot 会启用基于脚本的数据库初始化程序的快速故障功能。这意味着,如果脚本导致异常,应用程序将无法启动。您可以通过设置 spring.sql.init.continue-on-error 来调整该行为。
在创建任何 JPA EntityManagerFactory Bean 之前,默认会执行基于脚本的数据源初始化。schema.sql 可用于为 JPA 管理的实体创建模式,而 data.sql 可用于填充模式。虽然我们不建议使用多种数据源初始化技术,但如果你希望基于脚本的数据源初始化能在 Hibernate 执行的模式创建基础上进行,可将 spring.jpa.defer-datasource-initialization 设为 true。这样,数据源初始化将推迟到任何 EntityManagerFactory Bean 创建并初始化之后。然后,schema.sql 可用于对 Hibernate 执行的模式创建进行添加,data.sql 可用于对其进行填充。

初始化脚本支持单行注释 -- 和块注释 /* */。不支持其他注释格式。

如果使用 Flyway 或 Liquibase 等高级数据库迁移工具,则应单独使用它们来创建和初始化模式。不建议在使用 Flyway 或 Liquibase 的同时使用基本的 schema.sqldata.sql 脚本,未来的版本中将取消对它们的支持。
如果需要使用更高级别的数据库迁移工具来初始化测试数据,请参阅有关 Flyway 和 Liquibase 的章节。

初始化 Spring Batch 数据库

如果使用 Spring Batch,它预装了适用于大多数流行数据库平台的 SQL 初始化脚本。Spring Boot 可以检测您的数据库类型,并在启动时执行这些脚本。如果使用的是嵌入式数据库,默认情况下会这样做。您也可以为任何数据库类型启用该功能,如下例所示:

spring:
  batch:
    jdbc:
      initialize-schema: "always"

您也可以将 spring.batch.jdbc.initialize-schema 设置为never,从而明确关闭初始化。

使用高级数据库迁移工具

Spring Boot 支持两种更高级别的迁移工具: FlywayLiquibase

在启动时执行 Flyway 数据库迁移

要在启动时自动运行 Flyway 数据库迁移,请在类路径中添加 org.flywaydb:flyway-core
通常情况下,迁移脚本的格式为 V<VERSION>__<NAME>.sql(<VERSION>为下划线分隔的版本,如 “1” 或 “2_1”)。默认情况下,它们位于名为 classpath:db/migration 的目录中,但你可以通过设置 spring.flyway.locations 来修改该位置。这是一个以逗号分隔的列表,包含一个或多个classpath:filesystem:位置。例如,以下配置将在默认的类路径位置和/opt/migration目录下搜索脚本:

spring:
  flyway:
    locations: "classpath:db/migration,filesystem:/opt/migration"

您还可以添加一个特殊的 {vendor} 占位符,以使用特定于供应商的脚本。假设如下:

spring:
  flyway:
    locations: "classpath:db/migration/{vendor}"

前面的配置并没有使用db/migration,而是根据数据库的类型(如MySQL的db/migration/mysql)来设置要使用的目录。数据库驱动程序(DatabaseDriver)中提供了支持的数据库列表。
迁移程序也可以用Java编写。Flyway会自动配置任何实现了JavaMigration的Bean。
FlywayProperties 提供了 Flyway 的大部分设置和一小部分附加属性,可用于禁用迁移或关闭位置检查。如果你需要对配置进行更多控制,可以考虑注册一个 FlywayConfigurationCustomizer Bean。
Spring Boot 调用 Flyway.migrate() 来执行数据库迁移。如果需要更多控制,可提供一个实现 FlywayMigrationStrategy@Bean
Flyway支持SQL和Java回调。要使用基于 SQL 的回调,请将回调脚本放在 classpath:db/migration 目录中。要使用基于 Java 的回调,可创建一个或多个实现 Callback 的 Bean。任何此类 Bean 都会自动在 Flyway 注册。它们可以通过使用 @Order 或实现 Ordered 进行排序。实现已废弃的 FlywayCallback 接口的 Bean 也能被检测到,但它们不能与 Callback Bean 一起使用。
默认情况下,Flyway 会自动连接上下文中的(@Primary)数据源,并将其用于迁移。如果你想使用不同的数据源,可以创建一个并将其 @Bean 标记为 @FlywayDataSource。如果需要两个数据源,请记得创建另一个数据源并将其标记为 @Primary。另外,你也可以在外部属性中设置 spring.flyway.[url,user,password],从而使用 Flyway 的原生数据源。设置 spring.flyway.urlspring.flyway.user 即可让 Flyway 使用自己的数据源。如果未设置这三个属性中的任何一个,则将使用其对应的 spring.datasource 属性的值。
您还可以使用 Flyway 为特定场景提供数据。例如,你可以将特定于测试的迁移放在 src/test/resources,只有当应用程序启动测试时,迁移才会运行。此外,你还可以使用特定配置文件的配置来定制 spring.flyway.locations,这样只有当特定配置文件处于活动状态时,某些迁移才会运行。例如,你可以在 application-dev.properties 中指定以下设置:

spring:
  flyway:
    locations: "classpath:/db/migration,classpath:/dev/db/migration"

在这种设置下,dev/db/migration 中的迁移只有在 dev 配置文件处于活动状态时才会运行。

在启动时执行 Liquibase 数据库迁移

要在启动时自动运行 Liquibase 数据库迁移,请在类路径中添加 org.liquibase:liquibase-core

org.liquibase:liquibase-core 添加到类路径后,默认情况下会在应用程序启动时和测试运行前运行数据库迁移。可以使用 spring.liquibase.enabled 属性自定义这一行为,并在主配置和测试配置中设置不同的值。不可能使用两种不同的方式初始化数据库(例如,Liquibase 用于应用程序启动,JPA 用于测试运行)。

默认情况下,主变更日志从 db/changelog/db.changelog-master.yaml 读取,但你可以通过设置 spring.liquibase.change-log 来更改位置。除 YAML 外,Liquibase 还支持 JSON、XML 和 SQL 更改日志格式。
默认情况下,Liquibase 会自动连接上下文中的 (@Primary) DataSource,并将其用于迁移。如果你需要使用另一个数据源,可以创建一个并将其 @Bean 标记为 @LiquibaseDataSource。如果你需要两个数据源,记得创建另一个数据源并将其标记为 @Primary。或者,你也可以通过在外部属性中设置 spring.liquibase.[driver-class-name,url,user,password]来使用 Liquibase 的原生数据源。设置 spring.liquibase.urlspring.liquibase.user 即可使 Liquibase 使用其自身的数据源。如果未设置这三个属性中的任何一个,则将使用其对应的 spring.datasource 属性的值。
有关上下文、默认模式等可用设置的详情,请参阅 LiquibaseProperties

使用 Flyway 进行仅供测试的迁移

如果要创建用于填充测试数据库的 Flyway 迁移,请将其放在 src/test/resources/db/migration 中。例如,名为 src/test/resources/db/migration/V9999__test-data.sql 的文件将在生产迁移后执行,而且只有在运行测试时才会执行。你可以使用该文件创建所需的测试数据。该文件不会打包到 uber jar 或容器中。

使用 Liquibase 进行仅供测试的迁移

如果你想创建填充测试数据库的 Liquibase 迁移,你必须创建一个测试更新日志,其中也包括生产更新日志。
首先,你需要配置 Liquibase,以便在运行测试时使用不同的更新日志。一种方法是创建 Spring Boot 测试配置文件,并在其中放入 Liquibase 属性。为此,创建一个名为 src/test/resources/application-test.properties 的文件,并在其中加入以下属性:

spring:
  liquibase:
    change-log: "classpath:/db/changelog/db.changelog-test.yaml"

这将配置 Liquibase 在测试配置文件中运行时使用不同的更新日志。
现在在 src/test/resources/db/changelog/db.changelog-test.yaml 创建更新日志文件:

databaseChangeLog:
  - include:
      file: classpath:/db/changelog/db.changelog-master.yaml
  - changeSet:
      runOrder: "last"
      id: "test"
      changes:
        # Insert your changes here

该变更日志将在运行测试时使用,但不会打包到 uber jar 或容器中。它包括生产变更日志,然后声明一个新的变更集,其 runOrder: last 设置指定它在所有生产变更集运行后运行。现在,您可以使用 insert 变更集插入数据,或使用 sql 变更集直接执行 SQL。
最后要做的是配置 Spring Boot,以便在运行测试时激活测试配置文件。为此,您可以在 @SpringBootTest 注解的测试类中添加 @ActiveProfiles("test") 注解。

依赖于初始化数据库

数据库初始化在应用程序启动时进行,是应用程序上下文刷新的一部分。为了允许在启动过程中访问已初始化的数据库,系统会自动检测作为数据库初始化器的 Bean 和需要数据库已初始化的 Bean。初始化依赖于数据库已初始化的 Bean 将被配置为依赖于初始化数据库的 Bean。如果在启动过程中,应用程序尝试访问数据库,但数据库尚未初始化,则可以配置对初始化数据库和要求数据库已初始化的 Bean 进行额外检测。

检测数据库初始化

Spring Boot 会自动检测初始化 SQL 数据库的以下类型的 Bean:

  • DataSourceScriptDatabaseInitializer
  • EntityManagerFactory
  • Flyway
  • FlywayMigrationInitializer
  • R2dbcScriptDatabaseInitializer
  • SpringLiquibase

如果您使用的是数据库初始化库的第三方启动程序,它可能会提供一个检测器,以便自动检测到其他类型的 Bean。要检测到其他 Bean,请在 META-INF/spring.factories 中注册 DatabaseInitializerDetector 的实现。

检测依赖数据库初始化的 Bean

Spring Boot 会自动检测依赖于数据库初始化的以下类型的 Bean:

  • AbstractEntityManagerFactoryBean(除非将 spring.jpa.defer-datasource-initialization 设为 true
  • DSLContext (jOOQ)
  • EntityManagerFactory(除非 Spring.jpa.defer-datasource-initialization 设为 true
  • JdbcClient
  • JdbcOperations
  • 命名参数 JdbcOperations

如果您使用的是第三方启动数据访问库,它可能会提供一个检测器,以便自动检测到其他类型的 Bean。要检测到其他 Bean,请在 META-INF/spring.factories 中注册 DependsOnDatabaseInitializationDetector 的实现。或者,用 @DependsOnDatabaseInitialization 对 bean 的类或其 @Bean 方法进行注解。

NoSQL

Spring Boot 提供了许多支持 NoSQL 技术的启动器。本节将回答与 Spring Boot 一起使用 NoSQL 时出现的问题。

用 Jedis 代替 Lettuce

默认情况下,Spring Boot 启动程序 (spring-boot-starter-data-redis) 使用 Lettuce。您需要排除该依赖关系,转而使用 Jedis。Spring Boot 会管理这两个依赖关系,因此您可以切换到 Jedis,而无需指定版本。
下面的示例展示了如何在 Maven 中做到这一点:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <exclusions>
        <exclusion>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>

下面的示例展示了如何在 Gradle 中实现这一功能:

dependencies {
    implementation('org.springframework.boot:spring-boot-starter-data-redis') {
        exclude group: 'io.lettuce', module: 'lettuce-core'
    }
    implementation 'redis.clients:jedis'
    // ...
}

Messaging

Spring Boot 提供了许多支持消息传递的启动器。本节将回答与 Spring Boot 一起使用消息传递时出现的问题。

禁用事务处理 JMS 会话

如果您的 JMS 代理不支持事务会话,您就必须完全禁用对事务的支持。如果你创建了自己的 JmsListenerContainerFactory,那就没什么可做的了,因为默认情况下它不能进行事务处理。如果想使用 DefaultJmsListenerContainerFactoryConfigurer 重用 Spring Boot 的默认设置,可以禁用事务会话,如下所示:

import jakarta.jms.ConnectionFactory;

import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;

@Configuration(proxyBeanMethods = false)
public class MyJmsConfiguration {

    @Bean
    public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(ConnectionFactory connectionFactory,
            DefaultJmsListenerContainerFactoryConfigurer configurer) {
        DefaultJmsListenerContainerFactory listenerFactory = new DefaultJmsListenerContainerFactory();
        configurer.configure(listenerFactory, connectionFactory);
        listenerFactory.setTransactionManager(null);
        listenerFactory.setSessionTransacted(false);
        return listenerFactory;
    }

}

前面的示例覆盖了默认工厂,如果应用程序定义了其他工厂,也应将其应用到这些工厂中。

Batch Applications

在 Spring Boot 应用程序中使用 Spring Batch 时,经常会出现一些问题。本节将讨论这些问题。

指定Batch Data Source

默认情况下,批处理应用程序需要一个 DataSource 来存储作业详细信息。Spring Batch 默认需要一个数据源。要使用应用程序主数据源以外的数据源,请声明一个数据源 Bean,并用 @BatchDataSource 对其 @Bean 方法进行注解。如果您希望使用两个数据源,请记住将另一个数据源标记为 @Primary。要加强控制,可在 @Configuration 类中添加 @EnableBatchProcessing 或扩展 DefaultBatchConfiguration。更多详情,请参阅 @EnableBatchProcessingDefaultBatchConfiguration 的 Javadoc。
有关 Spring Batch 的更多信息,请参阅 Spring Batch 项目页面

启动时运行 Spring Batch Jobs

spring-boot-starter-batch 添加到应用程序的类路径中,即可启用 Spring Batch自动配置。
如果在应用程序上下文中发现单个Job,则会在启动时执行该作业(详见 JobLauncherApplicationRunner)。如果发现多个 Job Bean,则必须使用 spring.batch.job.name 指定应执行的作业。
要禁止运行在应用程序上下文中找到的Job,请将 spring.batch.job.enabled 设置为 false
有关详细信息,请参阅 BatchAutoConfiguration

通过命令行运行

Spring Boot 会将以 -- 开头的命令行参数转换为属性添加到Environment中,请参阅访问命令行属性。这不应用于向批处理作业传递参数。要在命令行中指定批处理参数,请使用常规格式(即不含--),如下例所示:

$ java -jar myapp.jar someParameter=someValue anotherParameter=anotherValue

如果在命令行中指定了环境属性,则作业会忽略该属性。请看下面的命令

$ java -jar myapp.jar --server.port=7070 someParameter=someValue

这只为批处理任务提供了一个参数:someParameter=someValue

重新启动停止或失败的作业

要重新启动失败的任务,必须在命令行上重新指定所有参数(识别和非识别参数)。非识别参数不会从上次执行中复制。这样就可以修改或删除这些参数。

使用自定义 JobParametersIncrementer 时,必须收集增量器管理的所有参数,才能重新启动失败的执行。

存储任务存储库

Spring Batch 需要一个用于作业存储库的数据存储。如果使用 Spring Boot,则必须使用实际数据库。请注意,它可以是内存数据库,请参阅配置作业存储库

Actuator

Spring Boot 包含 Spring Boot Actuator。本节将回答在使用过程中经常出现的问题。

更改执行器端点的 HTTP 端口或地址

在独立应用程序中,Actuator HTTP 端口默认与主 HTTP 端口相同。要使应用程序监听不同的端口,可设置外部属性:management.server.port。要在完全不同的网络地址上监听(例如,内部网络用于管理,外部网络用于用户应用程序),也可以将 management.server.address 设置为服务器可以绑定的有效 IP 地址。
更多详情,请参阅 ManagementServerProperties 源代码和 “生产就绪功能 “部分中的 “actuator.html”。

自定义 “whitelabel” 错误页面

Spring Boot 会安装一个 “whitelabel” 错误页面,如果遇到服务器错误,就会在浏览器客户端看到该页面(使用 JSON 和其他媒体类型的机器客户端应该会看到带有正确错误代码的合理响应)。

设置 server.error.whitelabel.enabled=false 可关闭默认错误页面。这样做可以恢复你所使用的 servlet 容器的默认设置。请注意,Spring Boot 仍会尝试解析错误视图,因此你可能应该添加自己的错误页面,而不是完全禁用它。

使用自己的模板覆盖错误页面取决于您使用的模板技术。例如,如果使用 Thymeleaf,可以添加 error.html 模板。如果使用 FreeMarker,则可以添加 error.ftlh 模板。一般来说,你需要一个解析名称为 errorView 或一个处理 /error 路径的 @Controller。除非您替换了某些默认配置,否则您应该在 ApplicationContext 中找到一个 BeanNameViewResolver,因此命名为 error @Bean 将是一种方法。有关更多选项,请参阅 ErrorMvcAutoConfiguration
另请参阅 “错误处理” 部分,了解如何在 servlet 容器中注册处理程序。

自定义脱敏

要控制 sanitization,请定义 SanitizingFunction Bean。调用该函数的 SanitizableData 可以访问键和值以及它们来自的 PropertySource。例如,这允许您对来自特定属性源的每个值进行脱敏。每个 SanitizingFunction 都会被依次调用,直到某个函数改变了可脱敏数据的值。

将健康指标映射到 Micrometer 度量标准

Spring Boot 健康指标会返回一个 Status 类型,用于指示系统的整体健康状态。如果要监控或警告特定应用程序的健康水平,可以使用 Micrometer 将这些状态导出为指标。Spring Boot 默认使用状态代码 “UP”、“DOWN”、”OUT_OF_SERVICE “和 “UNKNOWN”。要导出这些状态,您需要将这些状态转换成一组数字,以便与 Micrometer Gauge 配合使用。
下面的示例展示了编写此类导出器的一种方法:

import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;

import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.boot.actuate.health.Status;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyHealthMetricsExportConfiguration {

    public MyHealthMetricsExportConfiguration(MeterRegistry registry, HealthEndpoint healthEndpoint) {
        // This example presumes common tags (such as the app) are applied elsewhere
        Gauge.builder("health", healthEndpoint, this::getStatusCode).strongReference(true).register(registry);
    }

    private int getStatusCode(HealthEndpoint health) {
        Status status = health.health().getStatus();
        if (Status.UP.equals(status)) {
            return 3;
        }
        if (Status.OUT_OF_SERVICE.equals(status)) {
            return 2;
        }
        if (Status.DOWN.equals(status)) {
            return 1;
        }
        return 0;
    }

}

Security

本节讨论使用 Spring Boot 时的安全性问题,包括在 Spring Boot 中使用 Spring Security 时出现的问题。
有关 Spring Security 的更多信息,请参阅 Spring Security 项目页面

关闭 Spring Boot Security配置

如果在应用程序中定义了带有 SecurityFilterChain Bean 的 @Configuration,它就会关闭 Spring Boot 中默认的 Web 应用程序安全设置。

更改 UserDetailsService 并添加用户账户

如果您提供了 AuthenticationManagerAuthenticationProviderUserDetailsService 类型的 @Bean,则不会创建 InMemoryUserDetailsManager 的默认 @Bean。这意味着你可以使用 Spring Security 的全部功能集(如各种身份验证选项)。
添加用户账户的最简单方法是提供自己的 UserDetailsService Bean。

在代理服务器后运行时启用 HTTPS

对于任何应用程序来说,确保所有主要端点只能通过 HTTPS 访问都是一项重要任务。如果您使用 Tomcat 作为 servlet 容器,那么 Spring Boot 会在检测到某些环境设置时自动添加 Tomcat 自带的 RemoteIpValve,而且您应该能够依靠 HttpServletRequest 报告其是否安全(即使是在处理真正 SSL 终止的代理服务器的下游)。标准行为是由是否存在某些请求头(x-forwarded-forx-forwarded-proto)决定的,这些请求头的名称是常规的,因此它应该能与大多数前端代理服务器配合使用。您可以通过在 application.properties 中添加一些条目来切换值,如下例所示:

server:
  tomcat:
    remoteip:
      remote-ip-header: "x-forwarded-for"
      protocol-header: "x-forwarded-proto"

(其中任何一个属性的存在都会切换值)。或者,也可以通过使用 WebServerFactoryCustomizer Bean 自定义 TomcatServletWebServerFactory 来添加 RemoteIpValve)。
要将 Spring Security 配置为要求为所有(或部分)请求提供安全通道,可以考虑添加自己的 SecurityFilterChain Bean,其中添加以下 HttpSecurity 配置:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class MySecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // Customize the application security ...
        http.requiresChannel((channel) -> channel.anyRequest().requiresSecure());
        return http.build();
    }

}

热插拔

Spring Boot 支持热插拔。本节将回答有关其工作原理的问题。

重载静态内容

热重载有多种选择。推荐的方法是使用 spring-boot-devtools,因为它提供了额外的开发时间功能,如支持快速应用程序重启和 LiveReload,以及合理的开发时间配置(如模板缓存)。Devtools 通过监控类路径的变化来工作。这意味着必须 “构建” 静态资源更改才能使更改生效。默认情况下,这将在 Eclipse 中保存更改时自动发生。在 IntelliJ IDEA 中,Make Project 命令会触发必要的构建。由于默认的重启排除,对静态资源的更改不会触发应用程序的重启。不过,它们会触发实时重载。
另外,在集成开发环境中运行(尤其是在调试开启的情况下)也是一种很好的开发方式(所有现代集成开发环境都允许重载静态资源,通常还允许热插拔 Java 类更改)。
最后,可以对 Maven 和 Gradle 插件进行配置(参见 addResources 属性),以支持从命令行运行,并直接从源代码重载静态文件。如果使用更高级别的工具编写代码,可以将其与外部 css/js 编译器进程结合使用。

重载模板而无需重启容器

Spring Boot 支持的大多数模板技术都包含禁用缓存的配置选项(本文档稍后将介绍)。如果使用 spring-boot-devtools 模块,这些属性会在开发时自动为您配置

Thymeleaf Templates

如果使用 Thymeleaf,请将 spring.thymeleaf.cache 设置为 false。有关其他 Thymeleaf 自定义选项,请参见 ThymeleafAutoConfiguration

FreeMarker Templates

如果使用 FreeMarker,请将 spring.freemarker.cache 设置为 false。有关 FreeMarker 的其他自定义选项,请参见 FreeMarkerAutoConfiguration

Groovy Templates

如果使用 Groovy 模板,请将 spring.groovy.template.cache 设为 false。有关其他 Groovy 定制选项,请参阅 GroovyTemplateAutoConfiguration

快速重启应用程序

spring-boot-devtools 模块支持应用程序自动重启。虽然速度比不上 JRebel 等技术,但通常比 “冷启动” 快得多。在研究本文档稍后讨论的一些更复杂的重载选项之前,你或许应该先试一试。
更多详情,请参阅 using.html 部分。

无需重启容器即可重新加载 Java 类

许多现代集成开发环境(Eclipse、IDEA 等)都支持字节码的热插拔。因此,如果您所做的更改不影响类或方法签名,那么重新加载时应该不会产生任何副作用。

Testing

Spring Boot 包含大量测试实用程序和支持类,以及提供常用测试依赖项的专用启动器。本节将回答有关测试的常见问题。

使用 Spring Security 进行测试

Spring Security 支持以特定用户身份运行测试。例如,下面代码段中的测试将以拥有 ADMIN 角色的认证用户身份运行。

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.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;

@WebMvcTest(UserController.class)
class MySecurityTests {

    @Autowired
    private MockMvc mvc;

    @Test
    @WithMockUser(roles = "ADMIN")
    void requestProtectedUrlWithUser() throws Exception {
        this.mvc.perform(get("/"));
    }

}

Spring Security 提供了与 Spring MVC Test 的全面集成,在使用 @WebMvcTest 片和 MockMvc 测试控制器时也可使用。
有关 Spring Security 测试支持的更多详情,请参阅 Spring Security 参考文档

结构化 @Configuration,以便纳入切片测试

切片测试的工作原理是根据组件类型将 Spring Framework 的组件扫描限制在一组有限的组件上。对于任何未通过组件扫描创建的 Bean(例如,使用 @Bean 注解创建的 Bean),切片测试将无法从应用程序上下文中包含/排除它们。请看下面这个例子:

import org.apache.commons.dbcp2.BasicDataSource;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration(proxyBeanMethods = false)
public class MyConfiguration {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());
        return http.build();
    }

    @Bean
    @ConfigurationProperties("app.datasource.second")
    public BasicDataSource secondDataSource() {
        return DataSourceBuilder.create().type(BasicDataSource.class).build();
    }

}

对于使用上述 @Configuration 类的应用程序的 @WebMvcTest 来说,您可能希望在应用程序上下文中使用 SecurityFilterChain Bean,以便测试控制器端点是否安全。但是,@WebMvcTest 的组件扫描过滤器并没有选中 MyConfiguration,因为它与过滤器指定的任何类型都不匹配。您可以使用 @Import(MyConfiguration.class) 对测试类进行注解,从而显式地包含配置。这将加载 MyConfiguration 中的所有 Bean,包括在测试 Web 层时不需要的 BasicDataSource Bean。将配置类一分为二可以只导入安全配置。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration(proxyBeanMethods = false)
public class MySecurityConfiguration {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());
        return http.build();
    }

}
import org.apache.commons.dbcp2.BasicDataSource;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyDatasourceConfiguration {

    @Bean
    @ConfigurationProperties("app.datasource.second")
    public BasicDataSource secondDataSource() {
        return DataSourceBuilder.create().type(BasicDataSource.class).build();
    }

}

如果需要在切片测试中包含某个域的 Bean,那么使用单个配置类的效率可能会很低。相反,将应用程序的配置结构化为多个细粒度类,并包含特定域的 Bean,就可以只在特定切片测试中导入它们。

Build

Spring Boot 包含 Maven 和 Gradle 的构建插件。本节将回答有关这些插件的常见问题。

生成构建信息

Maven 插件和 Gradle 插件都允许生成包含项目坐标、名称和版本的构建信息。这些插件还可以通过配置添加其他属性。当存在此类文件时,Spring Boot 会自动配置一个 BuildProperties Bean。
要使用 Maven 生成构建信息,请为 build-info 目标添加执行,如下例所示:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>3.2.1</version>
            <executions>
                <execution>
                    <goals>
                        <goal>build-info</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

更多详情,请参阅 Spring Boot Maven Plugin 文档

下面的示例使用 Gradle 进行了同样的操作:

springBoot {
    buildInfo()
}

更多详情,请参阅 Spring Boot Gradle 插件文档

生成 Git 信息

Maven 和 Gradle 都允许生成 git.properties 文件,其中包含项目构建时 git 源代码仓库的状态信息。
对于 Maven 用户,spring-boot-starter-parent POM 包含一个预配置插件,用于生成 git.properties 文件。要使用该插件,请在 POM 中添加以下 Git Commit Id 插件声明:

<build>
    <plugins>
        <plugin>
            <groupId>io.github.git-commit-id</groupId>
            <artifactId>git-commit-id-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

Gradle 用户可以通过使用 gradle-git-properties 插件实现同样的效果,如下例所示:

plugins {
    id "com.gorylenko.gradle-git-properties" version "2.4.1"
}

Maven 和 Gradle 插件都允许配置 git.properties 中包含的属性。

git.properties 中的提交时间应符合以下格式:yyyy-MM-dd'T'HH:mm:ssZ。这是上述两个插件的默认格式。使用此格式可将时间解析为日期,并在序列化为 JSON 时由 Jackson 的日期序列化配置设置控制其格式。

自定义依赖版本

spring-boot-dependencies POM 管理常用依赖项的版本。Maven 和 Gradle 的 Spring Boot 插件允许使用构建属性自定义这些受管理的依赖版本。

每个 Spring Boot 版本都是根据这组特定的第三方依赖关系设计和测试的。覆盖版本可能会导致兼容性问题。

要在 Maven 中覆盖依赖版本,请参阅 Maven 插件文档的这一部分
要在 Gradle 中覆盖依赖版本,请参阅 Gradle 插件文档的这一部分

使用 Maven 创建可执行 JAR

spring-boot-maven-plugin 可用于创建可执行的 “fat” JAR。如果使用 spring-boot-starter-parent POM,则可以声明该插件,并按如下方式重新打包 JAR:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

如果不使用父 POM,仍可使用该插件。不过,您必须额外添加一个 <executions> 部分,如下所示:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>3.2.1</version>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

详细使用方法请参见插件文档

将 Spring Boot 应用程序作为依赖项

与 war 文件一样,Spring Boot 应用程序并不打算用作依赖项。如果您的应用程序包含希望与其他项目共享的类,建议的方法是将代码移到一个单独的模块中。这样,您的应用程序和其他项目都可以依赖该独立模块。
如果无法按照上述建议重新排列代码,则必须配置 Spring Boot 的 Maven 和 Gradle 插件,以生成适合用作依赖项的独立工件。由于可执行 jar 格式会将应用程序类打包到 BOOT-INF/classes 中,因此可执行存档不能用作依赖项。这意味着在将可执行 jar 作为依赖项使用时,无法找到这些类。
要生成两个工件(一个可作为依赖项,另一个可执行),必须指定一个分类器。该分类器将应用于可执行存档的名称,留下默认存档作为依赖项。
要在 Maven 中配置 exec 的分类器,可以使用以下配置:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <classifier>exec</classifier>
            </configuration>
        </plugin>
    </plugins>
</build>

在运行可执行 Jar 时提取特定库

可执行 jar 中的大多数嵌套库无需解压缩即可运行。不过,某些库可能会有问题。例如,JRuby 包含自己的嵌套 jar 支持,它假定 jruby-complete.jar 总是可以作为文件直接使用。
为了处理任何有问题的库,你可以标记特定的嵌套 jar 应在可执行 jar 首次运行时自动解压缩。这些嵌套的 jar 会被写入由 java.io.tmpdir 系统属性标识的临时目录下。

应注意确保操作系统的配置不会在应用程序仍在运行时删除已解压缩到临时目录中的 jar。

例如,若要指出 JRuby 应标记为使用 Maven 插件进行解包,可添加以下配置:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <requiresUnpack>
                    <dependency>
                        <groupId>org.jruby</groupId>
                        <artifactId>jruby-complete</artifactId>
                    </dependency>
                </requiresUnpack>
            </configuration>
        </plugin>
    </plugins>
</build>

创建带排除项的不可执行 JAR

通常情况下,如果将可执行 jar 和不可执行 jar 作为两个独立的构建产品,可执行版本会包含库 jar 中不需要的附加配置文件。例如,非可执行 JAR 中可能不包含 application.yaml 配置文件。
在 Maven 中,可执行 jar 必须是主要工件,您可以为库添加一个分类 jar,如下所示:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
        <plugin>
            <artifactId>maven-jar-plugin</artifactId>
            <executions>
                <execution>
                    <id>lib</id>
                    <phase>package</phase>
                    <goals>
                        <goal>jar</goal>
                    </goals>
                    <configuration>
                        <classifier>lib</classifier>
                        <excludes>
                            <exclude>application.yaml</exclude>
                        </excludes>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

使用 Maven 远程调试 Spring Boot 应用程序

要将远程调试器附加到使用 Maven 启动的 Spring Boot 应用程序,可以使用 maven 插件jvmArguments 属性。
更多详情,请参阅本示例

不使用 spring-boot-antlib 从 Ant 构建可执行归档文件

使用 Ant 构建时,需要抓取依赖项、编译,然后创建 jar 或 war 压缩包。要使其可执行,可以使用 spring-boot-antlib 模块,也可以按照以下说明操作:

  1. 如果要构建 jar,请将应用程序的类和资源打包到嵌套的 BOOT-INF/classes 目录中。如果要构建 war,则应像往常一样将应用程序的类打包到嵌套的 WEB-INF/classes 目录中。
  2. 如果是 jar,则在嵌套的 BOOT-INF/lib 目录中添加运行时依赖项;如果是 war,则在嵌套的 WEB-INF/lib 目录中添加运行时依赖项。切记不要压缩压缩包中的条目。
  3. 在 jar 的嵌套 BOOT-INF/lib 目录或 war 的 WEB-INF/lib-provided 目录中添加提供的(嵌入式容器)依赖项。切记不要压缩压缩包中的条目。
  4. 在压缩包根目录下添加 spring-boot-loader 类(以便主类可用)。
  5. 在清单中使用适当的启动器(如 jar 文件的 JarLauncher)作为主类属性,并将其所需的其他属性指定为清单条目,主要是通过设置 Start-Class 属性。

下面的示例展示了如何使用 Ant 构建可执行存档:

<target name="build" depends="compile">
    <jar destfile="target/${ant.project.name}-${spring-boot.version}.jar" compress="false">
        <mappedresources>
            <fileset dir="target/classes" />
            <globmapper from="*" to="BOOT-INF/classes/*"/>
        </mappedresources>
        <mappedresources>
            <fileset dir="src/main/resources" erroronmissingdir="false"/>
            <globmapper from="*" to="BOOT-INF/classes/*"/>
        </mappedresources>
        <mappedresources>
            <fileset dir="${lib.dir}/runtime" />
            <globmapper from="*" to="BOOT-INF/lib/*"/>
        </mappedresources>
        <zipfileset src="${lib.dir}/loader/spring-boot-loader-jar-${spring-boot.version}.jar" />
        <manifest>
            <attribute name="Main-Class" value="org.springframework.boot.loader.launch.JarLauncher" />
            <attribute name="Start-Class" value="${start-class}" />
        </manifest>
    </jar>
</target>

预处理

当人们使用 Spring Boot 应用程序的预处理功能时,经常会产生一些问题。本节将讨论这些问题。

条件

预处理可优化应用程序,并根据构建时的环境评估条件。预案是通过条件实现的,因此也会受到影响。
如果希望在预优化的应用程序中根据条件创建Bean,就必须在构建应用程序时设置环境。这样,在构建时进行预处理时创建的Bean就会在运行应用程序时始终创建,而且无法关闭。为此,您可以设置构建应用程序时应使用的配置文件。
对于 Maven,可以通过设置 spring-boot-maven-plugin:process-aot 执行的配置文件配置来实现:

<profile>
    <id>native</id>
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <executions>
                        <execution>
                            <id>process-aot</id>
                            <configuration>
                                <profiles>profile-a,profile-b</profiles>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</profile>

对于 Gradle,您需要配置 ProcessAot 任务:

tasks.withType(org.springframework.boot.gradle.tasks.aot.ProcessAot).configureEach {
    args('--spring.profiles.active=profile-a,profile-b')
}

在运行预优化的应用程序时,支持只更改不影响条件的配置属性的预案,不受任何限制。

传统部署

Spring Boot 支持传统部署和更现代的部署形式。本节将回答有关传统部署的常见问题。

创建可部署的 War 文件

由于 Spring WebFlux 并不严格依赖于 servlet API,而且应用程序默认部署在嵌入式 Reactor Netty 服务器上,因此 WebFlux 应用程序不支持 War 部署。

生成可部署 war 文件的第一步是提供 SpringBootServletInitializer 子类并覆盖其 configure 方法。这样做可以利用 Spring Framework 的 servlet 3.0 支持,让你在应用程序由 servlet 容器启动时对其进行配置。通常情况下,你应该更新应用程序的主类以扩展 SpringBootServletInitializer,如下例所示:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(MyApplication.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

}

下一步是更新构建配置,使项目生成 war 文件而不是 jar 文件。如果使用 Maven 和 spring-boot-starter-parent(可为你配置 Maven 的 war 插件),你只需修改 pom.xml,将打包方式改为 war,如下所示:

<packaging>war</packaging>

如果使用 Gradle,则需要修改 build.gradle,以便在项目中应用 war 插件,如下所示:

apply plugin: 'war'

流程的最后一步是确保嵌入式 servlet 容器不会干扰 war 文件所部署的 servlet 容器。为此,您需要将嵌入式 servlet 容器的依赖关系标记为已提供。
如果使用 Maven,下面的示例会将 servlet 容器(本例中为 Tomcat)标记为已提供:

<dependencies>
    <!-- ... -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>
    <!-- ... -->
</dependencies>

如果使用 Gradle,下面的示例会标记已提供 servlet 容器(本例中为 Tomcat):

dependencies {
    // ...
    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
    // ...
}

providedRuntime 比 Gradle 的compileOnly配置更受欢迎。除其他限制外,compileOnly依赖项不在测试类路径上,因此任何基于网络的集成测试都会失败。

如果使用 Spring Boot 构建工具,将嵌入式 servlet 容器依赖关系标记为已提供,就会生成一个可执行 war 文件,其中包含打包在 lib-provided 目录中的已提供依赖关系。这意味着,除了可以部署到 servlet 容器外,还可以在命令行上使用 java -jar 运行应用程序。

将现有应用程序转换为 Spring Boot

要将现有的非 Web Spring 应用程序转换为 Spring Boot 应用程序,请替换创建 ApplicationContext 的代码,代之以对 SpringApplicationSpringApplicationBuilder 的调用。Spring MVC Web 应用程序通常可以先创建一个可部署的 war 应用程序,然后将其迁移到可执行的 war 或 jar 中。请参阅《将 jar 转换为 war 入门指南》
要通过扩展 SpringBootServletInitializer(例如,在名为 Application 的类中)并添加 Spring Boot @SpringBootApplication 注解来创建可部署 war,请使用与下面示例中类似的代码:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        // Customize the application or call application.sources(...) to add sources
        // Since our example is itself a @Configuration class (through
        // @SpringBootApplication)
        // we actually do not need to override this method.
        return application;
    }


}

请记住,无论你在源代码中放入什么,都只是一个 Spring ApplicationContext。通常情况下,任何已经运行的东西都可以在这里运行。也许有些 Bean 你可以稍后移除,让 Spring Boot 为它们提供自己的默认值,但在你需要这样做之前,应该可以让一些东西正常工作。
静态资源可以移动到 classpath 根目录下的 /public(或 /static/resources/META-INF/resources)。这同样适用于 messages.properties(Spring Boot 会自动检测类路径根目录中的 messages.properties)。
Vanilla 使用 Spring DispatcherServlet 和 Spring Security 时应无需做进一步更改。如果您的应用程序有其他功能(例如,使用其他 servlet 或过滤器),您可能需要在 Application context 中添加一些配置,方法是替换 web.xml 中的这些元素,如下所示:

  • ServletServletRegistrationBean 类型的 @Bean 将在容器中安装该 Bean,就像在 web.xml 中安装 <servlet/><servlet-mapping/> 一样。
  • FilterFilterRegistrationBean 类型的 @Bean 也有类似的行为(如同 <filter/><filter-mapping/>)。
  • XML 文件中的 ApplicationContext 可通过应用程序中的 @ImportResource 添加。另外,在注解配置已被大量使用的情况下,只需几行 @Bean 定义即可重新创建注解配置。

war 文件运行后,您可以在Application中添加一个 main 方法,使其可执行,如下例所示:

public static void main(String[] args) {
    SpringApplication.run(MyApplication.class, args);
}

如果打算以 war 或可执行应用程序的形式启动应用程序,则需要在 SpringBootServletInitializer 回调方法和类似以下类的主方法中共享构建器的自定义设置:

import org.springframework.boot.Banner;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return customizerBuilder(builder);
    }

    public static void main(String[] args) {
        customizerBuilder(new SpringApplicationBuilder()).run(args);
    }

    private static SpringApplicationBuilder customizerBuilder(SpringApplicationBuilder builder) {
        return builder.sources(MyApplication.class).bannerMode(Banner.Mode.OFF);
    }

}

应用程序可分为多个类别:

  • 没有 web.xml 的 Servlet 3.0+ 应用程序。
  • web.xml 的应用程序。
  • 有上下文层次结构的应用程序。
  • 无上下文层次结构的应用程序。

所有这些都可以进行翻译,但每种翻译所需的技术可能略有不同。
Servlet 3.0+ 应用程序如果已经使用了 Spring Servlet 3.0+ 初始化器支持类,那么翻译起来可能会非常容易。通常,现有 WebApplicationInitializer 中的所有代码都可以移入 SpringBootServletInitializer 中。如果你的现有应用程序有不止一个 ApplicationContext(例如,如果它使用了 AbstractDispatcherServletInitializer),那么你也许可以将所有上下文源合并到一个 SpringApplication 中。您可能会遇到的主要复杂情况是,如果合并不起作用,您需要维护上下文层次结构。有关示例,请参阅 “构建层次结构” 条目。包含 Web 特定功能的现有父上下文通常需要拆分,以便将所有 ServletContextAware 组件都放在子上下文中。
还不是 Spring 应用程序的应用程序可能会转换为 Spring Boot 应用程序,前面提到的指导可能会有所帮助。不过,您可能还会遇到问题。在这种情况下,我们建议在 Stack Overflow 上以 spring-boot 为标签提问

将 WAR 部署到 WebLogic

要将 Spring Boot 应用程序部署到 WebLogic,必须确保您的 servlet 初始化程序直接实现了 WebApplicationInitializer(即使您是从已经实现了 WebApplicationInitializer 的基类扩展而来)。
WebLogic 的典型初始化器应类似于下面的示例:

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.web.WebApplicationInitializer;

@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer implements WebApplicationInitializer {

}

如果使用 Logback,还需要告诉 WebLogic 优先使用打包版本,而不是服务器预装的版本。方法是添加一个 WEB-INF/weblogic.xml 文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<wls:weblogic-web-app
    xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-web-app"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
        https://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd
        http://xmlns.oracle.com/weblogic/weblogic-web-app
        https://xmlns.oracle.com/weblogic/weblogic-web-app/1.4/weblogic-web-app.xsd">
    <wls:container-descriptor>
        <wls:prefer-application-packages>
            <wls:package-name>org.slf4j</wls:package-name>
        </wls:prefer-application-packages>
    </wls:container-descriptor>
</wls:weblogic-web-app>

Docker Compose

本节包括与 Spring Boot 中的 Docker Compose 支持相关的主题。

自定义 JDBC URL

在 Docker Compose 中使用 JdbcConnectionDetails 时,可通过在服务中应用 org.springframework.boot.jdbc.parameters 标签来定制 JDBC URL 的参数。例如:

services:
  postgres:
    image: 'postgres:15.3'
    environment:
      - 'POSTGRES_USER=myuser'
      - 'POSTGRES_PASSWORD=secret'
      - 'POSTGRES_DB=mydb'
    ports:
      - '5432:5432'
    labels:
      org.springframework.boot.jdbc.parameters: 'ssl=true&sslmode=require'

有了这个 Docker Compose 文件,使用的 JDBC URL 就是 jdbc:postgresql://127.0.0.1:5432/mydb?ssl=true&sslmode=require.

在多个应用程序之间共享服务

如果你想在多个应用程序之间共享服务,可以在其中一个应用程序中创建 compose.yaml 文件,然后在其他应用程序中使用配置属性 spring.docker.compose.file 引用 compose.yaml 文件。你还应将 spring.docker.compose.lifecycle-management 设置为start-only,因为它默认为start-and-stop,停止一个应用程序也会关闭其他仍在运行的应用程序的共享服务。将其设置为仅启动不会在应用程序停止时停止共享服务,但需要注意的是,如果关闭所有应用程序,服务将继续运行。你可以在包含 compose.yaml 文件的目录下,通过命令行运行 docker compose stop 来手动停止服务。

原文地址:https://blog.csdn.net/qq_41939901/article/details/135526937

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若转载,请注明出处:http://www.7code.cn/show_56106.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注