本节提供了一些在使用Spring Boot时经常出现的常见 ‘how do I do that…​’ 问题的答案. 它的覆盖范围不是很详尽,但是确实覆盖了很多.

如果您有一个我们不在此讨论的特定问题,则可能需要查看 stackoverflow.com 以查看是否有人已经提供了答案. 这也是询问新问题的好地方 (请使用 spring-boot 标签) .

我们也很乐意扩展此部分. 如果您想添加 "操作方法",请向我们发送 pull request.

1. Spring Boot 应用程序

本部分包括与Spring Boot应用程序直接相关的主题.

1.1. 创建自己的FailureAnalyzer

FailureAnalyzer 这是拦截启动时将异常转化为人类可读消息 (包装在) 的一种好方法 FailureAnalysis. Spring Boot为与应用程序上下文相关的异常,JSR-303验证等提供了此类分析器. 您也可以创建自己的. .

AbstractFailureAnalyzer 是一个方便的扩展,FailureAnalyzer 它检查要处理的异常中是否存在指定的异常类型. 您可以对此进行扩展,以便您的实现只有在异常出现时才有机会处理该异常. 如果由于某种原因无法处理该异常,请返回 null 以使另一个实现有机会处理该异常.

FailureAnalyzer 实现必须在 META-INF/spring.factories 中注册. 以下示例注册 ProjectConstraintViolationFailureAnalyzer:

org.springframework.boot.diagnostics.FailureAnalyzer=\
com.example.ProjectConstraintViolationFailureAnalyzer
如果您需要访问 BeanFactoryEnvironment,则 FailureAnalyzer 可以分别实现 BeanFactoryAwareEnvironmentAware.

1.2. 自动配置故障排除

Spring Boot自动配置会尽力 "做正确的事",但有时会失败,并且很难说出原因.

ConditionEvaluationReport 任何Spring Boot 都有一个非常有用的功能 ApplicationContext. 如果启用 DEBUG 日志记录输出,则可以看到它. 如果使用 spring-boot-actuator (请参阅 Actuator 一章) , 那么还有一个 conditions 端点,该端点以JSON形式呈现报告. 使用该端点来调试应用程序,并在运行时查看Spring Boot添加了哪些功能 (尚未添加) .

通过查看源代码和 Javadoc,可以回答更多问题. 阅读代码时,请记住以下经验法则:

  • 查找被调用的类 AutoConfiguration 并阅读其源代码. 特别注意 @Conditional 注解,以了解它们启用了哪些功能以及何时启用. 添加 --debug 到命令行或系统属性 -Ddebug 以在控制台上获取在您的应用中做出的所有自动配置决策的日志. 在启用了 Actuator 的运行应用程序中,查看 conditions 端点 (/actuator/conditions 或等效的JMX) 以获取相同信息.

  • 查找属于 @ConfigurationProperties (例如 ServerProperties) 的类,然后从中读取可用的外部配置选项. 该 @ConfigurationProperties 注解具有一个 name 充当前缀外部性能属性. 因此,ServerProperties 拥有 prefix="server" 和它的配置性能 server.port,server.address 以及其他. 在启用了 Actuator 的运行应用程序中,查看 configprops 端点.

  • 寻找对bind方法的使用,以一种轻松的方式 Binder 将配置值明确地拉出 Environment. 它通常与前缀一起使用.

  • 查找 @Value 直接绑定到的注解 Environment.

  • 寻找 @ConditionalOnExpression 注解以响应SpEL表达式来打开或关闭功能,这些注解通常使用从中解析的占位符进行评估 Environment.

1.3. 启动之前自定义环境或ApplicationContext

一个 SpringApplication 具有 ApplicationListenersApplicationContextInitializers 被用于应用自定义的背景或环境. Spring Boot加载了许多此类自定义项,以供内部使用 META-INF/spring.factories . 注册其他自定义项的方法有多种:

  • 在运行之前,通过对每个应用程序进行编程,方法是调用 addListenersaddInitializers 方法 SpringApplication.

  • 通过设置 context.initializer.classescontext.listener.classes 属性,以声明方式针对每个应用程序.

  • 声明性地,对于所有应用程序,通过添加 META-INF/spring.factories 和打包一个jar文件,这些文件都被应用程序用作库.

SpringApplication 发送一些特殊 ApplicationEvents 的听众 (背景下创造了一些甚至更早) ,然后注册了在公布的事件监听器 ApplicationContext 为好. 有关完整列表,请参见 ‘Spring Boot 特性’ 部分中的 “应用程序事件和监听器” .

还可以使用来自定义 Environment 刷新应用程序上下文之前的 EnvironmentPostProcessor. 每个实现都应在中注册 META-INF/spring.factories,如以下示例所示:

org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor

该实现可以加载任意文件并将其添加到中 Environment. 例如,以下示例从类路径加载YAML配置文件:

public class EnvironmentPostProcessorExample implements EnvironmentPostProcessor {

    private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        Resource path = new ClassPathResource("com/example/myapp/config.yml");
        PropertySource<?> propertySource = loadYaml(path);
        environment.getPropertySources().addLast(propertySource);
    }

    private PropertySource<?> loadYaml(Resource path) {
        if (!path.exists()) {
            throw new IllegalArgumentException("Resource " + path + " does not exist");
        }
        try {
            return this.loader.load("custom-resource", path).get(0);
        }
        catch (IOException ex) {
            throw new IllegalStateException("Failed to load yaml configuration from " + path, ex);
        }
    }

}
Environment 已经准备与所有常见的财产来源春天引导加载默认. 因此可以从环境中获取文件的位置. 前面的示例将 custom-resource 属性源添加到列表的末尾,以便在其他任何常见位置定义的键具有优先权. 定制实现可以定义另一个顺序.
在使用@PropertySource你的 @SpringBootApplication 似乎是加载在一个自定义资源的便利方式 Environment,我们不建议这样做. Environment在刷新应用程序上下文之前,不会将此类属性源添加到中. 现在配置某些属性 (如 logging.spring.main. 在刷新开始之前先读取) 为时已晚.

1.4. 建立ApplicationContext层次结构 (添加父上下文或根上下文)

您可以使用 ApplicationBuilder 该类创建父/子 ApplicationContext 层次结构. 有关更多信息,请参见 ‘Spring Boot 特性’ 部分中的 “spring-boot-features.html” .

1.5. 创建一个非Web应用程序

并非所有的Spring应用程序都必须是Web应用程序 (或Web服务) . 如果要在 main 方法中执行一些代码,又要引导Spring应用程序以设置要使用的基础结构,则可以使用 SpringApplication Spring Boot 的功能. 根据是否认为需要Web应用程序来 SpringApplication 更改其 ApplicationContext 类. 您可以做的第一件事是让服务器相关的依赖 (例如Servlet API) 脱离类路径. 如果你不能做到这一点 (例如,您从相同的代码库的两个应用程序) ,那么你可以显式调用 setWebApplicationType(WebApplicationType.NONE) 您的 SpringApplication 实例或设置 applicationContextClass 属性 (通过Java API或与外部属性) . 您可以将要作为业务逻辑运行的应用程序代码实现为 CommandLineRunner 并作为 @Bean 定义放到上下文中.

2. 属性和配置

本部分包括有关设置和读取属性,配置设置以及它们与Spring Boot应用程序的交互的主题.

2.1. 在构建时自动扩展属性

您可以使用现有的构建配置自动扩展它们,而不是对项目的构建配置中也指定的某些属性进行硬编码. 在Maven和Gradle中都是可能的.

2.1.1. 使用Maven自动扩展属性

您可以使用资源过滤从Maven项目自动扩展属性. 如果使用 spring-boot-starter-parent,则可以使用 @..@ 占位符引用Maven的 ‘project properties’,如以下示例所示:

app.encoding=@project.build.sourceEncoding@
app.java.version=@java.version@
这样只会过滤生产配置 (也就是说,不会对进行过滤 src/test/resources) .
如果启用该 addResources 标志,则 spring-boot:run 目标可以 src/main/resources 直接添加到类路径中 (用于热重载) . 这样做避免了资源过滤和此功能. 相反,您可以使用 exec:java 目标或自定义插件的配置. 有关更多详细信息,请参见 插件使用页面 .

如果您不使用入门级父级,则需要在 <build/> 元素中包括以下元素 pom.xml:

<resources>
    <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
    </resource>
</resources>

您还需要在其中包含以下元素 <plugins/>:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-resources-plugin</artifactId>
    <configuration>
        <delimiters>
            <delimiter>@</delimiter>
        </delimiters>
        <useDefaultDelimiters>false</useDefaultDelimiters>
    </configuration>
</plugin>
useDefaultDelimiters 如果在配置中使用标准的 Spring 占位符 (例如 ${placeholder}) ,则 该属性很重要. 如果该属性未设置为 false,则可以通过构建扩展它们.

2.1.2. 使用 Gradle 自动扩展属性

您可以通过配置 Java 插件的 processResources 任务来自动扩展 Gradle 项目中的属性,如以下示例所示:

processResources {
    expand(project.properties)
}

然后,您可以使用占位符来引用 Gradle 项目的属性,如以下示例所示:

app.name=${name}
app.description=${description}
Gradle的 expand 方法使用 Groovy 的方法 SimpleTemplateEngine 来转换 ${..} 令牌. 该 ${..} 风格的冲突与 Spring 自己的财产占位符机制. 要将 Spring 属性占位符与自动扩展一起使用,请按以下步骤对 Spring 属性占位符进行转义: \${..}.

2.2. 外部化配置 SpringApplication

SpringApplication 具有bean属性 (主要是setter) ,因此在创建应用程序时可以使用其Java API修改其行为. 或者,您可以通过在中设置属性来外部化配置 spring.main.*. 例如,在中 application.properties,您可能具有以下设置:

spring.main.web-application-type=none
spring.main.banner-mode=off

然后,启动时不会打印Spring Boot标语,并且应用程序也没有启动嵌入式Web服务器.

外部配置中定义的属性会覆盖用Java API指定的值,但用于创建的源的显着例外除外 ApplicationContext. 考虑以下应用程序:

new SpringApplicationBuilder()
    .bannerMode(Banner.Mode.OFF)
    .sources(demo.MyApp.class)
    .run(args);

现在考虑以下配置:

spring.main.sources=com.acme.Config,com.acme.ExtraConfig
spring.main.banner-mode=console

实际应用中,现在示出的旗帜 (如通过配置覆盖) ,并使用了三个源 ApplicationContext (按以下顺序) : demo.MyApp,com.acme.Configcom.acme.ExtraConfig.

2.3. 更改应用程序外部属性的位置

默认情况下,来自不同来源的属性 Environment 将以定义的顺序添加到Spring 中 (有关确切顺序,请参见 ‘Spring Boot 特性’ 部分中的 spring-boot-features.html) .

您还可以提供以下系统属性 (或环境变量) 来更改行为:

  • spring.config.name (spring.config.name[format=envvar]): 默认为 application 作为文件名的根.

  • spring.config.location (spring.config.location[format=envvar]): 要加载的文件 (例如类路径资源或URL) . Environment 为此文档设置了单独的属性源,可以通过系统属性,环境变量或命令行来覆盖它.

无论您在环境中进行什么设置,Spring Boot都将始终 application.properties 如上所述进行加载. 默认情况下,如果使用 YAML,则扩展名为 '.yml' 的文件也将添加到列表中.

Spring Boot记录在该 DEBUG 级别加载的配置文件以及在该级别找不到的候选文件 TRACE.

请参阅 ConfigFileApplicationListener 以获取更多详细信息.

2.4. 使用 ‘Short’ 命令行参数

有些人喜欢使用 (例如) --port=9000 而不是 --server.port=9000 在命令行上设置配置属性. 您可以通过在中使用占位符来启用此行为 application.properties ,如以下示例所示:

server.port=${port:8080}
如果您从 spring-boot-starter-parent POM 继承,则将的默认过滤器令牌 maven-resources-plugins 从更改 ${*}@ (即,@maven.token@ 而不是 ${maven.token}) , 以防止与Spring样式的占位符冲突. 如果 application.properties 直接启用了Maven过滤,则可能还需要更改默认过滤器令牌以使用其他定界符.
在这种特定情况下,端口绑定可在PaaS环境 (例如Heroku或Cloud Foundry) 中工作. 在这两个平台中,PORT 环境变量是自动设置的,Spring可以绑定到大写的 Environment 属性同义词.

2.5. 对外部属性使用YAML

YAML是JSON的超集,因此是一种方便的语法,用于以分层格式存储外部属性,如以下示例所示:

spring:
    application:
        name: cruncher
    datasource:
        driverClassName: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost/test
server:
    port: 9000

创建一个名为的文件 application.yml,并将其放在类路径的根目录中. 然后添加 snakeyaml 到您的依赖 (Maven坐标 org.yaml:snakeyaml,如果使用,则已经包含在内 spring-boot-starter) . 将YAML文件解析为Java Map<String,Object> (如JSON对象) ,然后Spring Boot展宽地图,使其深一层,并具有句点分隔的键,这是许多人习惯使用Java 中的 Properties 文件的原因.

前面的示例YAML对应于以下 application.properties 文件:

spring.application.name=cruncher
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost/test
server.port=9000

有关YAML的更多信息,请参见 “Spring Boot 特性” 部分中的 “spring-boot-features.html” .

2.6. 设置 Active Spring Profiles

Spring Environment 为此提供了一个API,但是您通常会设置一个 System 属性 (spring.profiles.active) 或OS环境变量 (SPRING_PROFILES_ACTIVE) . 另外,您可以使用 -D 参数启动应用程序 (请记住将其放在主类或jar存档之前) ,如下所示:

$ java -jar -Dspring.profiles.active=production demo-0.0.1-SNAPSHOT.jar

在Spring Boot中,您还可以在中设置 Active 配置文件 application.properties,如以下示例所示:

spring.profiles.active=production

以这种方式设置的值将由系统属性或环境变量设置代替,而不由 SpringApplicationBuilder.profiles() 方法替代. 因此,后一种Java API可用于扩充配置文件,而无需更改默认值.

有关更多信息,请参见 “Spring Boot 特性” 部分中的 “spring-boot-features.html” .

2.7. 根据环境更改配置

YAML文件实际上是由 --- 行分隔的文档序列,每个文档都分别解析为展平图.

如果YAML文档包含 spring.profiles 配置,则将配置文件值 (以逗号分隔的配置文件列表) 输入到Spring ·Environment.acceptsProfiles()· 方法中. 如果这些配置文件中的任何一个处于 active 状态,那么该文档将包含在最终合并中 (否则,它不会包含在此文档中) ,如以下示例所示:

server:
    port: 9000
---

spring:
    profiles: development
server:
    port: 9001

---

spring:
    profiles: production
server:
    port: 0

在前面的示例中,默认端口为 9000. 但是,如果名为 ‘development’ 的Spring概要文件处于 active 状态,则端口为9001. 如果 ‘production’ 为 active 状态,则该端口为 0.

YAML文档按照它们遇到的顺序进行合并. 以后的值将覆盖以前的值.

要对属性文件执行相同的操作,可以使用 application-${profile}.properties 指定特定于配置文件的值.

2.8. 发现外部属性的内置选项

Spring Boot 在运行时将外部属性 application.properties (或 .yml 文件和其他位置) 绑定到应用程序中. 在一个位置上没有 (而且从技术上来说不是) 所有受支持属性的详尽列表,因为贡献可能来自类路径上的其他jar文件.

具有Actuator功能的正在运行的应用程序具有一个 configprops 端点,该端点显示了可通过访问的所有绑定和可绑定属性 @ConfigurationProperties .

附录中包含一个 application.properties 示例,其中列出了Spring Boot支持的最常见属性. 最终列表来自搜索源代码中的 @ConfigurationProperties@Value 注解,以及偶尔使用 Binder. 有关加载属性的确切顺序的更多信息,请参见 "spring-boot-features.html".

3. 嵌入式 Web 服务器

每个Spring Boot Web应用程序都包含一个嵌入式Web服务器. 此功能导致许多方法问题,包括如何更改嵌入式服务器以及如何配置嵌入式服务器. 本节回答这些问题.

3.1. 使用其他 Web 服务器

许多 Spring Boot starter 都包含默认的嵌入式容器.

  • 对于 servlet 技术栈应用程序,通过 spring-boot-starter-web 包括来包括 Tomcat spring-boot-starter-tomcat,但是您可以使用 spring-boot-starter-jettyspring-boot-starter-undertow 代替.

  • 对于 reactive 技术栈的应用,spring-boot-starter-webflux 包括反应堆的Netty通过包括 spring-boot-starter-reactor-netty,但你可以使用 spring-boot-starter-tomcat,spring-boot-starter-jettyspring-boot-starter-undertow 代替.

切换到其他 HTTP 服务器时,除了包括所需的依赖之外,还需要排除默认的依赖. Spring Boot 为 HTTP 服务器提供了单独的启动器,以帮助简化此过程.

以下 Maven 示例显示了如何排除 Tomcat 并包括 Spring MVC 的 Jetty:

<properties>
    <servlet-api.version>3.1.0</servlet-api.version>
</properties>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <!-- Exclude the Tomcat dependency -->
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!-- Use Jetty instead -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
Servlet API 的版本已被覆盖,因为与 Tomcat 9 和 Undertow 2.0 不同,Jetty 9.4 不支持 Servlet 4.0.

以下 Gradle 示例显示了如何使用 Undertow 代替 Spring WebFlux 的 Reactor Netty:

configurations.all {
    resolutionStrategy.dependencySubstitution.all { dependency ->
        if (dependency.requested instanceof ModuleComponentSelector && dependency.requested.module == 'spring-boot-starter-reactor-netty') {
            dependency.useTarget("org.springframework.boot:spring-boot-starter-undertow:$dependency.requested.version", 'Use Undertow instead of Reactor Netty')
        }
    }
}

dependencies {
    compile 'org.springframework.boot:spring-boot-starter-webflux'
    // ...
}
spring-boot-starter-reactor-netty 使用 WebClient 该类是必需的,因此即使您需要包括其他HTTP服务器,也可能需要保持对Netty的依赖.

3.2. 禁用Web服务器

如果您的类路径包含启动Web服务器所需的位,则Spring Boot将自动启动它. 要禁用此行为,请 WebApplicationType 在中配置 application.properties,如以下示例所示:

spring.main.web-application-type=none

3.3. 更改HTTP端口

在独立应用程序中,主HTTP端口默认为,8080但可以使用 server.port (例如,在 application.properties System属性中或作为System属性) 进行设置. 由于轻松地绑定了 Environment 值,因此还可以使用 SERVER_PORT (例如,作为OS环境变量) .

要完全关闭HTTP端点,但仍创建一个 WebApplicationContext,请使用 server.port=-1 (这样做有时对测试很有用) .

有关更多详细信息,请参阅 ‘Spring Boot 特性’ 部分中的 “spring-boot-features.html” 或 ServerProperties 源代码.

3.4. 使用随机未分配的HTTP端口

要扫描可用端口 (使用OS本机来防止冲突) ,请使用 server.port=0.

3.5. 在运行时发现HTTP端口

您可以从日志输出或 WebServerApplicationContext 通过其端口访问服务器正在运行的端口 WebServer. 最好的方法是确保它已初始化,是添加一个 @Bean 类型 ApplicationListener<WebServerApplicationContext>, 然后在发布事件时将其从事件中拉出.

使用的测试 @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT) 还可以通过使用 @LocalServerPort 注解将实际端口注入字段中,如以下示例所示:

@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
public class MyWebIntegrationTests {

    @LocalServerPort
    int port;

    // ...

}

@LocalServerPort 是的元注解 @Value("${local.server.port}"). 不要尝试在常规应用程序中注入端口. 如我们所见,仅在初始化容器之后才设置该值. 与测试相反,应早处理应用程序代码回调 (在值实际可用之前) .

3.6. 启用 HTTP 响应压缩

Jetty,Tomcat 和 Undertow 支持 HTTP 响应压缩. 可以在中启用它 application.properties,如下所示:

server.compression.enabled=true

默认情况下,响应的长度必须至少为 2048 个字节才能执行压缩. 您可以通过设置 server.compression.min-response-size 属性来配置此行为.

默认情况下,仅当响应的内容类型为以下之一时,它们才被压缩:

  • text/html

  • text/xml

  • text/plain

  • text/css

  • text/javascript

  • application/javascript

  • application/json

  • application/xml

您可以通过设置 server.compression.mime-types 属性来配置此行为.

3.7. 配置 SSL

可以通过设置各种 server.ssl.* 属性来声明性地配置 SSL ,通常在 application.properties 或中 application.yml. 以下示例显示了在中设置 SSL 属性 application.properties:

server.port=8443
server.ssl.key-store=classpath:keystore.jks
server.ssl.key-store-password=secret
server.ssl.key-password=another-secret

有关 Ssl 所有受支持属性的详细信息,请参见.

使用上述示例的配置意味着应用程序不再在端口 8080 上支持纯 HTTP 连接器. SpringBoot 不支持通过进行 HTTP 连接器和HTTPS 连接器的配置 application.properties. 如果要同时拥有两者,则需要以编程方式配置其中之一. 我们建议您使用 application.properties HTTPS进行配置,因为HTTP连接器是两者中以编程方式进行配置的较容易方式.

3.8. 配置 HTTP/2

您可以使用 server.http2.enabled 配置属性在Spring Boot应用程序中启用HTTP/2支持. 该支持取决于所选的Web服务器和应用程序环境,因为JDK8不立即支持该协议.

Spring Boot不支持 h2c HTTP/2协议的明文版本. 因此,在接下来的部分中,您必须先配置SSL. 如果仍然选择使用 h2c,则可以查看 部分

3.8.1. Tomcat HTTP/2

默认情况下,Spring Boot随Tomcat 9.0.x一起提供,当使用JDK 9或更高版本时,Tomcat 9.0.x支持HTTP / 2. 另外,如果 libtcnative 库及其依赖已安装在主机操作系统上,则可以在JDK 8上使用 HTTP/2 .

如果没有,则必须使库文件夹可用于JVM库路径. 您可以使用JVM参数 (例如) 来执行此操作 -Djava.library.path=/usr/local/opt/tomcat-native/lib. 有关更多信息,请参见 Tomcat官方文档.

在没有该本机支持的情况下,在JDK 8上启动Tomcat 9.0.x会记录以下错误:

ERROR 8787 --- [           main] o.a.coyote.http11.Http11NioProtocol      : The upgrade handler [org.apache.coyote.http2.Http2Protocol] for [h2] only supports upgrade via ALPN but has been configured for the ["https-jsse-nio-8443"] connector that does not support ALPN.

此错误不是致命错误,并且该应用程序仍以 HTTP/1.1 SSL 支持开头.

3.8.2. Jetty HTTP/2

从 Jetty 9.4.8 开始, Conscrypt library 库还支持 HTTP/2 . 要启用该支持,您的应用程序需要具有两个附加依赖: org.eclipse.jetty:jetty-alpn-conscrypt-serverorg.eclipse.jetty.http2:http2-server.

3.8.3. Reactor Netty HTTP/2

spring-boot-webflux-starter 默认情况下,Reactor Netty作为服务器使用. 使用JDK 9或更高版本的JDK支持,可以将Reactor Netty配置为 HTTP/2. 对于JDK 8环境或最佳运行时性能,此服务器还支持带有本机库的HTTP/2. 为此,您的应用程序需要具有其他依赖.

Spring Boot管理 io.netty:netty-tcnative-boringssl-static "uber jar" 的版本,其中包含所有平台的本机库. 开发人员可以选择使用分类器仅导入所需的依赖 (请参阅 Netty官方文档) .

3.8.4. Undertow HTTP/2

从 Undertow 1.4.0+ 开始,在 JDK8 上没有任何其他要求就支持 HTTP/2.

3.8.5. 服务器支持 h2c

要启用 h2c, 您需要将 configprop:server.http2.enabled[] 属性设置为 false, 并且需要定制您所选择的服务器:

对于 Tomcat,我们需要添加升级协议:

@Bean
public TomcatConnectorCustomizer connectorCustomizer() {
    return (connector) -> connector.addUpgradeProtocol(new Http2Protocol());
}

对于 Jetty,我们需要向现有连接器添加连接工厂:

@Bean
public JettyServerCustomizer serverCustomizer() {
    return (server) -> {
        HttpConfiguration configuration = new HttpConfiguration();
        configuration.setSendServerVersion(false);
        Arrays.stream(server.getConnectors())
                .filter(connector -> connector instanceof ServerConnector)
                .map(ServerConnector.class::cast)
                .forEach(connector -> {
                    connector.addConnectionFactory(new HTTP2CServerConnectionFactory(configuration));
                });
    };
}

对于 Netty,我们需要添加 h2c 作为受支持的协议:

@Bean
public NettyServerCustomizer serverCustomizer() {
    return (server) -> server.protocol(HttpProtocol.H2C);
}

对于 Undertow, 您需要启用 HTTP2 选项:

@Bean
public UndertowBuilderCustomizer builderCustomizer() {
    return (builder) -> {
        builder.setServerOption(ENABLE_HTTP2, true);
    };
}

3.9. 配置 Web 服务器

通常,您首先应该考虑使用许多可用的配置键之一,并通过在您的 application.properties (或 application.yml,或环境等) 中添加新条目来自定义Web服务器. 请参阅发现外部属性的内置选项. 该server.命名空间是非常有用的在这里,它包括命名空间一样 server.tomcat.,server.jetty.* 和其他对服务器的特定功能. 请参阅 “appendix-application-properties.html ” 的列表.

前面的部分已经介绍了许多常见的用例,例如压缩,SSL或HTTP/2. 但是,如果您的用例不存在配置密钥,则应查看 WebServerFactoryCustomizer. 您可以声明一个这样的组件,并访问与您选择的服务器相关的工厂: 您应该为所选服务器 (Tomcat,Jetty,Reactor Netty,Undertow) 和所选Web堆栈 (Servlet或Reactive) 选择变体.

以下示例适用于带有 spring-boot-starter-web (Servlet 技术栈) 的Tomcat :

@Component
public class MyTomcatWebServerCustomizer
        implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {

    @Override
    public void customize(TomcatServletWebServerFactory factory) {
        // customize the factory here
    }
}

此外,Spring Boot 还提供:

Server Servlet stack Reactive stack

Tomcat

TomcatServletWebServerFactory

TomcatReactiveWebServerFactory

Jetty

JettyServletWebServerFactory

JettyReactiveWebServerFactory

Undertow

UndertowServletWebServerFactory

UndertowReactiveWebServerFactory

Reactor

N/A

NettyReactiveWebServerFactory

一旦访问了 WebServerFactory,就可以经常向其添加定制程序,以配置特定的部分,例如连接器,服务器资源或服务器本身-全部使用服务器特定的API.

最后,您还可以声明自己的 WebServerFactory 组件,该组件将覆盖Spring Boot提供的组件. 在这种情况下,您不能再依赖 server 命名空间中的配置属性.

3.10. 将 Servlet,Filter,Listener 添加到应用程序

在一个servlet栈的应用,即用 spring-boot-starter-web,有两种方法可以添加 Servlet,Filter,ServletContextListener,和由Servlet API到您的应用程序支持的其他听众:

3.10.1. 使用Spring Bean添加Servlet,过滤器或监听器

要使用Spring bean添加 Servlet,Filter 或 Servlet *Listener,必须为其提供 @Bean 定义. 当您要注入配置或依赖时,这样做非常有用. 但是,您必须非常小心,以免引起过多其他bean的急切初始化,因为必须在应用程序生命周期的早期就将它们安装在容器中. (例如,让它们依赖于您的 DataSource 或JPA配置不是一个好主意. ) 您可以通过在第一次使用bean时 (而不是在初始化时) 延迟初始化bean来解决这些限制.

对于过滤器和Servlet,还可以通过添加 FilterRegistrationBeanServletRegistrationBean 来代替基础组件或在基础组件之外添加映射和 init 参数.

如果在过滤器注册上未指定 dispatcherType,则使用 REQUEST. 这符合Servlet规范的默认调度程序类型.

像其他任何Spring bean一样,您可以定义Servlet过滤器bean的顺序. 请确保检查 “spring-boot-features.html” 部分.

禁用Servlet或过滤器的注册

如前所述,任何 ServletFilter Bean都会自动向Servlet容器注册. 要禁用特定 FilterServlet Bean的注册,请为其创建注册Bean并将其标记为已禁用,如以下示例所示:

@Bean
public FilterRegistrationBean registration(MyFilter filter) {
    FilterRegistrationBean registration = new FilterRegistrationBean(filter);
    registration.setEnabled(false);
    return registration;
}

3.10.2. 使用类路径扫描添加Servlet,过滤器和监听器

通过使用 @ServletComponentScan 注解 @Configuration 类并指定包含要注册的组件的软件包,可以将 @WebServlet, @WebFilter, 和 @WebListener 注解的类自动注册到嵌入式Servlet容器中. 默认情况下,@ServletComponentScan 从带注解的类的包中进行扫描.

3.11. 配置访问日志

可以通过它们各自的命名空间为Tomcat,Undertow和Jetty配置访问日志.

例如,以下设置使用 自定义模式记录对Tomcat的访问.

server.tomcat.basedir=my-tomcat
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%t %a "%r" %s (%D ms)
日志的默认位置是相对于Tomcat基本目录的日志目录. 默认情况下,logs 目录是一个临时目录,因此您可能需要修复Tomcat的基本目录或为日志使用绝对路径. 在前面的示例中,相对于应用程序的工作目录,日志位于 my-tomcat/logs 中.

可以用类似的方式配置Undertow的访问日志,如以下示例所示:

server.undertow.accesslog.enabled=true
server.undertow.accesslog.pattern=%t %a "%r" %s (%D ms)

日志存储在相对于应用程序工作目录的 logs 目录中. 您可以通过设置 server.undertow.accesslog.dir 属性来自定义此位置.

最后,Jetty的访问日志也可以配置如下:

server.jetty.accesslog.enabled=true
server.jetty.accesslog.filename=/var/log/jetty-access.log

默认情况下,日志被重定向到 System.err. 有关更多详细信息,请参见 Jetty 文档.

3.12. 在前端代理服务器后面运行

如果您的应用程序在代理,负载均衡器之后或在云中运行,则请求信息 (例如主机,端口,协议…​) 可能会随之变化. 例如,您的应用程序可能正在 "10.10.10.10:8080" 上运行,但是HTTP客户端应该只能看到 "example.org".

RFC7239 "Forwarded Headers" 定义了 "转发的" HTTP标头; 代理可以使用此标头提供有关原始请求的信息. 您可以将应用程序配置为读取这些标头,并在创建链接将其发送到HTTP 302响应,JSON文档或HTML页面中的客户端时自动使用该信息. 还有一些非标准的标头,例如 "X-Forwarded-Host","X-Forwarded-Port", "X-Forwarded-Proto","X-Forwarded-Ssl" 和 "X-Forwarded-Prefix".

如果代理添加了常用的 X-Forwarded-ForX-Forwarded-Proto 标头,则将 server.forward-headers-strategy 设置为 NATIVE 以支持这些标头. 使用此选项,Web服务器本身就需要支持此功能. 您可以查看他们的特定文档以了解特定行为.

如果这还不够,Spring框架会提供一个 ForwardedHeaderFilter. 您可以通过将 server.forward-headers-strategy 设置为 FRAMEWORK 来将其注册为 Servlet 过滤器.

如果您正在使用 Tomcat 并在代理处终止 SSL,则应将 configprop:server.tomcat.redirect-context-root[] 设置为 false. 这样可以在执行任何重定向之前信任 X-Forwarded-Proto 头.
如果您的应用程序在 Cloud Foundry 或 Heroku 中运行,则 server.forward-headers-strategy 属性默认为 NATIVE. 在所有其他情况下,它默认为 NONE.

3.12.1. 自定义Tomcat的代理配置

如果使用Tomcat,则可以另外配置用于携带 “forwarded” 信息的标头名称,如以下示例所示:

server.tomcat.remote-ip-header=x-your-remote-ip-header
server.tomcat.protocol-header=x-your-protocol-header

Tomcat还配置有一个默认正则表达式,该正则表达式与要信任的内部代理匹配. 默认情况下,信任 10/8, 192.168/16, 169.254/16127/8 中的IP地址. 您可以通过在 application.properties 中添加一个条目来自定义阀门的配置,如以下示例所示:

server.tomcat.internal-proxies=192\\.168\\.\\d{1,3}\\.\\d{1,3}
仅当使用属性文件进行配置时,才需要双反斜杠. 如果使用YAML,则单个反斜杠就足够了,与上一个示例中所示的值相等的值为 192\.168\.\d{1,3}\.\d{1,3}.
您可以通过将 internal-proxies 设置为空来信任所有代理 (但在生产环境中不要这样做) .

您可以通过关闭自动功能来完全控制 Tomcat的 RemoteIpValve 的配置 (为此,请设置 server.forward-headers-strategy=NONE) ,然后在 TomcatServletWebServerFactory bean中添加新的Valve实例.

3.13. 使用Tomcat启用多个连接器

您可以将 org.apache.catalina.connector.Connector 添加到 TomcatServletWebServerFactory,这可以允许多个连接器,包括HTTP和HTTPS连接器,如以下示例所示:

@Bean
public ServletWebServerFactory servletContainer() {
    TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
    tomcat.addAdditionalTomcatConnectors(createSslConnector());
    return tomcat;
}

private Connector createSslConnector() {
    Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
    Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
    try {
        File keystore = new ClassPathResource("keystore").getFile();
        File truststore = new ClassPathResource("keystore").getFile();
        connector.setScheme("https");
        connector.setSecure(true);
        connector.setPort(8443);
        protocol.setSSLEnabled(true);
        protocol.setKeystoreFile(keystore.getAbsolutePath());
        protocol.setKeystorePass("changeit");
        protocol.setTruststoreFile(truststore.getAbsolutePath());
        protocol.setTruststorePass("changeit");
        protocol.setKeyAlias("apitester");
        return connector;
    }
    catch (IOException ex) {
        throw new IllegalStateException("can't access keystore: [" + keystore
                + "] or truststore: [" + truststore + "]", ex);
    }
}

3.14. 使用Tomcat的LegacyCookieProcessor

默认情况下,Spring Boot使用的嵌入式Tomcat不支持Cookie格式的 "版本0",因此您可能会看到以下错误:

java.lang.IllegalArgumentException: An invalid character [32] was present in the Cookie value

如果有可能,您应该考虑将代码更新为仅存储符合以后Cookie规范的值. 但是,如果无法更改cookie的编写方式,则可以将Tomcat配置为使用 LegacyCookieProcessor. 要切换到 LegacyCookieProcessor,请使用添加了 TomcatContextCustomizerWebServerFactoryCustomizer bean,如以下示例所示:

@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> cookieProcessorCustomizer() {
    return (factory) -> factory
            .addContextCustomizers((context) -> context.setCookieProcessor(new LegacyCookieProcessor()));
}

3.15. 启用Tomcat的MBean注册表

默认情况下,嵌入式Tomcat的MBean注册表是禁用的. 这样可以最大程度地减少Tomcat的内存占用. 例如,如果要使用Tomcat的MBean,以便可以通过Micrometer暴露它们,则必须使用 server.tomcat.mbeanregistry.enabled 属性,如以下示例所示:

server.tomcat.mbeanregistry.enabled=true

3.16. 使用Undertow启用多个监听器

UndertowBuilderCustomizer 添加到 UndertowServletWebServerFactory 并将监听器添加到 Builder,如以下示例所示:

@Bean
public UndertowServletWebServerFactory servletWebServerFactory() {
    UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();
    factory.addBuilderCustomizers(new UndertowBuilderCustomizer() {

        @Override
        public void customize(Builder builder) {
            builder.addHttpListener(8080, "0.0.0.0");
        }

    });
    return factory;
}

3.17. 使用 @ServerEndpoint 创建WebSocket端点

如果要在使用嵌入式容器的Spring Boot应用程序中使用 @ServerEndpoint,则必须声明一个 ServerEndpointExporter @Bean,如以下示例所示:

@Bean
public ServerEndpointExporter serverEndpointExporter() {
    return new ServerEndpointExporter();
}

前面示例中显示的Bean将所有 @ServerEndpoint 注解的Bean注册到基础WebSocket容器. 当部署到独立的servlet容器时,此角色由servlet容器初始化程序执行,并且不需要 ServerEndpointExporter Bean.

4. Spring MVC

Spring Boot有许多启动器,其中包括Spring MVC. 请注意,一些入门者包括对Spring MVC的依赖,而不是直接包含它. 本部分回答有关Spring MVC和Spring Boot的常见问题.

4.1. 编写JSON REST服务

只要Jackson2在类路径上,Spring Boot应用程序中的任何Spring @RestController 默认情况下都应呈现JSON响应,如以下示例所示:

@RestController
public class MyController {

    @RequestMapping("/thing")
    public MyThing thing() {
            return new MyThing();
    }

}

只要Jackson 2可以对 MyThing 进行序列化 (对于普通的POJO或Groovy对象为true) ,则 localhost:8080/thing 默认情况下将以JSON表示. 请注意,在浏览器中,有时可能会看到XML响应,因为浏览器倾向于发送更喜欢XML的接受标头.

4.2. 编写XML REST服务

如果类路径上具有Jackson XML扩展名 (jackson-dataformat-xml) ,则可以使用它来呈现XML响应. 我们用于JSON的先前示例可以正常工作. 要使用Jackson XML渲染器,请将以下依赖添加到您的项目中:

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
</dependency>

如果Jackson的XML扩展名不可用而JAXB可用,则可以将XML呈现为附加要求,将 MyThing 注解为 @XmlRootElement,如以下示例所示:

@XmlRootElement
public class MyThing {
    private String name;
    // .. getters and setters
}

JAXB仅可与Java 8一起使用. 如果您使用的是较新的Java版本,请在项目中添加以下依赖:

<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
</dependency>
要使服务器呈现XML而不是JSON,您可能必须发送一个 Accept: text/xml 标头 (或使用浏览器) .

4.3. 自定义Jackson ObjectMapper

Spring MVC (客户端和服务器端) 使用 HttpMessageConverters 在HTTP交换中协商内容转换. 如果Jackson在类路径中,则您已经获得了 Jackson2ObjectMapperBuilder 提供的默认转换器,该转换器的实例已为您自动配置.

ObjectMapper (或用于Jackson XML转换器的 XmlMapper) 实例 (默认创建) 具有以下自定义属性:

  • MapperFeature.DEFAULT_VIEW_INCLUSION 被禁言

  • DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES 被禁言

  • SerializationFeature.WRITE_DATES_AS_TIMESTAMPS 被禁言

Spring Boot还具有一些功能,可以更轻松地自定义此行为.

您可以通过使用环境来配置 ObjectMapperXmlMapper 实例. Jackson 提供了一套广泛的简单的开/关功能,可用于配置其处理的各个方面. 在六个枚举 (在Jackson中) 中描述了这些功能,这些枚举映射到环境中的属性:

枚举 属性

com.fasterxml.jackson.databind.DeserializationFeature

spring.jackson.deserialization.<feature_name>

true, false

com.fasterxml.jackson.core.JsonGenerator.Feature

spring.jackson.generator.<feature_name>

true, false

com.fasterxml.jackson.databind.MapperFeature

spring.jackson.mapper.<feature_name>

true, false

com.fasterxml.jackson.core.JsonParser.Feature

spring.jackson.parser.<feature_name>

true, false

com.fasterxml.jackson.databind.SerializationFeature

spring.jackson.serialization.<feature_name>

true, false

com.fasterxml.jackson.annotation.JsonInclude.Include

spring.jackson.default-property-inclusion

always, non_null, non_absent, non_default, non_empty

例如,要启用漂亮打印,请设置 spring.jackson.serialization.indent_output = true. 请注意,由于使用了宽松绑定,因此 indent_output 的情况不必与相应的枚举常量 (即 INDENT_OUTPUT) 的情况匹配.

这种基于环境的配置将应用于自动配置的 Jackson2ObjectMapperBuilder Bean,并应用于使用该构建器创建的任何映射器,包括自动配置的 ObjectMapper Bean.

上下文的 Jackson2ObjectMapperBuilder 可以由一个或多个 Jackson2ObjectMapperBuilderCustomizer bean进行自定义. 可以对此类定制器bean进行排序 (Boot自己的定制器的顺序为0) ,从而可以在Boot定制之前和之后应用其他定制.

任何类型为 com.fasterxml.jackson.databind.Module 的bean都会自动注册到自动配置的 Jackson2ObjectMapperBuilder 中,并应用于它创建的任何 ObjectMapper 实例. 当您向应用程序添加新功能时,这提供了一种用于贡献自定义模块的全局机制.

如果要完全替换默认的 ObjectMapper,则可以定义该类型的 @Bean 并将其标记为 @Primary,或者,如果您更喜欢基于生成器的方法,则可以定义 Jackson2ObjectMapperBuilder @Bean. 请注意,无论哪种情况,这样做都会禁用 ObjectMapper 的所有自动配置.

如果您提供任何类型为 MappingJackson2HttpMessageConverter@Bean,它们将替换MVC配置中的默认值. 此外,还提供了 HttpMessageConverters 类型的便捷bean (如果使用默认的MVC配置,该bean始终可用) . 它提供了一些有用的方法来访问默认的和用户增强的消息转换器.

有关更多详细信息,请参见 “自定义@ResponseBody渲染” 部分和 WebMvcAutoConfiguration 源代码.

4.4. 自定义@ResponseBody渲染

Spring使用 HttpMessageConverters 渲染 @ResponseBody (或 @RestController 的响应) . 您可以通过在Spring Boot上下文中添加适当类型的bean来贡献额外的转换器. 如果您添加的Bean仍是默认情况下将包含的类型 (例如JSON转换的 MappingJackson2HttpMessageConverter) ,它将替换默认值. 提供了 HttpMessageConverters 类型的便捷bean,如果使用默认的MVC配置,它将始终可用. 它提供了一些有用的方法来访问默认的和用户增强的消息转换器 (例如,如果您想将它们手动注入到自定义的 RestTemplate 中,则可能会很有用) .

与正常的MVC用法一样,您提供的任何 WebMvcConfigurer Bean也可以通过重写 configureMessageConverters 方法来贡献转换器. 但是,与普通的MVC不同,您只能提供所需的其他转换器 (因为Spring Boot使用相同的机制来提供其默认值) . 最后,如果通过提供自己的 @EnableWebMvc 配置选择退出Spring Boot默认MVC配置,则可以完全控制并使用 WebMvcConfigurationSupport 中的 getMessageConverters 手动执行所有操作.

有关更多详细信息,请参见 WebMvcAutoConfiguration 源代码.

4.5. 处理分段文件上传

Spring Boot包含 Servlet 3 javax.servlet.http.Part API以支持上传文件. 默认情况下,Spring Boot用单个请求将Spring MVC配置为每个文件最大大小为 1MB,最大文件数据为10MB. 您可以使用 MultipartProperties 类中暴露的属性覆盖这些值,存储中间数据的位置 (例如,存储到 /tmp 目录) 以及将数据刷新到磁盘的阈值. 例如,如果要指定文件不受限制,请将 spring.servlet.multipart.max-file-size 属性设置为 -1.

当您想在Spring MVC控制器处理程序方法中以 MultipartFile 类型的 @RequestParam 注解参数接收多部分编码文件数据时,多部分支持会很有帮助.

有关更多详细信息,请参见 MultipartAutoConfiguration 源码.

建议使用容器的内置支持进行分段上传,而不要引入其他依赖,例如Apache Commons File Upload.

4.6. 关闭Spring MVC DispatcherServlet

默认情况下,所有内容均从应用程序 (/) 的根目录提供. 如果您希望映射到其他路径,则可以如下配置:

spring.mvc.servlet.path=/acme

如果您有其他 Servlet,则可以为每个 Servlet 声明一个 @BeanServletRegistrationBean 类型,Spring Boot会将它们透明地注册到容器中. 因为servlet是通过这种方式注册的,所以可以将它们映射到 DispatcherServlet 的子上下文,而无需调用它.

自己配置 DispatcherServlet 是不寻常的,但是如果您确实需要这样做,则还必须提供 DispatcherServletPath 类型的 @Bean,以提供自定义 DispatcherServlet 的路径.

4.7. 关闭默认的MVC配置

完全控制MVC配置的最简单方法是为您自己的 @Configuration 提供 @EnableWebMvc 注解. 这样做会使您掌握所有MVC配置.

4.8. 自定义 ViewResolvers

ViewResolver 是Spring MVC的核心组件,将 @Controller 中的视图名称转换为实际的 View 实现. 请注意,ViewResolvers 主要用于UI应用程序,而不是REST样式的服务 (View不用于呈现 @ResponseBody) . 有很多 ViewResolver 实现可供选择,Spring本身对是否应使用哪个视图没有意见. 另一方面,Spring Boot根据在类路径和应用程序上下文中找到的内容为您安装一个或两个. DispatcherServlet 使用它在应用程序上下文中找到的所有解析器, 依次尝试每个解析器,直到获得结果为止. 如果添加自己的解析器,则必须知道其顺序以及解析器的添加位置.

WebMvcAutoConfiguration 将以下 ViewResolvers 添加到您的上下文中:

  • 一个名为 defaultViewResolverInternalResourceViewResolver. 这一章查找可以通过使用 DefaultServlet 呈现的物理资源 (包括静态资源和JSP页面,如果使用的话) . 它在视图名称中应用前缀和后缀,然后在 Servlet 上下文中查找具有该路径的物理资源 (默认值均为空,但可通过 spring.mvc.view.prefixspring.mvc 进行外部配置访问. view.suffix) . 您可以通过提供相同类型的bean覆盖它.

  • 名为 beanNameViewResolverBeanNameViewResolver. 这是视图解析器链的有用成员,可以拾取与要解析的视图同名的所有bean. 不必重写或替换它.

  • 仅当实际上存在 View 类型的bean时,才添加一个名为 viewResolverContentNegotiatingViewResolver. 这是一个 ‘master’ 解析器,委派给所有其他解析器,并尝试查找与客户端发送的 ‘Accept’ HTTP标头匹配的内容. 您可能想学习有关 ContentNegotiatingViewResolver 的有用博客 ,以了解更多信息,并且您也可以查看源代码以获取详细信息. 您可以通过定义一个名为 viewResolver 的bean来关闭自动配置的 ContentNegotiatingViewResolver.

  • 如果您使用Thymeleaf,则还有一个名为 thymeleafViewResolverThymeleafViewResolver. 它通过在视图名称前后加上前缀和后缀来查找资源. 前缀为 spring.thymeleaf.prefix,后缀为 spring.thymeleaf.suffix. 前缀和后缀的值分别默认为 ‘classpath:/templates/’ 和 ‘.html’. 您可以通过提供同名的bean来覆盖 ThymeleafViewResolver.

  • 如果您使用FreeMarker,则还有一个名为 ‘freeMarkerViewResolver’ 的 FreeMarkerViewResolver. 它通过在视图名称前加上前缀和后缀来在加载器路径 (已将其外部化为 spring.freemarker.templateLoaderPath, 其默认值为 ‘classpath:/templates/’) 中查找资源. 前缀外部化为 spring.freemarker.prefix,后缀外部化为 spring.freemarker.suffix. 前缀和后缀的默认值分别为空和 ‘.ftlh’. 您可以通过提供同名的bean来覆盖 FreeMarkerViewResolver.

  • 如果您使用Groovy模板 (实际上,如果 groovy-templates 在类路径中) ,则您还将有一个名为 groovyMarkupViewResolverGroovyMarkupViewResolver. 它通过在视图名称前加上前缀和后缀 (在 spring.groovy.template.prefixspring.groovy.template.suffix 中进行了扩展) 来在加载程序路径中查找资源. 前缀和后缀的默认值分别为 ‘classpath:/templates/’ 和 ‘.tpl’. 您可以通过提供同名的bean来覆盖 GroovyMarkupViewResolver.

  • 如果您使用Mustache,则还有一个名为 ‘mustacheViewResolver’ 的 MustacheViewResolver. 它通过在视图名称前后加上前缀和后缀来查找资源. 前缀为 spring.mustache.prefix,后缀为 spring.mustache.suffix. 前缀和后缀的值分别默认为 ‘classpath:/templates/’ 和 ‘.mustache’. 您可以通过提供同名的bean来覆盖 MustacheViewResolver.

有关更多详细信息,请参见以下部分:

5. 使用Spring Security进行测试

Spring Security提供了对以特定用户身份运行测试的支持. 例如,下面的代码段中的测试将与具有 ADMIN 角色的经过身份验证的用户一起运行.

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

Spring Security提供了与Spring MVC Test的全面集成,并且在使用 @WebMvcTest slice和 MockMvc 测试控制器时也可以使用它.

有关Spring Security的测试支持的更多详细信息,请参阅Spring Security的 参考文档.

6. Jersey

6.1. 使用Spring Security保护Jersey端点

可以使用Spring Security来保护基于Jersey的Web应用程序,其方式与用来保护基于Spring MVC的Web应用程序的方式几乎相同. 但是,如果您想将Spring Security的方法级安全性与Jersey一起使用,则必须将Jersey配置为使用 setStatus(int) 而不是 sendError(int). 这可以防止Jersey在Spring Security有机会向客户端报告身份验证或授权失败之前提交响应.

必须在应用程序的 ResourceConfig bean上将 jersey.config.server.response.setStatusOverSendError 属性设置为 true,如以下示例所示:

@Component
public class JerseyConfig extends ResourceConfig {

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

}

6.2. 与另一个Web框架一起使用Jersey

要将Jersey与其他Web框架 (例如Spring MVC) 一起使用,应对其进行配置,以便它将允许其他框架处理无法处理的请求. 首先,通过将 spring.jersey.type 应用程序属性配置为 filter 值,将Jersey配置为使用Filter而不是Servlet. 其次,配置您的 ResourceConfig 以转发可能导致404的请求,如以下示例所示.

@Component
public class JerseyConfig extends ResourceConfig {

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

}

7. HTTP Clients

Spring Boot offers a number of starters that work with HTTP clients. Spring Boot提供了许多可与HTTP Clients 一起使用的 starters. 本节回答与使用它们有关的问题.

7.1. 配置RestTemplate使用代理

spring-boot-features.html 中所述,您可以将 RestTemplateCustomizerRestTemplateBuilder 一起使用以构建自定义的 RestTemplate. 建议使用此方法来创建配置为使用代理的 RestTemplate.

代理配置的确切详细信息取决于所使用的基础客户端请求工厂. 下面的示例使用一个HttpClient配置 HttpComponentsClientRequestFactory,该 HttpClient 为除 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));
    }

}

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

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

@Bean
ClientHttpConnector clientHttpConnector(ReactorResourceFactory resourceFactory) {
    TcpClient tcpClient = TcpClient.create(resourceFactory.getConnectionProvider())
            .runOn(resourceFactory.getLoopResources()).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 60000)
            .doOnConnected((connection) -> connection.addHandlerLast(new ReadTimeoutHandler(60)));
    return new ReactorClientHttpConnector(HttpClient.from(tcpClient));
}
注意将 ReactorResourceFactory 用于连接提供程序和事件循环资源. 这确保了用于服务器接收请求和客户端发出请求的资源的有效共享.

8. Logging

除了通常由Spring Framework的spring-jcl模块提供的Commons Logging API之外,Spring Boot没有强制性的日志记录依赖性. 要使用 Logback,您需要在类路径中包括它和 spring-jcl. 最简单的方法是通过启动程序,所有启动程序都依赖于 spring-boot-starter-logging. 对于Web应用程序,只需要 spring-boot-starter-web,因为它暂时依赖于日志记录启动器. 如果使用Maven,则以下依赖会为您添加日志记录:

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

Spring Boot有一个 LoggingSystem 抽象,它试图根据类路径的内容来配置日志. 如果可以使用Logback,则它是首选.

如果您需要对日志记录进行的唯一更改是设置各种记录器的级别,则可以使用 "logging.level" 前缀在 application.properties 中进行设置,如以下示例所示:

logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=ERROR

您还可以使用 "logging.file.name" 来设置要写入日志的文件的位置 (除了控制台) .

要配置日志记录系统的更细粒度的设置,您需要使用所讨论的LoggingSystem支持的本机配置格式. 默认情况下,Spring Boot从系统的默认位置 (例如,用于Logback的 classpath:logback.xml) 拾取本地配置,但是您可以使用 logging.config 属性设置配置文件的位置.

8.1. 配置 Logback Logging

如果您需要应用自定义项来进行登录,而不是使用 application.properties 可以实现的自定义项,则需要添加一个标准的登录配置文件. 您可以将 logback.xml 文件添加到类路径的根目录中,以进行logback查找. 如果要使用 Spring Boot Logback扩展,也可以使用 logback-spring.xml.

Logback文档有一个专用部分,其中 详细介绍了配置.

Spring Boot提供了许多您自己的配置中 included 的logback配置. 这些包括旨在允许重新应用某些常见的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>

您的日志配置文件也可以利用 LoggingSystem 为您创建的System属性:

  • ${PID}: The 当前进程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 文件.

8.1.1. 配置仅文件输出的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.properties 中,如以下示例所示:

logging.file.name=myapplication.log

8.2. 配置 Log4j 日志

如果Spring Boot在类路径上,则它支持 Log4j 2 进行日志记录配置. 如果使用 starters 来组装依赖,则必须排除Logback,然后改为包括 log4j 2. 如果您不使用启动器,则除了Log4j 2外,还需要 (至少) 提供 spring-jcl.

最简单的方法可能是通过启动程序,即使它需要对排除对象进行微调. 以下示例显示了如何在Maven中设置 starters:

<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中设置 starters 的一种方法:

    dependencies {
        compile 'org.springframework.boot:spring-boot-starter-web'
    }

    configurations.all {
        resolutionStrategy.dependencySubstitution.all { dependency ->
            if (dependency.requested instanceof ModuleComponentSelector && dependency.requested.module == 'spring-boot-starter-logging') {
                dependency.useTarget("org.springframework.boot:spring-boot-starter-log4j2:$dependency.requested.version", '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 logging adapter.

8.2.1. 使用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

9. 数据访问

Spring Boot包含许多用于处理数据源的启动器. 本节回答与这样做有关的问题.

9.1. 配置自定义数据源

要配置自己的数据源,请在配置中定义该类型的 @Bean. Spring Boot重用您的 DataSource 到任何需要的地方,包括数据库初始化. 如果需要外部化某些设置,则可以将 DataSource 绑定到环境 (请参见"`spring-boot-features.html`") .

以下示例显示了如何在Bean中定义数据源:

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

以下示例显示如何通过设置属性来定义数据源:

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

假设您的 FancyDataSource 具有URL,用户名和池大小的常规JavaBean属性,则在将 DataSource 提供给其他组件之前,将自动绑定这些设置. 常规的数据库初始化 也会发生 (因此 spring.datasource.* 的相关子集仍然可以与您的自定义配置一起使用) .

Spring Boot还提供了一个名为 DataSourceBuilder 的实用工具生成器类,可用于创建标准数据源之一 (如果它位于类路径上) . 构建者可以根据类路径中可用的内容来检测要使用的内容. 它还基于JDBC URL自动检测驱动程序.

下面的示例演示如何使用 DataSourceBuilder 创建数据源:

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

要使用该数据源运行应用程序,您需要的只是连接信息. 还可以提供特定于池的设置. 有关更多详细信息,请检查将在运行时使用的实现.

以下示例显示如何通过设置属性来定义JDBC数据源:

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

但是,有一个陷阱. 由于未暴露连接池的实际类型,因此在自定义DataSource的元数据中不会生成任何键,并且IDE中也无法完成操作 (因为 DataSource 接口未暴露任何属性) . 另外,如果您碰巧在类路径上有Hikari,则此基本设置将不起作用,因为Hikari没有 url 属性 (但确实具有 jdbcUrl 属性) . 在这种情况下,您必须按照以下方式重写配置:

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

您可以通过强制连接池使用并返回专用的实现而不是 DataSource 来解决此问题. 您无法在运行时更改实现,但是选项列表将是明确的.

以下示例显示了如何使用 DataSourceBuilder 创建 HikariDataSource:

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

您甚至可以利用 DataSourceProperties 为您做的事情进一步发展-即,通过提供默认的嵌入式数据库,并在不提供URL的情况下提供合理的用户名和密码. 您可以从任何 DataSourceProperties 对象的状态轻松地初始化 DataSourceBuilder,因此还可以注入Spring Boot自动创建的 DataSource. 但是,这会将您的配置分为两个命名空间: spring.datasource 上的 url, username, password, typedriver,其余部分放在您的自定义命名空间 (app.datasource) 上. 为避免这种情况,可以在自定义命名空间上重新定义自定义 DataSourceProperties,如以下示例所示:

@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();
}

默认情况下,该设置使您与Spring Boot为您执行的操作保持同步,不同的是,已选择 (以代码形式) 专用连接池,并且其设置在 app.datasource.configuration 子命名空间中暴露. 由于 DataSourceProperties 会为您处理 url / jdbcUrl 转换,因此可以按以下方式进行配置:

app.datasource.url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.configuration.maximum-pool-size=30
Spring Boot会将针对Hikari的设置暴露给 spring.datasource.hikari. 本示例使用更通用的配置子命名空间,因为该示例不支持多个数据源实现.
由于您的自定义配置选择使用Hikari,因此 app.datasource.type 无效. 实际上,构建器会使用您可以在其中设置的任何值进行初始化,然后由对 .type () 的调用覆盖.

有关更多详细信息,请参见 "Spring Boot 特性" 部分中的 “spring-boot-features.html” 和 DataSourceAutoConfiguration 类.

9.2. 配置两个数据源

如果需要配置多个数据源,则可以应用上一节中介绍的相同技巧. 但是,您必须将其中一个 DataSource 实例标记为 @Primary,因为将来各种自动配置都希望能够按类型获取一个.

如果您创建自己的数据源,则会取消自动配置. 在以下示例中,我们提供与自动配置在主数据源上提供的功能完全相同的功能集:

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

@Bean
@Primary
@ConfigurationProperties("app.datasource.first.configuration")
public HikariDataSource firstDataSource() {
    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
app.datasource.first.username=dbuser
app.datasource.first.password=dbpass
app.datasource.first.configuration.maximum-pool-size=30

app.datasource.second.url=jdbc:mysql://localhost/second
app.datasource.second.username=dbuser
app.datasource.second.password=dbpass
app.datasource.second.max-total=30

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

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

@Bean
@Primary
@ConfigurationProperties("app.datasource.first.configuration")
public HikariDataSource firstDataSource() {
    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() {
    return secondDataSourceProperties().initializeDataSourceBuilder().type(BasicDataSource.class).build();
}

上面的示例在自定义命名空间上配置两个数据源,其逻辑与Spring Boot在自动配置中使用的逻辑相同. 请注意,每个配置子命名空间均基于所选实现提供高级设置.

9.3. 使用 Spring Data Repositories

Spring Data可以创建各种风格的 @Repository 接口的实现. 只要那些 @Repositories 包含在 @EnableAutoConfiguration 类的同一包 (或子包) 中,Spring Boot就会为您处理所有这些操作.

对于许多应用程序,您所需要做的就是在类路径上放置正确的Spring Data依赖. 有一个用于JPA的 spring-boot-starter-data-jpa,一个用于Mongodb的 spring-boot-starter-data-mongodb,等等. 首先,创建一些存储库接口来处理 @Entity 对象.

Spring Boot会根据发现的 @EnableAutoConfiguration 尝试猜测 @Repository 定义的位置. 要获得更多控制权,请使用 @EnableJpaRepositories 注解 (来自Spring Data JPA) .

有关Spring Data的更多信息,请参见 Spring Data 项目页面.

9.4. 将@Entity定义与Spring配置分开

Spring Boot会根据发现的 @EnableAutoConfiguration 尝试猜测 @Entity 定义的位置. 要获得更多控制,可以使用 @EntityScan 注解,如以下示例所示:

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

    //...

}

9.5. 配置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
spring.jpa.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属性应用高级自定义,请考虑注册在创建 EntityManagerFactory 之前将被调用的 HibernatePropertiesCustomizer bean. 这优先于自动配置应用的任何内容.

9.6. 配置 Hibernate 命名策略

Hibernate使用 两种不同的命名策略 将名称从对象模型映射到相应的数据库名称. 可以分别通过设置 spring.jpa.hibernate.naming.physical-strategyspring.jpa.hibernate.naming.implicit-strategy 属性来配置物理和隐式策略实现的标准类名. 另外,如果在应用程序上下文中可以使用 ImplicitNamingStrategyPhysicalNamingStrategy Bean,则Hibernate将自动配置为使用它们.

默认情况下,Spring Boot 使用 SpringPhysicalNamingStrategy 配置物理命名策略. 此实现提供了与Hibernate 4相同的表结构: 所有点都由下划线替换,而骆驼套也由下划线替换. 默认情况下,所有表名均以小写形式生成,但是如果您的架构需要它,则可以覆盖该标志.

例如,一个 TelephoneNumber 实体被映射到 telephone_number 表.

@Bean
SpringPhysicalNamingStrategy caseSensitivePhysicalNamingStrategy() {
    return new SpringPhysicalNamingStrategy() {

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

    };
}

如果您希望改用 Hibernate 5 的默认设置,请设置以下属性:

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

另外,您可以配置以下bean:

@Bean
public PhysicalNamingStrategy physicalNamingStrategy() {
    return new PhysicalNamingStrategyStandardImpl();
}

有关更多详细信息,请参见 HibernateJpaAutoConfigurationJpaBaseConfiguration.

9.7. 配置Hibernate二级缓存

可以为一系列缓存提供程序配置Hibernate 二级缓存. 与其将Hibernate配置为再次查找缓存提供程序,不如提供尽可能在上下文中可用的缓存提供程序.

如果您使用的是JCache,这非常简单. 首先,确保 org.hibernate:hibernate-jcache 在类路径上可用. 然后,添加一个 HibernatePropertiesCustomizer bean,如以下示例所示:

@Configuration(proxyBeanMethods = false)
public class HibernateSecondLevelCacheExample {

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

}

这个定制器将配置Hibernate使用与应用程序相同的 CacheManager. 也可以使用单独的 CacheManager 实例. 有关详细信息,请参阅 Hibernate用户指南.

9.8. 在 Hibernate 组件中使用依赖注入

默认情况下,Spring Boot注册一个使用BeanFactory的 BeanContainer 实现,以便转换器和实体监听器可以使用常规的依赖注入.

您可以通过注册删除或更改 hibernate.resource.beans.container 属性的 HibernatePropertiesCustomizer 来禁用或调整此行为.

9.9. 使用自定义EntityManagerFactory

要完全控制 EntityManagerFactory 的配置,您需要添加一个名为 ‘entityManagerFactory’ 的 @Bean. 如果存在这种类型的Bean,Spring Boot自动配置将关闭其实体管理器.

9.10. 使用两个EntityManager

即使默认的 EntityManagerFactory 正常工作,您也需要定义一个新的. 否则,该类型的第二个bean的存在将关闭默认值. 为了简化操作,您可以使用Spring Boot提供的便捷 EntityManagerBuilder. 或者,您可以直接从Spring ORM中直接访问 LocalContainerEntityManagerManagerBean,如以下示例所示:

// add two data sources configured as above

@Bean
public LocalContainerEntityManagerFactoryBean customerEntityManagerFactory(
        EntityManagerFactoryBuilder builder) {
    return builder
            .dataSource(customerDataSource())
            .packages(Customer.class)
            .persistenceUnit("customers")
            .build();
}

@Bean
public LocalContainerEntityManagerFactoryBean orderEntityManagerFactory(
        EntityManagerFactoryBuilder builder) {
    return builder
            .dataSource(orderDataSource())
            .packages(Order.class)
            .persistenceUnit("orders")
            .build();
}
当您自己为 LocalContainerEntityManagerFactoryBean 创建bean时,在自动配置的 LocalContainerEntityManagerFactoryBean 创建期间应用的所有自定义设置都将丢失. 例如,对于Hibernate,spring.jpa.hibernate 前缀下的任何属性都不会自动应用于您的 LocalContainerEntityManagerManagerBean. 如果您依靠这些属性来配置诸如命名策略或DDL模式之类的东西,那么在创建 LocalContainerEntityManagerManagerBean bean时将需要显式配置. 另一方面,如果您使用自动配置的 EntityManagerFactoryBuilder 来构建 LocalContainerEntityManagerFactoryBean bean,那么将自动应用通过 spring.jpa.properties 指定的应用于自动配置的 EntityManagerFactoryBuilder 的属性.

上面的配置几乎可以独立工作. 为了完成此图,您还需要为两个 EntityManager 配置 TransactionManager. 如果将其中一个标记为 @Primary,则可以由Spring Boot中的默认 JpaTransactionManager 拾取. 另一个必须显式地注入到新实例中. 另外,您也许可以使用跨两个JTA事务管理器.

如果使用Spring Data,则需要相应地配置 @EnableJpaRepositories,如以下示例所示:

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

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

9.11. 使用传统的 persistence.xml 文件

默认情况下,Spring Boot不会搜索或使用 META-INF/persistence.xml . 如果您更喜欢使用传统的 persistence.xml,则需要定义自己的 LocalBeanManagerFactoryBean 类型的 @Bean (ID为 ‘entityManagerFactory’) ,并在其中设置持久性单元名称.

有关默认设置,请参见 JpaBaseConfiguration.

9.12. 使用 Spring Data JPA 和 Mongo 存储库

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,Solr等) ,存在相同的障碍和相同的功能. 要使用它们,请相应地更改注解和标志的名称.

9.13. 定制 Spring Data 的 Web 支持

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

9.14. 将 Spring Data Repositories 暴露为REST端点

如果已为应用程序启用了 Spring MVC,则 Spring Data REST 可以为您将 Repository 实现作为REST端点暴露.

Spring Boot 暴露了一组有用的属性 (来自 spring.data.rest 命名空间) ,这些属性来自定义 RepositoryRestConfiguration. 如果需要提供其他定制,则应使用 RepositoryRestConfigurer bean.

如果您未在自定义 RepositoryRestConfigurer 上指定任何顺序,则该顺序在一个 Spring Boot 内部使用后运行. 如果您需要指定订单,请确保该订单大于 0.

9.15. 配置JPA使用的组件

如果要配置JPA使用的组件,则需要确保在JPA之前初始化该组件. 当组件被自动配置后,Spring Boot会为您处理. 例如,当自动配置Flyway时,会将Hibernate配置为依赖Flyway,以便Flyway有机会在Hibernate尝试使用数据库之前对其进行初始化.

如果您自己配置组件,则可以使用 EntityManagerFactoryDependsOnPostProcessor 子类作为设置必要依赖的便捷方法. 例如,如果您将Hibernate Search和Elasticsearch用作其索引管理器,则必须将任何 EntityManagerFactory Bean配置为依赖于 elasticsearchClient Bean,如以下示例所示:

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

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

}

9.16. 使用两个数据源配置jOOQ

如果需要将jOOQ与多个数据源一起使用,则应该为每个数据源创建自己的 DSLContext. 有关更多详细信息,请参阅 JooqAutoConfiguration .

特别是,可以重用 JooqExceptionTranslatorSpringTransactionProvider 以提供与自动配置对单个 DataSource 所做的功能相似的功能.

10. 初始化 Database

可以使用不同的方式初始化SQL数据库,具体取决于堆栈是什么. 当然,如果数据库是一个单独的过程,您也可以手动执行. 建议使用单一机制进行模式生成.

10.1. 使用JPA初始化数据库

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

spring.jpa.hibernate.ddl-auto (枚举)

  • spring.jpa.generate-ddl (boolean) 开启和关闭该功能,并且与供应商无关.

  • spring.jpa.hibernate.ddl-auto (enum)是一种Hibernate功能,可以更精细地控制行为. 此功能将在本指南的后面部分详细介绍.

10.2. 使用 Hibernate 初始化数据库

您可以显式设置 spring.jpa.hibernate.ddl-auto,并且标准的Hibernate属性值为 none,验证,更新,创建和创建放置. Spring Boot根据是否认为您的数据库已嵌入为您选择默认值. 如果未检测到模式管理器,或者在所有其他情况下均未检测到模式管理器,则默认为 create-drop. 通过查看连接类型可以检测到嵌入式数据库. hsqldb,h2derby 是嵌入式的,其他则不是. 从内存数据库转换为 "真实" 数据库时,请务必不要假设新平台中表和数据的存在. 您必须显式设置 ddl-auto 或使用其他机制之一来初始化数据库.

您可以通过启用 org.hibernate.SQL 记录器来输出模式创建. 如果启用调试模式,此操作将自动为您完成.

另外,如果Hibernate从头开始创建架构 (即,如果 ddl-auto 属性设置为 createcreate-drop) ,则在启动时会在类路径的根目录中执行一个名为 import.sql 的文件. 如果您小心的话,这对于演示和测试很有用,但可能不希望出现在生产环境的类路径中. 这是一个Hibernate功能 (与Spring无关) .

10.3. 初始化数据库

Spring Boot 可以自动创建数据源的架构 (DDL脚本) 并对其进行初始化 (DML脚本) . 它从标准根类路径位置 (分别为 schema.sqldata.sql) 加载SQL. 另外,Spring Boot处理 schema-${platform}.sqldata-${platform}.sql 文件 (如果存在) ,其中 platformspring.datasource.platform 的值. 这使您可以在必要时切换到特定于数据库的脚本. 例如,您可以选择将其设置为数据库的供应商名称 (hsqldb,h2,oracle,mysql,postgresql 等) .

Spring Boot 自动创建嵌入式数据源的架构. 可以使用 spring.datasource.initialization-mode 属性来自定义此行为. 例如,如果要始终初始化数据源,而不管其类型如何:

spring.datasource.initialization-mode=always

在基于 JPA 的应用程序中,您可以选择让 Hibernate 创建 schema 或使用 schema.sql,但您不能两者都做. 如果使用 schema.sql,请确保禁用 spring.jpa.hibernate.ddl-auto.

spring.jpa.hibernate.ddl-auto=none

如果你正在使用 Flyway 或 Liquibase 高级数据库迁移工具, 则无法使用 basic SQL 创建和初始化 schema 的脚本。 不建议将 basic schema.sqldata.sql 脚本与 Flyway 或 Liquibase 一起使用,并且在以后的版本中将删除支持。

默认情况下,Spring Boot 启用 Spring JDBC 初始化程序的快速失败功能. 这意味着,如果脚本导致异常,则应用程序将无法启动. 您可以通过设置 spring.datasource.continue-on-error 来调整行为.

10.4. 初始化一个Spring Batch数据库

如果您使用 Spring Batch,则它随大多数流行的数据库平台一起预包装了SQL初始化脚本. Spring Boot 可以检测您的数据库类型并在启动时执行这些脚本. 如果您使用嵌入式数据库,则默认情况下会发生这种情况. 您还可以为任何数据库类型启用它,如以下示例所示:

spring.batch.initialize-schema=always

您还可以通过设置 spring.batch.initialize-schema=never 显式关闭初始化.

10.5. 使用高级数据库迁移工具

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

10.5.1. 在启动时执行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编写. 将使用实现 JavaMigration 的任何bean自动配置 Flyway.

FlywayProperties 提供了Flyway的大多数设置以及少量的其他属性,这些属性可用于禁用迁移或关闭位置检查. 如果您需要对配置进行更多控制,请考虑注册 FlywayConfigurationCustomizer bean.

Spring Boot调用 Flyway.migrate() 来执行数据库迁移. 如果您想要更多控制,请提供一个实现 FlywayMigrationStrategy@Bean.

Flyway支持SQL和Java callbacks. 要使用基于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使用其自己的 DataSource. 如果未设置这三个属性中的任何一个,则将使用其等效的 spring.datasource 属性的值.

您还可以使用Flyway为特定情况提供数据. 例如,您可以将特定于测试的迁移放置在 src/test/resources 中,并且仅在您的应用程序开始进行测试时才运行它们. 另外,您可以使用特定于配置文件的配置来自定义 spring.flyway.locations,以便仅在特定配置文件处于 active 状态时才运行某些迁移. 例如,在 application-dev.properties 中,您可以指定以下设置:

spring.flyway.locations=classpath:/db/migration,classpath:/dev/db/migration

通过该设置,仅在 dev 环境下才运行 dev/db/migration 中的迁移.

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

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

默认情况下,从 db/changelog/db.changelog-master.yaml 中读取主更改日志,但是您可以通过设置 spring.liquibase.change-log 来更改位置. 除了 YAML,Liquibase还支持JSON,XML和SQL更改日志格式.

默认情况下,Liquibase在您的上下文中自动装配 (@Primary) 数据源,并将其用于迁移. 如果需要使用其他数据源,则可以创建一个并将其 @Bean 标记为 @LiquibaseDataSource. 如果这样做,并且想要两个数据源,请记住创建另一个数据源并将其标记为 @Primary. 另外,您可以通过在外部属性中设置 spring.liquibase.[url,user,password] 来使用Liquibase的本机数据源. 设置 spring.liquibase.urlspring.liquibase.user 足以使 Liquibase 使用其自己的数据源. 如果未设置这三个属性中的任何一个,则将使用其等效的 spring.datasource 属性的值.

有关可用设置 (例如上下文,默认架构等) 的详细信息,请参见 LiquibaseProperties.

11. 消息

Spring Boot提供了许多包含消息传递的启动器. 本部分回答了将消息与Spring Boot一起使用所引起的问题.

11.1. 禁用事务JMS会话

如果您的JMS代理不支持事务处理会话,则必须完全禁用对事务的支持. 如果创建自己的 JmsListenerContainerFactory,则无需执行任何操作,因为默认情况下无法进行处理. 如果您想使用 DefaultJmsListenerContainerFactoryConfigurer 重用Spring Boot的默认设置,则可以按以下方式禁用事务会话:

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

前面的示例将覆盖默认工厂,并且应将其应用于应用程序定义的任何其他工厂 (如果有) .

12. Batch Applications

当人们从Spring Boot应用程序中使用Spring Batch时,经常会出现许多问题. 本节解决这些问题.

12.1. 指定批处理数据源

默认情况下,批处理应用程序需要一个数据源来存储作业详细信息. 批处理在您的上下文中自动装配单个数据源,并将其用于处理. 要使批处理使用应用程序的主数据源以外的其他数据源,请声明一个数据源bean,并用 @BatchDataSource 注解其 @Bean 方法. 如果这样做并想要两个数据源,请记住创建另一个数据源并将其标记为 @Primary. 为了更好地控制,请实现 BatchConfigurer. 有关更多详细信息,请参见 The Javadoc of @EnableBatchProcessing 的Javadoc.

有关Spring Batch的更多信息,请参见 Spring Batch 项目页面.

12.2. 在启动时执行Spring Batch作业

通过在 @Configuration 类的某个位置添加 @EnableBatchProcessing,可以启用Spring Batch自动配置.

默认情况下,它将在启动时在应用程序上下文中执行所有作业 (有关详细信息,请参见 JobLauncherCommandLineRunner) . 您可以通过指定 spring.batch.job.names (采用作业名称模式的逗号分隔列表) 来缩小到一个或多个特定作业.

{spring-boot-autoconfigure-module-code}/batch/BatchAutoConfiguration.java[BatchAutoConfiguration] and {spring-batch-api}/core/configuration/annotation/EnableBatchProcessing.html[@EnableBatchProcessing] 获取更多信息.

12.3. 在命令行上运行

从命令行通过Spring Boot运行Spring Batch与从命令行单独运行Spring Batch有所不同. 最重要的区别是,它们对命令行参数的解析方式不同,这可能会引起麻烦,如下一节所述.

12.3.1. 通过命令行参数

Spring Boot将任何以 -- 开头的命令行参数转换为一个属性以添加到 Environment 中,请参见 << spring-boot-features.adoc#boot-features-external-config-command-line-args,访问命令行属性>>. 不应该将其作为参数传递给批处理作业. 要在命令行上指定批处理参数,请使用常规格式 (即不使用 -- ) ,如以下示例所示:

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

如果在命令行上指定 Environment 的属性,它将影响您的作业使用的参数. 考虑以下命令:

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

这为批处理作业提供了两个参数: someParameter=someValue-server.port=7070. 请注意,第二个参数缺少连字符,因为Spring Batch将删除属性的第一个 - 字符 (如果存在) .

12.4. 存储作业库

Spring Batch需要一个用于Job仓库的数据存储. 如果使用Spring Boot,则必须使用实际的数据库. 请注意,它可以是内存数据库,请参见 docs.spring.io/spring-batch/docs/{spring-batch-version}/reference/html/ job.html#configuringJobRepository[配置作业存储库].

13. Actuator

Spring Boot包括Spring Boot Actuator. 本节回答了经常因使用而引起的问题.

13.1. 更改 Actuator 端点的HTTP端口或地址

在独立应用程序中,Actuator HTTP端口默认与主HTTP端口相同. 要使应用程序在其他端口上进行监听,请设置外部属性: management.server.port. 要监听完全不同的网络地址 (例如,当您拥有用于管理的内部网络和用于用户应用程序的外部网络) 时,还可以将 management.server.address 设置为服务器能够绑定到的有效IP地址.

有关更多详细信息,请参阅 生产就绪功能 部分中的 ManagementServerProperties 源代码和 “production-ready-features.html” .

13.2. 自定义 ‘whitelabel’ 错误页面

如果遇到服务器错误,Spring Boot会安装一个'`whitelabel’ 错误页面,您会在浏览器客户端中看到该错误页面 (使用JSON和其他媒体类型的机器客户端应该看到带有正确错误代码的明智响应) .

设置 server.error.whitelabel.enabled=false 可以关闭默认错误页面. 这样做将还原您正在使用的servlet容器的默认值. 请注意,Spring Boot仍然尝试解决错误视图,因此您应该添加自己的错误页面,而不是完全禁用它.

用自己的方法覆盖错误页面取决于您使用的模板技术. 例如,如果您使用Thymeleaf,则可以添加 error.html 模板. 如果使用FreeMarker,则可以添加 error.ftlh 模板. 通常,您需要使用错误名称解析的View或处理 /error 路径的 @Controller. 除非您替换了某些默认配置,否则您应该在 ApplicationContext 中找到一个 BeanNameViewResolver,因此,以 @Bean 命名的错误将是一种简单的方法. 有关更多选项,请参见 ErrorMvcAutoConfiguration .

有关如何在Servlet容器中注册处理程序的详细信息,另请参见 “错误处理” 部分.

13.3. Sanitize Sensitive Values

envconfigprops 端点返回的信息可能有些敏感,因此默认情况下会清理匹配特定模式的键 (即,它们的值将替换为 ) .

可以分别使用 management.endpoint.env.keys-to-sanitizemanagement.endpoint.configprops.keys-to-sanitize 来定制要使用的模式.

Spring Boot 对此类密钥使用明智的默认设置: 例如,对任何以单词 "password", "secret", "key", "token", "vcap_services", "sun.java.command" 结尾的密钥进行清理. 也可以改用正则表达式,例如 *credentials.* 来清理任何将单词凭据作为密钥一部分保存的密钥.

此外,Spring Boot 仅对以 "uri", "uris", "address", or "addresses". 结尾的密钥的 URI 敏感部分进行清理。 URI 的敏感部分使用格式 <scheme>://<username>:<password>@<host>:<port>/ 来标识

例如,对于属性 myclient.uri=http://user1:password1@localhost:8081,最终的清理结果是 http://user1:******@localhost:8081.

13.4. 映射健康状态

Spring Boot 通过 Status 类型反应系统运行状况。 如果要监视或警告特定应用程序的运行状况,可以通过 Micrometer 暴露这些状态。 默认情况下,Spring Boot 使用状态代码 “up”, “down”,“out of service” 和 “unknown”。 要暴露这些状态,您需要将这些状态转换为一组数字,以便它们可以与 Micrometer 一起使用。

以下示例显示了一种方法:

@Configuration
public class HealthMetricsConfiguration {

    public HealthMetricsConfiguration(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;
    }

}

14. 安全

本部分解决有关使用Spring Boot时的安全性的问题,包括因将Spring Security与Spring Boot一起使用而引起的问题.

有关Spring Security的更多信息,请参见Spring Security 项目页面.

14.1. 关闭Spring Boot安全性配置

如果您在应用程序中使用 WebSecurityConfigurerAdapter 定义 @Configuration,它将关闭Spring Boot中的默认Webapp安全设置.

14.2. 更改UserDetailsService并添加用户帐户

如果提供类型为 AuthenticationManager,AuthenticationProviderUserDetailsService@Bean,则不会为 InMemoryUserDetailsManager 创建默认的 @Bean. 这意味着您拥有完整的Spring Security功能集 (例如 各种身份验证选项) .

添加用户帐户的最简单方法是提供自己的 UserDetailsService bean.

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

对于所有应用程序而言,确保所有主要端点仅可通过HTTPS进行访问都是一项重要的工作. 如果您将Tomcat用作Servlet容器,则Spring Boot如果检测到某些环境设置,则会自动添加Tomcat自己的RemoteIpValve, 并且您应该能够依靠 HttpServletRequest 来报告它是否安全 (甚至在代理服务器的下游) 处理真实的SSL终止) . 标准行为由某些请求标头 (x-forwarded-forx-forwarded-proto) 的存在或不存在决定,它们的名称是常规名称, 因此它应可与大多数前端代理一起使用. 您可以通过将一些条目添加到 application.properties 来打开阀门,如以下示例所示:

server.tomcat.remote-ip-header=x-forwarded-for
server.tomcat.protocol-header=x-forwarded-proto

(这些属性中的任何一个都会在阀上切换. 或者,您可以通过添加 TomcatServletWebServerFactory bean来添加 RemoteIpValve. )

要将Spring Security配置为对所有 (或某些) 请求都需要安全通道,请考虑添加自己的 WebSecurityConfigurerAdapter,其中添加了以下 HttpSecurity 配置:

@Configuration(proxyBeanMethods = false)
public class SslWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // Customize the application security
        http.requiresChannel().anyRequest().requiresSecure();
    }

}

15. 热交换

Spring Boot支持热插拔. 本部分回答有关其工作方式的问题.

15.1. 重新加载静态内容

有几种热加载选项. 推荐的方法是使用 spring-boot-devtools,因为它提供了其他开发时功能,例如对应用程序快速重启和LiveReload的支持以及合理的开发时配置 (例如模板缓存) . Devtools通过监视类路径的更改来工作. 这意味着必须 "构建" 静态资源更改才能使更改生效. 默认情况下,当您保存更改时,这在Eclipse中自动发生. 在IntelliJ IDEA中,"生成项目" 命令将触发必要的构建. 由于默认的重新启动排除项, 对静态资源的更改不会触发应用程序的重新启动. 但是,它们确实会触发实时重新加载.

另外,在IDE中运行 (特别是在调试时打开) 是进行开发的好方法 (所有现代IDE都允许重新加载静态资源,并且通常还允许热交换Java类更改) .

最后,可以配置 Maven 和 Gradle 插件 (请参见 addResources 属性) 以支持从命令行运行,并直接从源代码重新加载静态文件. 如果要使用高级工具编写该代码,则可以将其与外部 css/js 编译器进程一起使用.

15.2. 重新加载模板,而无需重新启动容器

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

15.2.1. Thymeleaf 模板

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

15.2.2. FreeMarker 模板

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

15.2.3. Groovy 模板

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

15.3. 快速重启应用程序

spring-boot-devtools 模块包括对应用程序自动重启的支持. 尽管不如 JRebel 这样的技术快,但通常比 “cold start” 要快得多. 在研究本文档后面讨论的一些更复杂的重载选项之前,您可能应该先尝试一下.

有关更多详细信息,请参见 using-spring-boot.html 部分.

15.4. 重新加载Java类而无需重新启动容器

许多现代的IDE (Eclipse,IDEA等) 都支持字节码的热交换. 因此,如果所做的更改不影响类或方法的签名,则应干净地重新加载而没有副作用.

16. 构建

Spring Boot包括Maven和Gradle的构建插件. 本部分回答有关这些插件的常见问题.

16.1. 生成构建信息

Maven插件和Gradle插件都允许生成包含项目的坐标,名称和版本的构建信息. 还可以将插件配置为通过配置添加其他属性. 当存在这样的文件时,Spring Boot会自动配置 BuildProperties bean.

要使用Maven生成构建信息,请为 build-info 目标添加执行,如以下示例所示:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>2.2.13.RELEASE</version>
            <executions>
                <execution>
                    <goals>
                        <goal>build-info</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
有关更多详细信息,请参见 Spring Boot Maven 插件文档.

下面的示例对Gradle执行相同的操作:

springBoot {
    buildInfo()
}
有关更多详细信息,请参见 Spring Boot Gradle 插件文档 .

16.2. 生成 Git 信息

Maven和Gradle都允许生成一个 git.properties 文件,其中包含有关构建项目时 git 源代码仓库状态的信息.

对于Maven用户,spring-boot-starter-parent POM包含一个预先配置的插件,用于生成 git.properties 文件. 要使用它,请将以下声明添加到您的POM中:

<build>
    <plugins>
        <plugin>
            <groupId>pl.project13.maven</groupId>
            <artifactId>git-commit-id-plugin</artifactId>
        </plugin>
    </plugins>
</build>

Gradle用户可以使用 gradle-git-properties插件获得相同的结果,如以下示例所示:

plugins {
    id "com.gorylenko.gradle-git-properties" version "2.2.2"
}
git.properties 中的提交时间应与以下格式匹配: yyyy-MM-dd’T’HH: mm: ssZ. 这是上面列出的两个插件的默认格式. 使用这种格式,可以将时间解析为 Date,并将其序列化为JSON后,由杰克逊的日期序列化配置设置控制.

16.3. 自定义依赖版本

如果您使用的Maven构建直接或间接继承自 spring-boot-dependencies (例如 spring-boot-starter-parent) ,但您想覆盖特定的第三方依赖,则可以添加适当的 <properties> 元素. 浏览 spring-boot-dependencies POM以获取属性的完整列表. 例如,要选择其他 slf4j 版本,应添加以下属性:

<properties>
    <slf4j.version>1.7.5<slf4j.version>
</properties>
仅当您的Maven项目 (直接或间接) 继承自 spring-boot-dependencies 时,此方法才有效. 如果使用 <scope>import</scope> 在自己的 dependencyManagement 部分中添加了 spring-boot-dependencies ,则必须自己重新定义 artifacts ,而不是覆盖属性.
每个Spring Boot版本都是针对这组特定的第三方依赖进行设计和测试的. 覆盖版本可能会导致兼容性问题.

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

16.4. 使用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>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

有关完整用法的详细信息,请参阅 插件文档 .

16.5. 使用Spring Boot应用程序作为依赖

像war文件一样,Spring Boot应用程序也不打算用作依赖. 如果您的应用程序包含要与其他项目共享的类,则建议的方法是将该代码移到单独的模块中. 然后,您的应用程序和其他项目可以依赖单独的模块.

如果您无法按照上面的建议重新排列代码,则必须配置Spring Boot的Maven和Gradle插件以生成单独的 artifacts ,该 artifacts 适合用作依赖. 可执行存档不能用作依赖,因为可执行jar格式 BOOT-INF/classes 中的应用程序类打包. 这意味着当将可执行jar用作依赖时,找不到它们.

为了产生两个 artifacts ,一个可以用作依赖,另一个可以执行,必须指定分类器. 该分类器应用于可执行归档文件的名称,保留默认归档文件以用作依赖.

要在Maven中配置 exec 的 classifier,可以使用以下配置:

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

16.6. 运行可执行jar时提取特定的库

可执行jar中的大多数嵌套库不需要解压即可运行. 但是,某些库可能会有问题. 例如,JRuby包含其自己的嵌套jar支持,它假定 jruby-complete.jar 始终可以直接作为文件直接使用.

为了处理任何有问题的库,您可以标记在可执行jar首次运行时应自动解压缩特定的嵌套jar. 这种嵌套的jar会写在 java.io.tmpdir 系统属性标识的临时目录下.

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

例如,为了指示应该使用Maven插件将JRuby标记为要解包,您可以添加以下配置:

<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>

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

通常,如果您具有一个可执行文件和一个不可执行的jar作为两个单独的构建产品,则可执行版本具有库jar中不需要的其他配置文件. 例如,application.yml 配置文件可能被排除在不可执行的JAR中.

在Maven中,可执行jar必须是主要 artifacts ,您可以为库添加一个 classified 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.yml</exclude>
                        </excludes>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

16.8. 远程调试以Maven开头的Spring Boot应用程序

要将远程调试器附加到使用Maven启动的Spring Boot应用程序,可以使用 maven 插件jvmArguments 属性.

有关更多详细信息,请参见此 示例.

16.9. 在不使用 spring-boot-antlib 的情况下从Ant构建可执行归档文件

要使用Ant进行构建,您需要获取依赖,进行编译,然后创建一个jar或war存档. 要使其可执行,可以使用 spring-boot-antlib 模块,也可以按照以下说明进行操作:

  1. 如果您要构建jar,请将应用程序的类和资源打包在嵌套的 BOOT-INF/classes 目录中. 如果要打仗,请照常将应用程序的类打包在嵌套的 WEB-INF/classes 目录中.

  2. 将运行时依赖添加到jar的嵌套 BOOT-INF/lib 目录中,或将其添加到 war 的 WEB-INF/lib 中. 切记不要压缩存档中的条目.

  3. provided 的 (嵌入式容器) 依赖添加到jar的嵌套 BOOT-INF/lib 目录中,或将 war 添加到 WEB-INF/lib 提供的嵌套目录中. 切记不要压缩存档中的条目.

  4. 在归档文件的根目录中添加 spring-boot-loader 类 (以便可以使用 Main-Class) .

  5. 使用适当的启动器 (例如jar文件的 JarLauncher) 作为清单中的 Main-Class 属性,并通过设置 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.JarLauncher" />
            <attribute name="Start-Class" value="${start-class}" />
        </manifest>
    </jar>
</target>

17. 传统部署

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

17.1. 创建可部署的 War 文件

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

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

@SpringBootApplication
public class Application extends SpringBootServletInitializer {

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

    public static void main(String[] args) {
        SpringApplication.run(Application.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'
    // …
}
与Gradle的 compileOnly 配置相比,providerRuntime 更受欢迎. 除其他限制外,compileOnly 依赖不在测试类路径上,因此任何基于Web的集成测试都将失败.

如果您使用 Spring Boot 构建工具,则将提供的嵌入式servlet容器依赖标记为提供,将生成可执行的war文件,其中提供的依赖打包在lib提供的目录中. 这意味着,除了可以部署到Servlet容器之外,还可以通过在命令行上使用 java -jar 运行应用程序.

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

对于非 Web 应用程序,将现有的 Spring 应用程序转换为 Spring Boot 应用程序应该很容易. 为此,请丢弃创建您的 ApplicationContext 的代码,并将其替换为对 SpringApplicationSpringApplicationBuilder 的调用. Spring MVC Web 应用程序通常适合于首先创建可部署的 war 应用程序,然后再将其迁移到可执行的 war 或 jar. 请参阅有关将 将 jar 转换为 war 的入门指南.

要通过扩展 SpringBootServletInitializer (例如,在名为 Application 的类中) 并添加Spring Boot @SpringBootApplication 注解来创建可部署的 war ,请使用类似于以下示例中所示的代码:

@SpringBootApplication
public class Application 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 (via @SpringBootApplication)
        // we actually don't need to override this method.
        return application;
    }

}

请记住,无论您在源代码中放入什么内容,都仅是Spring ApplicationContext. 通常,任何已经起作用的东西都应该在这里工作. 可能有些bean可以在以后删除,并让Spring Boot为它们提供自己的默认值,但是应该可以使某些东西工作,然后再执行此操作.

可以将静态资源移至类路径根目录中的 /public (或 /static/resources/META-INF/resources) . 这同样适用于 messages.properties (Spring Boot会在类路径的根目录中自动检测到该消息) .

在Spring DispatcherServlet 和Spring Security中使用 Vanilla 不需要进一步更改. 如果您的应用程序中具有其他功能 (例如,使用其他servlet或过滤器) ,则可能需要通过替换 web.xml 中的那些元素来向 Application 上下文中添加一些配置,如下所示:

  • 类型为 ServletServletRegistrationBean@Bean 将该bean安装在容器中,就好像它是 web.xml 中的 <servlet /><servlet-mapping /> 一样.

  • 类型为 FilterFilterRegistrationBean@Bean 的行为类似 (作为 <filter /><filter-mapping />) .

  • 可以通过应用程序中的 @ImportResource 添加XML文件中的 ApplicationContext. 或者,可以在几行中重新创建已经大量使用注解配置的简单情况作为 @Bean 定义.

war文件运行后,可以通过向 Application 中添加 main 方法使其变为可执行文件,如以下示例所示:

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

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

@SpringBootApplication
public class Application extends SpringBootServletInitializer {

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

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

    private static SpringApplicationBuilder configureApplication(SpringApplicationBuilder builder) {
        return builder.sources(Application.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应用程序,前面提到的指南可能会有所帮助. 但是,您可能仍然遇到问题. 在这种情况下,我们建议 使用 spring-boot 标签在Stack Overflow上提问.

17.3. 将WAR部署到WebLogic

要将Spring Boot应用程序部署到WebLogic,必须确保servlet初始化程序直接实现 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>

17.4. 使用 Jedis 代替 Lettuce

默认情况下,Spring Boot 启动器 (spring-boot-starter-data-redis) 使用 Lettuce. 您需要排除该依赖性,而改为包含 Jedis. Spring Boot 管理这些依赖,以帮助使此过程尽可能简单.

以下示例显示了如何在 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 中执行此操作:

configurations {
    compile.exclude module: "lettuce"
}

dependencies {
    compile("redis.clients:jedis")
    // ...
}