本部分提供了一些常见问题的解答:我该如何做那个…​在使用Spring Boot时经常出现的问题。它的报道不是详尽的,但确实涵盖了相当多的内容。

如果您有我们这里没有介绍的特定问题,您可能需要查看stackoverflow.com,看看是否有人已经提供了答案。这也是提出新问题的好地方(请使用SpringBoot标记)。

我们也非常乐意延长这一部分。如果您想添加How-to,请向我们发送拉取请求。

1. Spring Boot Application

本节包括与Spring Boot应用程序直接相关的主题。

1.1. Create Your Own FailureAnalyzer

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

AbstractFailureAnalyzerFailureAnalyzer的方便扩展,它检查要处理的异常中是否存在指定的异常类型。您可以在此基础上进行扩展,以便您的实现只有在异常实际存在时才有机会处理它。无论出于何种原因,如果您无法处理该异常,则返回NULL,以便让另一个实现有机会处理该异常。

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

org.springframework.boot.diagnostics.FailureAnalyzer=\ com.example.ProjectConstraintViolationFailureAnalyzer
            
            
If you need access to the BeanFactory or the Environment, your FailureAnalyzer can implement BeanFactoryAware or EnvironmentAware respectively.

1.2. Troubleshoot Auto-configuration

Spring Boot自动配置会尽最大努力“做正确的事情”,但有时事情会失败,而且很难说出原因。

在任何Spring BootApplicationContext中都有非常有用的ConditionEvaluationReport。如果启用调试记录输出,则可以看到它。如果您使用SpringBoot-Actuator(请参阅the Actuator章节),那么还有一个Conditions端点可以在JSON中呈现报表。使用该端点来调试应用程序,并查看Spring Boot在运行时添加了(和没有添加)了哪些功能。

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

  • 查找名为*Autoconfiguration的类,并阅读它们的源代码。请特别注意@Conditional*注释,以找出它们启用了哪些功能以及何时启用。将--DEBUG添加到命令行或系统属性-DDEBUG,以在控制台上获取在应用程序中做出的所有自动配置决策的日志。在启用了Actuator的运行应用程序中,查看Conditions端点(/Actuator/Conditions或JMX等效项)以了解相同的信息。

  • 查找@ConfigurationProperties的类(例如ServerProperties),并从中读取可用的外部配置选项。@ConfigurationProperties批注有一个name属性,该属性充当外部属性的前缀。因此,ServerPropertiesprefix=“服务器”,其配置属性是server.portserver.Address等。在启用了执行器的运行应用程序中,查看configprops端点。

  • 寻找在绑定器上使用Bind方法,以轻松的方式从Environment显式拉出配置值。它经常与前缀连用。

  • 查找直接绑定到环境@Value批注。

  • 查找响应Spel表达式打开和关闭功能的@ConditionalOnExpression注释,通常使用从Environment解析的占位符进行计算。

1.3. Customize the Environment or ApplicationContext Before It Starts

SpringApplication具有用于将自定义应用于上下文或环境的ApplicationListenersApplicationContextInitializers。Spring Boot从META-INF/spring.Factory加载许多这样的定制供内部使用。注册附加自定义的方式有多种:

  • 以编程方式针对每个应用程序,在运行它之前调用SpringApplication上的addListenersaddInitializers方法。

  • 声明性地针对每个应用程序,通过设置context.Initializer.classcontext.listener.class属性。

  • 声明性地,对于所有应用程序,通过添加META-INF/spring.Factory并打包一个JAR文件,应用程序都将其作为库使用。

SpringApplication将一些特殊的ApplicationEvent发送给侦听器(有些甚至在创建上下文之前),然后也为ApplicationContext发布的事件注册侦听器。有关完整列表,请参阅“Spring Boot特性”部分中的“应用程序事件和侦听器”。

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

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

该实现可以加载任意文件并将它们添加到环境。例如,下面的示例从类路径加载YAML配置文件:

Java
Kotlin
import java.io.IOException; import org.springframework.boot.SpringApplication; import org.springframework.boot.env.EnvironmentPostProcessor; import org.springframework.boot.env.YamlPropertySourceLoader; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.PropertySource; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.util.Assert; public class MyEnvironmentPostProcessor 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) { Assert.isTrue(path.exists(), () -> "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); } } } 
            
            
The Environment has already been prepared with all the usual property sources that Spring Boot loads by default. It is therefore possible to get the location of the file from the environment. The preceding example adds the custom-resource property source at the end of the list so that a key defined in any of the usual other locations takes precedence. A custom implementation may define another order.
While using @PropertySource on your @SpringBootApplication may seem to be a convenient way to load a custom resource in the Environment, we do not recommend it. Such property sources are not added to the Environment until the application context is being refreshed. This is too late to configure certain properties such as logging.* and spring.main.* which are read before refresh begins.

1.4. Build an ApplicationContext Hierarchy (Adding a Parent or Root Context)

您可以使用ApplicationBuilder类创建父/子ApplicationContext层次结构。有关更多信息,请参阅“Spring Boot特性”部分中的“ett ures.html”。

1.5. Create a Non-web Application

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

2. Properties and Configuration

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

2.1. Automatically Expand Properties at Build Time

您可以使用现有的生成配置自动展开某些属性,而不是对项目的生成配置中也指定的某些属性进行硬编码。这在Maven和Gradle中都是可能的。

2.1.1. Automatic Property Expansion Using Maven

通过使用资源筛选,您可以自动展开Maven项目中的属性。如果您使用SpringBoot-starter-Parent,则可以使用@..@占位符引用您的Maven‘项目属性’,如下例所示:

Properties
Yaml
app.encoding=@project.build.sourceEncoding@
app.java.version=@java.version@
             
             
Only production configuration is filtered that way (in other words, no filtering is applied on src/test/resources).
If you enable the addResources flag, the spring-boot:run goal can add src/main/resources directly to the classpath (for hot reloading purposes). Doing so circumvents the resource filtering and this feature. Instead, you can use the exec:java goal or customize the plugin’s configuration. See the plugin usage page for more details.

如果不使用起始父级,则需要在pom.xml<;Build/>;元素中包含以下元素:

<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>
    <version>2.7</version>
    <configuration>
        <delimiters>
            <delimiter>@</delimiter>
        </delimiters>
        <useDefaultDelimiters>false</useDefaultDelimiters>
    </configuration>
</plugin>
             
             
The useDefaultDelimiters property is important if you use standard Spring placeholders (such as ${placeholder}) in your configuration. If that property is not set to false, these may be expanded by the build.

2.1.2. Automatic Property Expansion Using Gradle

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

tasks.named('processResources') {
    expand(project.properties)
}
             
             

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

Properties
Yaml
app.name=${name}
app.description=${description}
             
             
Gradle’s expand method uses Groovy’s SimpleTemplateEngine, which transforms ${..} tokens. The ${..} style conflicts with Spring’s own property placeholder mechanism. To use Spring property placeholders together with automatic expansion, escape the Spring property placeholders as follows: \${..}.

2.2. Externalize the Configuration of SpringApplication

SpringApplication具有Bean属性设置器,因此您可以在创建应用程序时使用其Java API来修改其行为。或者,您可以通过设置spring.main.*中的属性来外部化配置。例如,在Applation.Properties中,您可能具有以下设置:

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

那么在启动时不会打印Spring Boot横幅,应用程序也不会启动嵌入式Web服务器。

外部配置中定义的属性覆盖和替换使用Java API指定的值,但主源除外。主要源代码是提供给SpringApplication构造函数的源代码:

Java
Kotlin
import org.springframework.boot.Banner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class MyApplication { public static void main(String[] args) { SpringApplication application = new SpringApplication(MyApplication.class); application.setBannerMode(Banner.Mode.OFF); application.run(args); } } 
            
            

或发送到<代码>源文件(…​)<代码>SpringApplicationBuilder方法:

Java
Kotlin
import org.springframework.boot.Banner; import org.springframework.boot.builder.SpringApplicationBuilder; public class MyApplication { public static void main(String[] args) { new SpringApplicationBuilder() .bannerMode(Banner.Mode.OFF) .sources(MyApplication.class) .run(args); } } 
            
            

在上面的示例中,如果我们有以下配置:

Properties
Yaml
spring.main.sources=com.example.MyDatabaseConfig,com.example.MyJmsConfig
spring.main.banner-mode=console
            
            

实际的应用程序将显示横幅(被配置覆盖),并为ApplicationContext使用三个源。应用程序来源包括:

  1. MyApplication(来自代码)

  2. 我的数据库配置(来自外部配置)

  3. MyJmsConfig(来自外部配置)

2.3. Change the Location of External Properties of an Application

默认情况下,来自不同来源的属性以定义的顺序添加到SpringEnvironment中(有关确切顺序,请参阅‘Spring Boot Feature’一节中的“Feature ures.html”)。

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

  • spring.config.name(SPUNG_CONFIG_NAME):默认为应用程序作为文件名的根。

  • spring.config.Location(SpringCONFIG_LOCATION):要加载的文件(如类路径资源或URL)。为该文档设置了单独的Environment属性源,它可以被系统属性、环境变量或命令行覆盖。

无论您在环境中设置什么,Spring Boot始终加载Application.Properties,如上所述。默认情况下,如果使用YAML,则扩展名为“.yml”的文件也会添加到列表中。

If you want detailed information about the files that are being loaded you can set the logging level of org.springframework.boot.context.config to trace.

2.4. Use ‘Short’ Command Line Arguments

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

Properties
Yaml
server.port=${port:8080}
            
            
If you inherit from the spring-boot-starter-parent POM, the default filter token of the maven-resources-plugins has been changed from ${*} to @ (that is, @maven.token@ instead of ${maven.token}) to prevent conflicts with Spring-style placeholders. If you have enabled Maven filtering for the application.properties directly, you may want to also change the default filter token to use other delimiters.
In this specific case, the port binding works in a PaaS environment such as Heroku or Cloud Foundry. In those two platforms, the PORT environment variable is set automatically and Spring can bind to capitalized synonyms for Environment properties.

2.5. Use YAML for External Properties

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

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

创建一个名为applation.yml的文件,并将其放在类路径的根目录中。然后将Snakeyaml添加到您的依赖项(Maven坐标org.yaml:snakeyaml,如果您使用Spring-boot-starter,就已经包含了)。YAML文件被解析为JavaMap<;字符串、对象(类似于JSON对象),而Spring Boot将映射展平,以便它有一级深度并具有句点分隔的键,就像许多人习惯于使用Java中的Properties文件一样。

前面的示例YAML对应于以下Applation.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特性”部分中的“Feature.html”。

2.6. Set the Active Spring Profiles

SpringEnvironment有一个用于此的API,但您通常需要设置一个系统属性(spring.profiles.active)或一个操作系统环境变量(SpringPROFILES_ACTIVE)。此外,您还可以使用-D参数启动应用程序(请记住将其放在主类或JAR归档文件之前),如下所示:

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

在Spring Boot中,您还可以在Application.Properties中设置活动配置文件,如下例所示:

Properties
Yaml
spring.profiles.active=production
            
            

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

有关更多信息,请参阅“Spring Boot特性”部分中的“ett ures.html”。

2.7. Set the Default Profile Name

默认配置文件是在没有配置文件处于活动状态时启用的配置文件。默认情况下,默认配置文件的名称是Default,但可以使用系统属性(spring.profiles.Default)或操作系统环境变量(Spring_PROFILES_DEFAULT)来更改它。

在Spring Boot中,您还可以在Application.Properties中设置默认配置文件名称,如下例所示:

Properties
Yaml
spring.profiles.default=dev
            
            

有关更多信息,请参阅“Spring Boot特性”部分中的“ett ures.html”。

2.8. Change Configuration Depending on the Environment

Spring Boot支持多文档YAML和属性文件(有关详细信息,请参阅Feature ures.html),这些文件可以根据活动配置文件有条件地激活。

如果文档包含代码键,则配置文件值(以逗号分隔的配置文件列表或配置文件表达式)将被提供给Spring.Accept tsProfiles() spring.config.activate.on-profile>方法。如果配置文件表达式匹配,则该文档将包括在最终合并中(否则不包括),如下例所示:

Properties
Yaml
server.port=9000
#---
spring.config.activate.on-profile=development
server.port=9001
#---
spring.config.activate.on-profile=production
server.port=0
            
            

在上例中,默认端口为9000。但是,如果名为‘Development’的Spring配置文件处于活动状态,则端口为9001。如果‘Products’处于活动状态,则端口为0。

The documents are merged in the order in which they are encountered. Later values override earlier values.

2.9. Discover Built-in Options for External Properties

Spring Boot在运行时将来自Applation.Properties(或.yml文件和其他位置)的外部属性绑定到应用程序。在单个位置中没有(从技术上讲也不可能)列出所有受支持属性的详尽列表,因为贡献可以来自类路径上的其他JAR文件。

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

附录包括一个application.properties示例,其中列出了Spring Boot支持的最常见属性。确定的列表来自于在源代码中搜索@ConfigurationProperties@Value注释,以及偶尔使用活页夹。有关加载属性的确切顺序的详细信息,请参阅“Featureres.html”。

3. Embedded Web Servers

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

3.1. Use Another Web Server

许多Spring Boot启动器都包含默认的嵌入式容器。

  • 对于Servlet堆栈应用程序,SpringBoot-starter-web通过包含Spring-boot-starter-tomcat包括Tomcat,但您可以使用Spring-boot-starter-jettySpring-ot-starter-undertow

  • 对于反应式堆栈应用程序,SpringBoot-starter-webFlux通过包含spring-boot-starter-reactor-netty,来包括反应器Netty,但是您可以使用Spring-Boot-starter-tomcatSpring-Boot-starter-jettySpring-Boot-starter-undertow

当切换到不同的HTTP服务器时,您需要将默认依赖项替换为您需要的依赖项。为了帮助完成这个过程,Spring Boot为每个受支持的HTTP服务器提供了一个单独的启动器。

下面的Maven示例显示如何排除Tomcat而包含Jetty for Spring MVC:

<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>
            
            
The version of the servlet API has been overridden as, unlike Tomcat 9 and Undertow 2, Jetty 9.4 does not support servlet 4.0.

如果您希望使用Jetty 10,它支持Servlet 4.0,则可以按以下示例所示进行操作:

<properties>
    <jetty.version>10.0.8</jetty.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>
    <exclusions>
        <!-- Exclude the Jetty-9 specific dependencies -->
        <exclusion>
            <groupId>org.eclipse.jetty.websocket</groupId>
            <artifactId>websocket-server</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.eclipse.jetty.websocket</groupId>
            <artifactId>javax-websocket-server-impl</artifactId>
        </exclusion>
    </exclusions>
</dependency>
            
            

注意,除了排除Tomcat启动器之外,还需要排除几个特定于Jetty9的依赖项。

下面的Gradle示例配置了必要的依赖项和一个模块替换,以使用Undertow来替换Spring WebFlux的反应器Netty:

dependencies {
    implementation "org.springframework.boot:spring-boot-starter-undertow"
    implementation "org.springframework.boot:spring-boot-starter-webflux"
    modules {
        module("org.springframework.boot:spring-boot-starter-reactor-netty") {
            replacedBy("org.springframework.boot:spring-boot-starter-undertow", "Use Undertow instead of Reactor Netty")
        }
    }
}
            
            
spring-boot-starter-reactor-netty is required to use the WebClient class, so you may need to keep a dependency on Netty even when you need to include a different HTTP server.

3.2. Disabling the Web Server

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

Properties
Yaml
spring.main.web-application-type=none
            
            

3.3. Change the HTTP Port

在独立应用程序中,主HTTP端口默认为8080,但可以使用server.port进行设置(例如,在Applation.Properties中或作为系统属性)。由于Environment值的松散绑定,您还可以使用SERVER_PORT(例如,作为OS环境变量)。

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

有关更多详细信息,请参阅“Spring Boot特性”部分中的“web.html”,或ServerProperties源代码。

3.4. Use a Random Unassigned HTTP Port

要扫描空闲端口(使用操作系统本机来防止冲突),请使用server.port=0

3.5. Discover the HTTP Port at Runtime

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

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

Java
Kotlin
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.boot.test.web.server.LocalServerPort; @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) public class MyWebIntegrationTests { @LocalServerPort int port; // ... } 
            
            

@LocalServerPort@Value(“${local.server.port}”)的元注解。请勿尝试在常规应用程序中插入端口。正如我们刚刚看到的,只有在初始化容器之后才会设置该值。与测试相反,应用程序代码回调被提前处理(在值实际可用之前)。

3.6. Enable HTTP Response Compression

Jetty、Tomcat、Reactive Netty和Undertow支持HTTP响应压缩。可以在Applation.Properties中开启,如下所示:

Properties
Yaml
server.compression.enabled=true
            
            

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

默认情况下,只有当响应的内容类型为以下类型之一时,才会压缩响应:

  • text/html

  • Text/XML

  • 文本/纯文本

  • 文本/css

  • 文本/Java脚本

  • 应用程序/Java脚本

  • 应用程序/json

  • 应用程序/XML

您可以通过设置server.compression.MIME-Types属性来配置此行为。

3.7. Configure SSL

可以通过设置各种server.ssl.*属性来声明性地配置SSL,这些属性通常位于Application.PropertiesApplication.yml中。以下示例显示使用Java密钥库文件设置SSL属性:

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

以下示例显示使用PEM编码的证书和私钥文件设置SSL属性:

Properties
Yaml
server.port=8443
server.ssl.certificate=classpath:my-cert.crt
server.ssl.certificate-private-key=classpath:my-cert.key
server.ssl.trust-certificate=classpath:ca-cert.crt
            
            

有关所有受支持属性的详细信息,请参阅SSL

使用如上所述的配置意味着应用程序不再支持端口8080处的纯HTTP连接器。Spring Boot不支持通过Applation.Properties配置HTTP连接器和HTTPS连接器。如果您想同时拥有两者,则需要以编程方式配置其中一个。我们建议使用Applation.Properties来配置HTTPS,因为在两者中,通过编程配置HTTP连接器更容易。

3.8. Configure HTTP/2

您可以使用server.HTTP2.Enabled配置属性在您的Spring Boot应用程序中启用HTTP/2支持。同时支持h2(TLS上的HTTP/2)和h2c(TCP上的HTTP/2)。若要使用H2,还必须启用SSL。未启用SSL时,将使用h2c。例如,当您的应用程序在执行TLS终止的代理服务器后面运行时,您可能希望使用h2ch2支持的详细信息取决于所选的Web服务器和应用程序环境,因为并非所有JDK 8发行版都现成支持该协议。

3.8.1. HTTP/2 With Tomcat

默认情况下,Spring Boot附带Tomcat 9.0.x,当使用JDK 9或更高版本时,它支持开箱即用的h2ch2。或者,如果libtcative库及其依赖项安装在主机操作系统上,则可以在JDK 8上使用h2

库目录必须对JVM库路径可用(如果尚未提供)。您可以使用jvm参数来实现这一点,比如-Djava.library.path=/usr/local/opt/tomcat-native/lib.有关这方面的更多信息,请参阅Tomcat官方文档

在启用了HTTP/2和SSL的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. HTTP/2 With Jetty

为了支持http/2,Jetty需要额外的org.eclipse.jetty.http2:http2-server依赖项。若要使用h2c,不需要其他依赖项。要使用h2,您还需要根据您的部署选择以下依赖项之一:

  • 适用于在JDK9+上运行的应用程序的org.eclipse.jetty:jetty-alpn-java-server

  • 用于在JDK8u252+上运行的应用程序的org.eclipse.jetty:jetty-alpn-openjdk8-server

  • org.eclipse.jetty:jetty-alpn-conscrypt-server加密库,无需jdk

3.8.3. HTTP/2 With Reactor Netty

默认情况下,SpringBoot-WebFlux-starter使用反应器Netty作为服务器。反应器Netty支持使用JDK 8或更高版本的h2c,不需要额外的依赖项。反应器Netty使用JDK 9或更高版本的JDK支持来支持H2。对于JDK 8环境或最佳运行时性能,该服务器还支持带有本地库的h2。要实现这一点,您的应用程序需要有一个额外的依赖项。

Spring Boot管理io.netty:netty-tcnative-boringssl-static“Uber JAR”的版本,其中包含所有平台的本地库。开发人员可以选择使用分类器仅导入所需的依赖项(参见Netty官方文档)。

3.8.4. HTTP/2 With Undertow

从Undertow 1.4.0+开始,JDK 8支持h2h2c,无需任何额外依赖。

3.9. Configure the Web Server

通常,您应该首先考虑使用众多可用配置密钥中的一个,并通过在Application.PropertiesApplication.yml文件中添加新条目来自定义您的Web服务器。请参阅“了解外部属性的内置选项”)。server.*名称空间在这里非常有用,它包括server.tomcat.*server.jetty.*等名称空间,用于特定于服务器的功能。请参阅应用程序-属性.html的列表。

前面的小节已经介绍了许多常见的用例,比如压缩、SSL语言或HTTP2。您可以声明这样的组件并访问与您的选择相关的服务器工厂:您应该为所选的服务器(Tomcat、Jetty、Reactive Netty、Undertow)和所选的Web堆栈(Servlet或Reactive)选择变体。

下面的示例针对的是带有Spring-boot-starter-web(Servlet堆栈)的Tomcat:

Java
Kotlin
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.stereotype.Component; @Component public class MyTomcatWebServerCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> { @Override public void customize(TomcatServletWebServerFactory factory) { // customize the factory here } } 
            
            
Spring Boot uses that infrastructure internally to auto-configure the server. Auto-configured WebServerFactoryCustomizer beans have an order of 0 and will be processed before any user-defined customizers, unless it has an explicit order that states otherwise.

一旦您使用定制器访问了WebServerFactory,您就可以使用它来配置特定的部分,如连接器、服务器资源或服务器本身--所有这些都使用特定于服务器的API。

此外,Spring Boot还提供:

Server Servlet stack Reactive stack

汤姆猫

TomcatServletWebServerFactory

TomcatReactive WebServerFactory

码头

JettyServletWebServerFactory

JettyReactive WebServerFactory

暗流

UnderowServletWebServerFactory

UnderowReactive WebServerFactory

反应堆

不适用

NettyReactive WebServerFactory

最后,您还可以声明自己的WebServerFactoryBean,它将覆盖由Spring Boot提供的Bean。这样做时,自动配置的定制器仍将应用于您的定制工厂,因此请谨慎使用该选项。

3.10. Add a Servlet, Filter, or Listener to an Application

在Servlet堆栈应用程序中,即使用,有两种方法可以将ServletFilterServletContextListener以及Servlet API支持的其他侦听器添加到您的应用程序中:

3.10.1. Add a Servlet, Filter, or Listener by Using a Spring Bean

要使用Spring Bean添加Servlet筛选器或Servlet*Listener,您必须为其提供@Bean定义。当您想要注入配置或依赖项时,这样做可能非常有用。但是,您必须非常注意它们不会导致太多其他Bean的急切初始化,因为它们必须在应用程序生命周期的非常早的时候安装在容器中。(例如,让它们依赖于您的DataSource或JPA配置不是一个好主意。)您可以通过在第一次使用时延迟初始化Bean来避免此类限制,而不是在初始化时进行。

对于筛选器和Servlet,您还可以通过添加FilterRegistrationBeanServletRegistrationBean来代替或添加基础组件,从而添加映射和初始化参数。

如果筛选器注册没有指定Dispatcher Type,则使用请求。这与Servlet规范的默认调度程序类型一致。

与任何其他Spring Bean一样,您可以定义Servlet过滤器Bean的顺序;请确保查看“web.html部分。

Disable Registration of a Servlet or Filter

正如前面所述,任何ServletFilterBean都会自动注册到Servlet容器。要禁用特定筛选器ServletBean的注册,请为其创建注册Bean并将其标记为已禁用,如下例所示:

Java
Kotlin
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration(proxyBeanMethods = false) public class MyFilterConfiguration { @Bean public FilterRegistrationBean<MyFilter> registration(MyFilter filter) { FilterRegistrationBean<MyFilter> registration = new FilterRegistrationBean<>(filter); registration.setEnabled(false); return registration; } } 
              
              

3.10.2. Add Servlets, Filters, and Listeners by Using Classpath Scanning

@WebServlet@WebFilter@WebListener注释类可以自动注册到嵌入的Servlet容器中,方法是使用@ServletComponentScan注释@Configuration类并指定包含您要注册的组件的包。默认情况下,@ServletComponentScan从带注释的类的包扫描。

3.11. Configure Access Logging

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

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

Properties
Yaml
server.tomcat.basedir=my-tomcat
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%t %a %r %s (%D ms)
            
            
The default location for logs is a logs directory relative to the Tomcat base directory. By default, the logs directory is a temporary directory, so you may want to fix Tomcat’s base directory or use an absolute path for the logs. In the preceding example, the logs are available in my-tomcat/logs relative to the working directory of the application.

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

Properties
Yaml
server.undertow.accesslog.enabled=true
server.undertow.accesslog.pattern=%t %a %r %s (%D ms)
server.undertow.options.server.record-request-start-time=true
            
            

请注意,除了启用访问日志记录并配置其模式外,还启用了记录请求开始时间。在访问日志模式中包括响应时间(%D)时,这是必需的。日志存储在相对于应用程序工作目录的Logs目录中。您可以通过设置server.underow.acceslog.dir属性来自定义此位置。

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

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

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

3.12. Running Behind a Front-end Proxy Server

如果您的应用程序在代理、负载均衡器或云中运行,则请求信息(如主机、端口、方案…花旗集团(​:行情)可能会在此过程中发生变化.您的应用程序可能运行在10.10.10.10:8080上,但HTTP客户端应该只看到example.org

RFC7239“Forwarded Headers”定义ForwardedHTTP标头;代理可以使用该标头来提供有关原始请求的信息。您可以将应用程序配置为读取这些头文件,并在创建链接并将它们以HTTP302响应、JSON文档或HTML页面的形式发送给客户端时自动使用这些信息。还有非标准标头,如X-Forwarded-HostX-Forwarded-PortX-Forwarded-ProtoX-Forwarded-SSLX-Forwarded-Prefix

如果代理添加了常用的X-Forwarded-ForX-Forwarded-Proto头,则将server.Forward-Headers-Strategy设置为原生就足以支持它们。使用此选项,Web服务器本身本身就支持此功能;您可以查看其特定文档以了解特定行为。

如果这还不够,Spring框架提供了一个ForwardedHeaderFilter。您可以将其注册为应用程序中的Servlet过滤器,方法是将server.ward-Headers-Strategy设置为框架

If you are using Tomcat and terminating SSL at the proxy, server.tomcat.redirect-context-root should be set to false. This allows the X-Forwarded-Proto header to be honored before any redirects are performed.
If your application runs in Cloud Foundry or Heroku, the server.forward-headers-strategy property defaults to NATIVE. In all other instances, it defaults to NONE.

3.12.1. Customize Tomcat’s Proxy Configuration

如果您使用Tomcat,则可以额外配置用于携带转发信息的Header的名称,如下例所示:

Properties
Yaml
server.tomcat.remoteip.remote-ip-header=x-your-remote-ip-header
server.tomcat.remoteip.protocol-header=x-your-protocol-header
             
             

Tomcat还配置了一个正则表达式,该表达式与要信任的内部代理相匹配。有关其默认值,请参阅附录中的server.tomcat.remoteip.internal-proxies条目。您可以通过向Applation.Properties添加条目来自定义阀门的配置,如下例所示:

Properties
Yaml
server.tomcat.remoteip.internal-proxies=192\\.168\\.\\d{1,3}\\.\\d{1,3}
             
             
You can trust all proxies by setting the internal-proxies to empty (but do not do so in production).

您可以通过关闭自动的RemoteIpValve来完全控制Tomcat的RemoteIpValve的配置(为此,设置server.forward-headers-strategy=NONE)并使用WebServerFactoryCustomizerBean添加一个新的阀实例。

3.13. Enable Multiple Connectors with Tomcat

您可以在<org.apache.catalina.connector.Connector>TomcatServletWebServerFactory中添加一个连接器,可以支持多个连接器,包括http和HTTPS连接器,如下例所示:

Java
Kotlin
import org.apache.catalina.connector.Connector; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration(proxyBeanMethods = false) public class MyTomcatConfiguration { @Bean public WebServerFactoryCustomizer<TomcatServletWebServerFactory> connectorCustomizer() { return (tomcat) -> tomcat.addAdditionalTomcatConnectors(createConnector()); } private Connector createConnector() { Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol"); connector.setPort(8081); return connector; } } 
            
            

3.14. Enable Tomcat’s MBean Registry

默认情况下,Embedded Tomcat的MBean注册表处于禁用状态。这最大限度地减少了Tomcat的内存占用。例如,如果要使用Tomcat的MBean,以便微米可以使用它们来公开指标,则必须使用server.tomcat.mbeanregistry.enabled属性来执行此操作,如下例所示:

Properties
Yaml
server.tomcat.mbeanregistry.enabled=true
            
            

3.15. Enable Multiple Listeners with Undertow

UnderowServletWebServerFactory添加一个UnderTower BuilderCustomizer,向Builder添加一个监听器,如下例所示:

Java
Kotlin
import io.undertow.Undertow.Builder; import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration(proxyBeanMethods = false) public class MyUndertowConfiguration { @Bean public WebServerFactoryCustomizer<UndertowServletWebServerFactory> undertowListenerCustomizer() { return (factory) -> factory.addBuilderCustomizers(this::addHttpListener); } private Builder addHttpListener(Builder builder) { return builder.addHttpListener(8080, "0.0.0.0"); } } 
            
            

3.16. Create WebSocket Endpoints Using @ServerEndpoint

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

Java
Kotlin
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter; @Configuration(proxyBeanMethods = false) public class MyWebSocketConfiguration { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } } 
            
            

上例中显示的Bean向底层WebSocket容器注册任何@ServerEndpoint注释的Bean。当部署到独立的Servlet容器时,此角色由Servlet容器初始值设定项执行,ServerEndpointExporterBean不是必需的。

4. Spring MVC

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

4.1. Write a JSON REST Service

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

Java
Kotlin
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class MyController { @RequestMapping("/thing") public MyThing thing() { return new MyThing(); } } 
            
            

只要Mything可以由Jackson2序列化(对于普通的POJO或Groovy对象为真),localhost:8080/thing默认情况下提供它的JSON表示。请注意,在浏览器中,您有时可能会看到XML响应,因为浏览器倾向于发送首选XML的Accept标头。

4.2. Write an XML REST Service

如果类路径上有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,如下例所示:

Java
Kotlin
import jakarta.xml.bind.annotation.XmlRootElement; @XmlRootElement public class MyThing { private String name;  // getters/setters ...  public String getName() { return this.name; } public void setName(String name) { this.name = name; } } 
            
            

您需要确保JAXB库是项目的一部分,例如,通过添加:

<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
</dependency>
            
            
To get the server to render XML instead of JSON, you might have to send an Accept: text/xml header (or use a browser).

4.3. Customize the 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中)中进行了描述,它们映射到环境中的属性:

Enum Property Values

com.fasterxml.jackson.databind.DeserializationFeature

spring.jackson.deserialization.<;feature_name>;

TrueFalse

com.fasterxml.jackson.core.JsonGenerator.Feature

spring.jackson.generator.<;feature_name>;

TrueFalse

com.fasterxml.jackson.databind.MapperFeature

spring.jackson.mapper.<;feature_name>;

TrueFalse

com.fasterxml.jackson.core.JsonParser.Feature

spring.jackson.parser.<;feature_name>;

TrueFalse

com.fasterxml.jackson.databind.SerializationFeature

spring.jackson.serialization.<;feature_name>;

TrueFalse

com.fasterxml.jackson.annotation.JsonInclude.Include

spring.jackson.default-property-inclusion

始终非空值非缺省非默认非空

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

此基于环境的配置应用于自动配置的Jackson2ObjectMapperBuilderBean,并应用于使用构建器创建的任何映射器,包括自动配置的ObjectMapperBean。

上下文的Jackson2ObjectMapperBuilder可以由一个或多个Jackson2ObjectMapperBuilderCustomizerBean自定义。这样的定制器Bean可以订购(Boot自己的定制器的顺序为0),允许在Boot的定制之前和之后应用额外的定制。

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

如果您想要完全替换默认的对象映射器,可以定义该类型的@Bean并将其标记为@Primary,或者,如果您更喜欢基于构建器的方法,则定义一个Jackson2ObjectMapperBuilder@Bean。请注意,在任何一种情况下,这样做都会禁用对象映射器的所有自动配置。

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

有关更多详细信息,请参阅定制@ResponseBody呈现一节和WebMvcAutoConfiguration源代码。

4.4. Customize the @ResponseBody Rendering

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

与正常的MVC使用一样,您提供的任何WebMvcConfigurerBean也可以通过覆盖figureMessageConverters方法来提供转换器。然而,与普通的MVC不同,您只能提供所需的附加转换器(因为Spring Boot使用相同的机制来提供其缺省值)。最后,如果您通过提供自己的@EnableWebMvc配置退出了Spring Boot默认MVC配置,则可以完全控制并通过使用WebMvcConfigurationSupport中的getMessageConverters手动完成所有操作。

有关更多详细信息,请参阅WebMvcAutoConfiguration源代码。

4.5. Handling Multipart File Uploads

Spring Boot采用Servlet 5jakarta.servlet.http.PartAPI来支持文件上传。默认情况下,Spring Boot将Spring MVC配置为每个文件的最大大小为1MB,单个请求中的文件数据最大为10MB。您可以使用MultipartProperties类中公开的属性来覆盖这些值、存储中间数据的位置(例如,存储到/tmp目录中)和数据刷新到磁盘的阈值。例如,如果要指定文件不受限制,请将spring.servlet.multipart.max-file-size属性设置为<代码>-1

当您希望在Spring MVC控制器处理程序方法中将多部分编码文件数据作为@RequestParam类型的带注释的参数MultipartFile接收时,多部分支持很有帮助。

有关更多详细信息,请参阅MultipartAutoConfiguration源代码。

It is recommended to use the container’s built-in support for multipart uploads rather than introducing an additional dependency such as Apache Commons File Upload.

4.6. Switch Off the Spring MVC DispatcherServlet

默认情况下,所有内容都从应用程序的根(/)提供。如果您希望映射到其他路径,则可以按如下方式配置一条路径:

Properties
Yaml
spring.mvc.servlet.path=/mypath
            
            

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

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

4.7. Switch off the Default MVC Configuration

完全控制MVC配置的最简单方法是为您自己的@configuration提供@EnableWebMvc注释。这样做会让您掌握所有MVC配置。

4.8. Customize ViewResolvers

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

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

  • 名为“defaultViewResolver”的InternalResourceViewResolver。它定位可以使用DefaultServlet呈现的物理资源(包括静态资源和JSP页面,如果您使用它们的话)。它将前缀和后缀应用于视图名,然后在Servlet上下文中查找具有该路径的物理资源(缺省值均为空,但可通过spring.mvc.view.prefixspring.mvc.view.Suffix进行外部配置)。您可以通过提供相同类型的Bean来覆盖它。

  • 名为‘beanNameViewResolver’的BeanNameViewResolver。这是视图解析器链中有用的成员,并获取与被解析的视图同名的任何Bean。应该没有必要覆盖或替换它。

  • 仅当实际存在View类型的Bean时,才会添加名为“”viewResolver“”的Content NeatheratingViewResolver。“”这是一个复合解析器,委托给所有其他解析器,并尝试查找与客户端发送的‘Accept’HTTP头匹配的内容。有一个关于ContentNegotiatingViewResolver的有用的博客,您可能想要学习它以了解更多,您也可以查看源代码以获取详细信息。您可以通过定义一个名为‘viewResolver’的Bean来关闭自动配置的ContentNeatheratingViewResolver

  • 如果您使用Thymeleaf,您还拥有一个名为‘ThymeleafViewResolver’的ThymeleafViewResolver。它通过用前缀和后缀将视图名括起来来查找资源。前缀为spring.thoreleaf.prefix,后缀为spring.thoreleaf.Suffix。前缀和后缀的值默认为‘classpath:/plates/’和‘.html’。您可以通过提供同名的Bean来覆盖ThymeleafViewResolver

  • 如果您使用的是FreeMarker,则还会有一个名为“freMarkerViewResolver”的FreeMarkerViewResolver。它通过使用前缀和后缀将视图名括起来,在加载器路径(外部化到spring.freemarker.templateLoaderPath,缺省值为‘classpath:/Templates/’)中查找资源。前缀被外部化为spring.freemarker.prefix,后缀外部化为spring.freemarker.Suffix。前缀和后缀的默认值分别为空和‘.ftlh’。您可以通过提供同名的Bean来覆盖FreeMarkerViewResolver

  • 如果您使用Groovy模板(实际上,如果您的类路径上有groovy-plates),那么您还有一个名为‘groovyMarkupViewResolver’的GroovyMarkupViewResolver。它通过将视图名加上前缀和后缀(外部化为spring.groovy.template.prefixspring.groovy.template.Suffix)来查找加载器路径中的资源。前缀和后缀的缺省值分别为‘classpath:/plates/’和‘.tpl’。您可以通过提供同名的Bean来覆盖GroovyMarkupViewResolver

  • 如果您使用Mustache,您还将拥有一个名为‘mustaheViewResolver’的MustaheViewResolver。它通过用前缀和后缀将视图名括起来来查找资源。前缀为spring.musta he.prefix,后缀为spring.musta he.Suffix。前缀和后缀的值默认为‘classpath:/Templates/’和‘.masache’。您可以通过提供同名的Bean来覆盖MustaheViewResolver

有关更多详细信息,请参阅以下各节:

5. Jersey

5.1. Secure Jersey endpoints with Spring Security

Spring Security可以用来保护基于Jersey的Web应用程序的安全,就像它可以用来保护基于Spring MVC的Web应用程序一样。但是,如果您希望在Jersey中使用Spring Security的方法级安全性,则必须将Jersey配置为使用setStatus(Int)而不是sendError(Int)。这可以防止Jersey在Spring Security有机会向客户端报告身份验证或授权失败之前提交响应。

必须在应用程序的资源配置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)); } } 
            
            

5.2. Use Jersey Alongside Another Web Framework

要将Jersey与其他Web框架(如Spring MVC)一起使用,应该对其进行配置,以便允许其他框架处理它无法处理的请求。首先,通过将spring.Jersey.type应用程序属性的值配置为Filter,将Jersey配置为使用筛选器而不是Servlet。其次,配置您的资源配置以转发可能导致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); } } 
            
            

6. HTTP Clients

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

6.1. Configure RestTemplate to Use a Proxy

io.html中所述,您可以使用RestTemplateCustomizerRestTemplateBuilder来构建定制的RestTemplateCustomizer。这是创建配置为使用代理的RestTemplate的推荐方法。

代理配置的确切细节取决于正在使用的底层客户端请求工厂。

6.2. Configure the TcpClient used by a Reactor Netty-based WebClient

当反应器Netty位于类路径上时,将自动配置基于反应器Netty的WebClient。要定制客户端对网络连接的处理,请提供一个ClientHttpConnectorBean。以下示例配置60秒连接超时并添加ReadTimeoutHandler

Java
Kotlin
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.reactive.ClientHttpConnector; import org.springframework.http.client.reactive.ReactorClientHttpConnector; import org.springframework.http.client.reactive.ReactorResourceFactory; @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); } } 
            
            
Note the use of ReactorResourceFactory for the connection provider and event loop resources. This ensures efficient sharing of resources for the server receiving requests and the client making requests.

7. Logging

除了Commons Logging API之外,Spring Boot没有强制的日志依赖项,该API通常由Spring框架的Spring-JCL模块提供。要使用Logback,您需要在类路径中包含它和Spring-JCL。推荐的方法是通过启动器,它们都依赖于Spring-ot-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可用,则它是首选。

如果您需要对日志记录进行的唯一更改是设置各种记录器的级别,则可以在Application.Properties中使用“logging.Level”前缀来执行此操作,如下例所示:

Properties
Yaml
logging.level.org.springframework.web=debug
logging.level.org.hibernate=error
           
           

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

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

7.1. Configure Logback for Logging

如果您需要对Logback应用定制,而不是使用Application.Properties可以实现的定制,则需要添加一个标准的Logback配置文件。您可以将logback.xml文件添加到类路径的根目录中,以供Logback查找。如果您想要使用Spring Boot Logback扩展,还可以使用logback-spring.xml

The Logback documentation has a dedicated section that covers configuration in some detail.

Spring Boot提供了许多可以包含在您自己的配置中的Logback配置。这些包含旨在允许重新应用某些常见的Spring Boot约定。

org/springframework/boot/logging/logback/:下提供了以下文件

  • defaults.xml-提供转换规则、模式属性和通用记录器配置。

  • ConsoleAppendder.xml-使用控制台_日志_模式添加ConsoleAppender

  • 使用FILE_LOG_PatternsRolling_FILE_NAME_Pattern添加一个RollingFileAppender

此外,为了与早期版本的Spring Boot兼容,还提供了一个遗留的base.xml文件。

典型的自定义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负责为您创建的系统属性:

  • ${id}:当前进程ID。

  • ${log_file}:是否在Boot的外部配置中设置了logging.file.name

  • ${LOG_PATH}:是否在Boot的外部配置中设置了logging.file.path(表示存放日志文件的目录)。

  • ${LOG_EXCEPTION_CONVERSION_WORD}:是否在引导的外部配置中设置了logging.exception-conversion-word

  • ${ROLING_FILE_NAME_PROPERT}:是否在Boot的外部配置中设置了logging.pattern.rolling-file-name

通过使用定制的Logback转换器,Spring Boot还在控制台上(但不是在日志文件中)提供一些不错的ANSI色彩终端输出。有关示例,请参阅defaults.xml配置中的控制台_日志_模式

如果Groovy位于类路径上,您也应该能够使用logback.groovy配置Logback。如果存在,则优先考虑此设置。

Spring extensions are not supported with Groovy configuration. Any logback-spring.groovy files will not be detected.

7.1.1. Configure Logback for File-only Output

如果要禁用控制台日志记录并仅将输出写入文件,则需要一个自定义Logback-spring.xml,该文件可导入文件-appendder.xml,但不能导入控制台-appendder.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添加到您的applation.Propertiesapplation.yaml中,如下例所示:

Properties
Yaml
logging.file.name=myapplication.log
             
             

7.2. Configure Log4j for Logging

如果位于类路径上,Spring Boot支持Log4j 2进行日志配置。如果使用启动器组装依赖项,则必须排除Logback,然后改为包含log4j 2。如果您不使用启动器,那么除了Log4j2之外,您还需要(至少)提供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 Starter的依赖项,并告诉Gradle,任何出现的默认日志记录Starter都应替换为Log4j 2 Starter,如下例所示:

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")
        }
    }
}
            
            
The Log4j starters gather together the dependencies for common logging requirements (such as having Tomcat use java.util.logging but configuring the output using Log4j 2).
To ensure that debug logging performed using java.util.logging is routed into Log4j 2, configure its JDK logging adapter by setting the java.util.logging.manager system property to org.apache.logging.log4j.jul.LogManager.

7.2.1. Use YAML or JSON to Configure Log4j 2

除了默认的XML配置格式,Log4j 2还支持YAML和JSON配置文件。要将Log4j 2配置为使用替代配置文件格式,请将适当的依赖项添加到类路径,并命名配置文件以匹配您选择的文件格式,如下例所示:

Format Dependencies File names

YAML

com.fasterxml.jackson.core:jackson-databind+com.fasterxml.jackson.dataformat:jackson-dataformat-yaml

log4j2.yaml+log4j2.yml

杰森

com.fasterxml.jackson.core:jackson-databind

log4j2.json+log4j2.jsn

7.2.2. Use Composite Configuration to Configure Log4j 2

Log4j 2支持将多个配置文件组合到单个复合配置中。要在Spring Boot中使用此支持,请使用一个或多个辅助配置文件的位置来配置logging.log4j2.config.over。辅助配置文件将与主配置合并,无论主配置的源是Spring Boot的缺省值、标准位置(如log4j.xml)还是由logging.config属性配置的位置。

8. Data Access

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

8.1. Configure a Custom DataSource

要配置您自己的DataSource,请在您的配置中定义该类型的@Bean。Spring Boot在任何需要的地方重用您的DataSource,包括数据库初始化。如果您需要外部化某些设置,您可以将DataSource绑定到环境(请参阅“Featureres.html”)。

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

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

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

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

假设SomeDataSource具有URL、用户名和池大小的常规JavaBean属性,则在DataSource可用于其他组件之前自动绑定这些设置。

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

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

Java
Kotlin
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数据源:

Properties
Yaml
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属性)。在这种情况下,您必须重写配置,如下所示:

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

您可以通过强制连接池使用并返回专用实现而不是DataSource来修复该问题。您不能在运行时更改实现,但选项列表将是明确的。

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

Java
Kotlin
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-URL,即在没有提供URL的情况下提供具有合理用户名和密码的默认嵌入式数据库。您可以很容易地从任何DataSourceProperties对象的状态初始化DataSourceBuilder,因此您还可以注入Spring Boot自动创建的数据源。但是,这会将您的配置分成两个名称空间:url用户名密码typespring.data ource上的驱动程序,其余的在您的自定义名称空间(app.datource)上。为避免出现这种情况,您可以在自定义命名空间上重新定义自定义DataSourceProperties,如下例所示:

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

此设置使与Spring Boot在默认情况下为您执行的操作保持同步,只是(在代码中)选择了一个专用连接池,并且其设置在app.datource.configuration子名称空间中公开。由于DataSourceProperties会为您处理url/jdbcUrl翻译,因此您可以按如下方式进行配置:

Properties
Yaml
app.datasource.url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.configuration.maximum-pool-size=30
            
            
Spring Boot will expose Hikari-specific settings to spring.datasource.hikari. This example uses a more generic configuration sub namespace as the example does not support multiple datasource implementations.
Because your custom configuration chooses to go with Hikari, app.datasource.type has no effect. In practice, the builder is initialized with whatever value you might set there and then overridden by the call to .type().

有关更多详细信息,请参阅“Spring Boot特性”部分中的“data.htmlDataSourceAutoConfiguration类。

8.2. Configure Two DataSources

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

如果您创建自己的DataSource,自动配置就会退出。在以下示例中,我们提供了与自动配置在主数据源上提供的完全相同的功能集:

Java
Kotlin
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 has to be flagged as @Primary so that the database initializer feature uses your copy (if you use the initializer).

这两个数据源还绑定了高级定制。例如,您可以按如下方式配置它们:

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

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

Java
Kotlin
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在自动配置中使用的相同逻辑在自定义命名空间上配置两个数据源。请注意,每个配置子命名空间都提供基于所选实现的高级设置。

8.3. Use Spring Data Repositories

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

对于许多应用程序,您所需要的就是将正确的Spring数据依赖项放在类路径上。有针对JPA的Spring-ot-starter-data-jpa,针对MongoDB的Spring-ot-starter-data-MongoDB,以及用于支持的技术的各种其他启动器。首先,创建一些存储库接口来处理您的@Entity对象。

Spring Boot试图根据它找到的@EnableAutoConfiguration猜测@Repository定义的位置。要获得更多控制,请使用@EnableJpaRepositories注释(来自Spring data JPA)。

有关Spring数据的更多信息,请参阅Spring data项目页面

8.4. Separate @Entity Definitions from Spring Configuration

Spring Boot根据它找到的@EnableAutoConfiguration尝试猜测@EnableEntity定义的位置。要获得更多控制,可以使用@EntityScan注释,如下例所示:

Java
Kotlin
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 { // ... } 
            
            

8.5. Configure JPA Properties

Spring data JPA已经提供了一些独立于供应商的配置选项(比如用于SQL日志记录的选项),而Spring Boot将这些选项和一些更多的Hibernate选项公开为外部配置属性。其中一些是根据上下文自动检测的,因此您应该不必设置它们。

spring.jpa.hibernate.ddl-auto是一个特例,因为根据运行时条件的不同,它具有不同的缺省值。如果使用嵌入式数据库,并且没有模式管理器(如Liquibase或Flyway)正在处理DataSource,则默认为Create-Drop。在所有其他情况下,它默认为None

要使用的方言由JPA提供程序检测。如果您希望自己设置方言,请设置spring.jpa.database-Platform属性。

要设置的最常见选项如下例所示:

Properties
Yaml
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将不会应用该设置。

If you need to apply advanced customization to Hibernate properties, consider registering a HibernatePropertiesCustomizer bean that will be invoked prior to creating the EntityManagerFactory. This takes precedence to anything that is applied by the auto-configuration.

8.6. Configure Hibernate Naming Strategy

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

默认情况下,Spring Boot使用CamelCaseToUnderscoresNamingStrategy.配置物理命名策略使用这种策略,所有的点都被下划线取代,驼峰大小写也被下划线取代。此外,默认情况下,所有表名都以小写形式生成。例如,TelephoneNumber实体被映射到Telephone_Number表。如果您的架构需要大小写混合的标识符,请定义一个自定义CamelCaseToUnderscoresNamingStrategyBean,如下例所示:

Java
Kotlin
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 5的默认设置,请设置以下属性:

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

或者,您可以配置以下Bean:

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

8.7. Configure Hibernate Second-Level Caching

要使用jCache来实现这一点,首先要确保类路径上有可用的org.hibernate.orm:hibernate-jcache。然后,添加一个HibernatePropertiesCustomizerBean,如下例所示:

Java
Kotlin
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用户指南

8.8. Use Dependency Injection in Hibernate Components

默认情况下,Spring Boot注册一个使用BeanFactoryBeanContainer实现,以便转换器和实体侦听器可以使用常规的依赖项注入。

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

8.9. Use a Custom EntityManagerFactory

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

8.10. Using Multiple EntityManagerFactories

如果您需要对多个数据源使用JPA,则每个数据源可能需要一个EntityManagerFactory。来自Spring ORM的代码允许您根据需要配置<LocalContainerEntityManagerFactoryBean>EntityManager Factory。您还可以重用JpaProperties来绑定每个EntityManagerFactory的设置,如下例所示:

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

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

When you create a bean for LocalContainerEntityManagerFactoryBean yourself, any customization that was applied during the creation of the auto-configured LocalContainerEntityManagerFactoryBean is lost. For example, in case of Hibernate, any properties under the spring.jpa.hibernate prefix will not be automatically applied to your LocalContainerEntityManagerFactoryBean. If you were relying on these properties for configuring things like the naming strategy or the DDL mode, you will need to explicitly configure that when creating the LocalContainerEntityManagerFactoryBean bean.

您应该为需要JPA访问的任何其他数据源提供类似的配置。为了完成这幅图,您还需要为每个EntityManagerFactory配置一个JpaTransactionManager。或者,您也可以使用跨两者的JTA事务管理器。

如果您使用的是Spring数据,则需要相应地配置@EnableJpaRepositories,如下例所示:

Java
Kotlin
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 { } 
            
            
Java
Kotlin
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 { } 
            
            

8.11. Use a Traditional persistence.xml File

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

有关默认设置,请参阅JpaBaseConfiguration

8.12. Use Spring Data JPA and Mongo Repositories

Spring data JPA和Spring data Mongo都可以自动为您创建Repository实现。如果它们都出现在类路径上,您可能需要做一些额外的配置来告诉Spring Boot要创建哪个存储库。要做到这一点,最明确的方法是使用标准的Spring数据@EnableJpaRepositories@EnableMongoRepositories注释,并提供Repository接口的位置。

还有标志(spring.data.*.repositories.enabledspring.data.*.repositories.type,您可以使用它们在外部配置中打开和关闭自动配置的存储库。例如,如果您想要关闭Mongo存储库而仍然使用自动配置的MongoTemplate,这样做很有用。

对于其他自动配置的Spring数据存储库类型(Elasticearch、Solr等),也存在相同的障碍和相同的功能。要使用它们,请相应地更改注释和标志的名称。

8.13. Customize Spring Data’s Web Support

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

8.14. Expose Spring Data Repositories as REST Endpoint

只要为应用程序启用了Spring MVC,Spring data rest可以将Repository实现公开为您的REST端点。

Spring Boot公开了一组有用的属性(来自 RepositoryRestConfiguration.>spring.data.rest命名空间),用于定制 RepositoryRestConfigurerBean。

If you do not specify any order on your custom RepositoryRestConfigurer, it runs after the one Spring Boot uses internally. If you need to specify an order, make sure it is higher than 0.

8.15. Configure a Component that is Used by JPA

如果您想要配置JPA使用的组件,那么您需要确保在JPA之前初始化该组件。当组件被自动配置时,Spring Boot会为您处理这一点。例如,当Flyway被自动配置时,Hibernate被配置为依赖于Flyway,这样Flyway就有机会在Hibernate尝试使用它之前初始化数据库。

如果您自己配置组件,则可以使用EntityManagerFactoryDependsOnPostProcessor子类作为设置必要依赖项的便捷方法。例如,如果您使用Hibernate Search并将Elasticearch作为其索引管理器,则必须将任何EntityManagerFactoryBean配置为依赖于弹性搜索客户端Bean,如下例所示:

Java
Kotlin
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"); } } 
            
            

8.16. Configure jOOQ with Two DataSources

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

In particular, JooqExceptionTranslator and SpringTransactionProvider can be reused to provide similar features to what the auto-configuration does with a single DataSource.

9. Database Initialization

根据堆栈的不同,可以以不同的方式初始化SQL数据库。当然,您也可以手动完成此操作,前提是数据库是一个单独的进程。建议使用单一的模式生成机制。

9.1. Initialize a Database Using JPA

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

  • spring.jpa.Generate-ddl(Boolean)打开和关闭该功能,并且独立于供应商。

  • spring.jpa.hibernate.ddl-auto(Enum)是一个Hibernate特性,它以更细粒度的方式控制行为。本指南后面将更详细地介绍此功能。

9.2. Initialize a Database Using Hibernate

您可以显式设置spring.jpa.hibernate.ddl-auto,标准的Hibernate属性值为NoneValidupdatecreateCreate-Drop。Spring Boot根据它是否认为您的数据库是嵌入式的来为您选择一个缺省值。如果没有检测到模式管理器,则默认为Create-Drop,否则默认为None。通过查看连接类型和JDBC url来检测嵌入式数据库。hsqldbh2derby是候选代码,而其他代码不是。从内存中切换到“真实”数据库时要小心,不要对新平台中是否存在表和数据做出假设。您必须显式设置DDL-AUTO,或者使用其他机制之一来初始化数据库。

You can output the schema creation by enabling the org.hibernate.SQL logger. This is done for you automatically if you enable the debug mode.

此外,如果Hibernate从头开始创建模式(也就是,如果DDL-AUTO属性设置为CREATECREATE-DROP),则类路径根目录中名为port.sql的文件将在启动时执行。如果您仔细的话,这对于演示和测试可能很有用,但您可能不希望出现在生产中的类路径上。它是一种休眠特性(与Spring无关)。

9.3. Initialize a Database Using Basic SQL Scripts

Spring Boot可以自动创建JDBCDataSource或R2DBCConnectionFactory的模式(DDL脚本)并对其进行初始化(DML脚本)。它从标准的根类路径位置加载SQL:schema.sqldata.sql。此外,Spring Boot还处理架构-${Platform}.SQLdata-${Platform}.SQL文件(如果存在),其中Platformspring.sql.init.Platform的值。这允许您在必要时切换到特定于数据库的脚本。例如,您可以选择将其设置为数据库的供应商名称(hsqldbh2OracleMySQLPostgreSQL等)。默认情况下,仅在使用嵌入式内存数据库时才执行SQL数据库初始化。要始终初始化SQL数据库,而不考虑其类型,请将spring.sql.init.mode设置为Always。同样,要禁用初始化,请将spring.sql.init.mode设置为Never。默认情况下,Spring Boot启用其基于脚本的数据库初始化器的快速故障特性。这意味着,如果脚本导致异常,应用程序将无法启动。您可以通过设置spring.sql.init.continue-on-error.来调整该行为

默认情况下,基于脚本的DataSource初始化在创建任何JPAEntityManagerFactoryBean之前执行。schema.sql可以用来为JPA管理的实体创建模式,data.sql可以用来填充它。虽然我们不建议使用多种数据源初始化技术,但如果您希望基于脚本的<代码>数据源 初始化能够在Hibernate执行的架构创建的基础上构建,请将spring.jpa.defer-datasource-initialization设置为<代码>真 。这将推迟数据源初始化,直到创建并初始化任何EntityManagerFactoryBean之后。然后,可以使用schema.sql向Hibernate执行的任何模式创建添加内容,并且data.sql可以用来填充它。

如果您使用的是更高级的数据库迁移工具,如Flyway或Liquibase,则应该单独使用它们来创建和初始化模式。不建议在Flyway或Liquibase中使用基本的schema.sqldata.sql脚本,并且在未来的版本中将不再支持。

9.4. Initialize a Spring Batch Database

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

Properties
Yaml
spring.batch.jdbc.initialize-schema=always
            
            

您还可以通过将spring.batch.jdbc.initialize-schema设置为Never显式关闭初始化。

9.5. Use a Higher-level Database Migration Tool

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

9.5.1. Execute Flyway Database Migrations on Startup

要在启动时自动运行Flyway数据库迁移,请将org.flywaydb:flyway-core添加到类路径中。

通常,迁移是V<;VERSION>;__<;NAME>;.sql形式的脚本(使用<代码><;版本&> 一个下划线分隔的版本,如‘1’或‘2_1’)。默认情况下,它们位于名为classpath:db/Migration的目录中,但您可以通过设置spring.flyway.Locations来修改该位置。这是一个或多个类路径:文件系统:位置的逗号分隔列表。例如,以下配置将在默认类路径位置和/opt/Migration目录中搜索脚本:

Properties
Yaml
spring.flyway.locations=classpath:db/migration,filesystem:/opt/migration
             
             

您还可以添加特殊的{供应商}占位符以使用供应商特定的脚本。假设以下情况:

Properties
Yaml
spring.flyway.locations=classpath:db/migration/{vendor}
             
             

上面的配置没有使用db/Migration,而是根据数据库的类型设置要使用的目录(例如db/Migration/MySQL用于MySQL)。支持的数据库列表位于DatabaseDriver中。

迁移也可以用Java编写。Flyway将使用实现JavaMigration的任何Bean自动配置。

Flyway Properties提供了Flyway的大部分设置和一小部分可用于禁用迁移或关闭位置检查的附加属性。如果您需要对配置进行更多控制,请考虑注册Flyway ConfigurationCustomizerBean。

Spring Boot调用Flyway.Migrate()来执行数据库迁移。如果您想要更多控制,请提供实现 FlywayMigrationStrategy.>的<代码>@Bean

Flyway支持SQL和Java回调。要使用基于SQL的回调,请将回调脚本放在classpath:db/Migration目录中。要使用基于Java的回调,请创建一个或多个实现回调的Bean。任何此类Bean都会自动注册到Flyway。可以使用@Order或通过实现Ordered对它们进行排序。也可以检测到实现已弃用的Flyway Callback接口的Bean,但是它们不能与回调Bean一起使用。

默认情况下,Flyway自动生成上下文中的(@Primary)DataSource,并将其用于迁移。如果您想使用不同的DataSource,您可以创建一个,并将其@Bean标记为@FlywayDataSource。如果这样做并且需要两个数据源,请记住创建另一个数据源,并将其标记为@Primary。或者,您也可以通过在外部属性中设置spring.flyway.[URL,User,Password]来使用Flyway的原生DataSource。设置spring.flyway.urlspring.flyway.user足以使Flyway使用其自己的数据源。如果尚未设置这三个属性中的任何一个,则将使用其等效的spring.datource属性的值。

您还可以使用Flyway为特定场景提供数据。例如,您可以将特定于测试的迁移放在src/test/resource中,并且它们仅在您的应用程序启动测试时运行。此外,您还可以使用特定于配置文件的配置来自定义spring.flyway.Locations,以便某些迁移仅在特定配置文件处于活动状态时运行。例如,在application-dev.properties中,您可以指定以下设置:

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

通过该设置,dev/db/Migration中的迁移仅在dev配置文件处于活动状态时运行。

9.5.2. Execute Liquibase Database Migrations on Startup

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

当您向类路径添加org.iquubase:iquibase-core时,默认情况下,在应用程序启动期间和测试运行之前都会运行数据库迁移。通过使用spring.iquibase.Enabled属性,在maintest配置中设置不同的值,可以自定义此行为。不可能使用两种不同的方法来初始化数据库(例如,Liquibase用于应用程序启动,JPA用于测试运行)。

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

默认情况下,Liquibase自动生成上下文中的(@Primary)DataSource,并将其用于迁移。如果您需要使用不同的数据源,您可以创建一个,并将其@Bean标记为@Liquibase DataSource。如果这样做并且需要两个数据源,请记住创建另一个数据源,并将其标记为@Primary。或者,您也可以使用Liquibase的原生DataSource,方法是在外部属性中设置spring.iquibase.[DRIVER-CLASS-NAME,URL,USER,PASSWORD]。设置spring.iquibase.urlspring.iqubase.user足以使Liquibase使用其自己的DataSource。如果尚未设置这三个属性中的任何一个,则将使用其等效的spring.datource属性的值。

有关上下文、默认模式等可用设置的详细信息,请参阅Liquibase Properties

9.6. Depend Upon an Initialized Database

数据库初始化是在应用程序作为应用程序上下文刷新的一部分启动时执行的。为了允许在启动期间访问已初始化的数据库,将自动检测充当数据库初始化器的Bean和需要初始化该数据库的Bean。其初始化依赖于已被初始化的数据库的Bean被配置为依赖于初始化它的那些Bean。如果在启动期间,您的应用程序尝试访问数据库,但数据库尚未初始化,则可以配置对初始化数据库并要求数据库已初始化的Bean的其他检测。

9.6.1. Detect a Database Initializer

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

  • DataSourceScriptDatabaseInitializer

  • 实体管理器工厂

  • Flyway

  • Flyway MigrationInitializer

  • R2dbcScriptDatabaseInitializer

  • SpringLiquibase

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

9.6.2. Detect a Bean That Depends On Database Initialization

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

  • <代码>抽象实体管理器工厂Bean (除非spring.jpa.defer-datasource-initialization设置为<代码>真 )

  • DSLContext(JOOQ)

  • <代码>实体管理器工厂 (除非spring.jpa.defer-datasource-initialization设置为<代码>真 )

  • JdbcOperations

  • 命名参数JdbcOperations

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

10. Messaging

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

10.1. Disable Transacted JMS Session

如果您的JMS Broker不支持事务会话,则必须完全禁用对事务的支持。如果您创建了自己的JmsListenerContainerFactory,则无需执行任何操作,因为默认情况下不能对其进行事务处理。如果您想使用DefaultJmsListenerContainerFactoryConfigurer来重用Spring Boot的缺省设置,您可以禁用事务处理会话,如下所示:

Java
Kotlin
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; } } 
            
            

上面的示例重写默认工厂,并且它应该应用于您的应用程序定义的任何其他工厂(如果有)。

11. Batch Applications

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

11.1. Specifying a Batch Data Source

默认情况下,批处理应用程序需要数据源来存储作业详细信息。默认情况下,Spring Batch需要单个DataSource。若要使其使用应用程序主DataSource以外的DataSource,请声明一个DataSourceBean,并使用@BatchDataSource注释其@Bean方法。如果这样做并且需要两个数据源,请记住将另一个@Primary标记为。若要获得更好的控制,请实现BatchConfigurer。详见the Javadoc of@EnableBatchProcessing

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

11.2. Running Spring Batch Jobs on Startup

通过将@EnableBatchProcessing添加到您的一个@Configuration类中,可以启用Spring Batch自动配置。

如果在应用程序上下文中找到单个 JobLauncherApplicationRunner>作业 ,则在启动时执行该作业(有关详细信息,请参阅 spring.Batch.job.name指定应该执行的作业。

若要禁止运行在应用程序内容中找到的作业,请将spring.Batch.job.Enabled设置为False。

有关详细信息,请参阅BatchAutoConfiguration@EnableBatchProcessing。

11.3. Running From the Command Line

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

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

如果在命令行上指定Environment的属性,作业将忽略该属性。请考虑以下命令:

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

这只为批处理作业提供了一个参数:ome参数=omeValue

11.4. Storing the Job Repository

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

12. Actuator

Spring Boot包括Spring Boot执行器。本节回答了在使用它时经常出现的问题。

12.1. Change the HTTP Port or Address of the Actuator Endpoints

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

有关更多详细信息,请参阅“生产就绪特性”一节中的ManagementServerProperties源代码和actuator.html

12.2. Customize the ‘whitelabel’ Error Page

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

Set server.error.whitelabel.enabled=false to switch the default error page off. Doing so restores the default of the servlet container that you are using. Note that Spring Boot still tries to resolve the error view, so you should probably add your own error page rather than disabling it completely.

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

有关如何在Servlet容器中注册处理程序的详细信息,请参阅“错误处理一节。

12.3. Sanitize Sensitive Values

/env/configprops/Quartz端点返回的信息可能有些敏感。默认情况下,所有值都经过清理(替换为*)。可以使用该终结点的showValues属性为每个终结点配置查看未清理表单中的原始值。此属性可以配置为具有下列值:

  • 始终-所有值都以未经清理的形式显示给所有用户

  • Never-始终清理所有值(替换为`++)

  • WHEN_AUTHORIZED-所有值都以未经清理的形式显示给授权用户

对于HTTP终结点,如果用户已通过身份验证并具有由终结点的Roles属性配置的角色,则认为该用户已获得授权。默认情况下,任何经过身份验证的用户都是经过授权的。对于JMX端点,所有用户始终获得授权。

Properties
Yaml
management.endpoint.env.show-values=WHEN_AUTHORIZED
management.endpoint.env.roles=admin
            
            

上面的配置使具有admin角色的所有用户能够从/env终结点以其原始形式查看所有值。

When show-values is set to ALWAYS or WHEN_AUTHORIZED any sanitization applied by a SanitizingFunction will still be applied.

12.3.1. Customizing Sanitization

可以通过两种不同的方式自定义清理。

若要更好地控制清理,请定义一个SaniizingFunctionBean。调用函数时使用的SaniizableData提供对键和值以及它们所来自的PropertySource的访问。例如,这允许您清理来自特定属性源的每个值。每个SaniizingFunction都是按顺序调用的,直到某个函数更改了可清理数据的值。如果没有函数更改其值,则执行内置的基于键的清理。

12.4. Map Health Indicators to Micrometer Metrics

Spring Boot运行状况指示器返回状态类型以指示整体系统运行状况。如果您想要监视或警告特定应用程序的运行状况级别,您可以将这些状态导出为带有测微计的指标。默认情况下,Spring Boot使用状态码UP、DOWN、OUT_OF_SERVICE和UNKNOWN。要导出这些状态,您需要将这些状态转换为一组数字,以便它们可以与微米量规一起使用。

下面的示例显示了编写此类导出器的一种方法:

Java
Kotlin
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; } } 
            
            

13. Security

本节讨论在使用Spring Boot时有关安全性的问题,包括在Spring Boot中使用Spring Security时出现的问题。

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

13.1. Switch off the Spring Boot Security Configuration

如果在应用程序中使用SecurityFilterChainBean定义@configuration,它将关闭Spring Boot中的默认WebApp安全设置。

13.2. Change the UserDetailsService and Add User Accounts

如果您提供AuthenticationManagerAuthenticationProviderUserDetailsService类型的@Bean,则不会为InMemory yUserDetailsManager创建默认的@Bean。这意味着您拥有Spring Security的全部功能集(例如各种身份验证选项)。

添加用户帐户的最简单方法是提供您自己的UserDetailsServiceBean。

13.3. Enable HTTPS When Running behind a Proxy Server

确保您的所有主端点只能通过HTTPS使用,这对于任何应用程序都是一项重要的工作。如果您使用Tomcat作为Servlet容器,那么Spring Boot会在检测到某些环境设置时自动添加Tomcat自己的RemoteIpValve,并且您应该能够依赖HttpServletRequest来报告它是否安全(甚至在处理真正的SSL终止的代理服务器的下游)。标准行为由某些请求头(x-Forwarded-Forx-Forwarded-proto)的存在或不存在决定,它们的名称是常规的,因此它应该适用于大多数前端代理。您可以通过向Applation.Properties添加一些条目来打开阀门,如下例所示:

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

(如果存在这两种属性中的任何一种,则开启阀门。或者,您可以通过使用WebServerFactoryCustomizerBean自定义TomcatServletWebServerFactory来添加RemoteIpValve。)

要将Spring Security配置为要求对所有(或某些)请求使用安全通道,请考虑添加您自己的SecurityFilterChainBean,该Bean添加以下HttpSecurity配置:

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

14. Hot Swapping

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

14.1. Reload Static Content

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

或者,在IDE中运行(尤其是在启动调试的情况下)是进行开发的好方法(所有现代的IDE都允许重新加载静态资源,并且通常也允许对Java类更改进行热插拔)。

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

14.2. Reload Templates without Restarting the Container

Spring Boot支持的大多数模板技术都包含一个禁用缓存的配置选项(本文稍后将对此进行介绍)。如果您使用Spring-ot-DevTools模块,这些属性将在开发时自动配置

14.2.1. Thymeleaf Templates

如果您使用Thymeleaf,请将spring.thoreleaf.cache设置为FALSE。有关其他胸腺叶自定义选项,请参阅ThymeleafAutoConfiguration

14.2.2. FreeMarker Templates

如果使用FreeMarker,请将spring.freemarker.cache设置为FALSE。有关其他自由标记定制选项,请参阅FreeMarkerAutoConfiguration

14.2.3. Groovy Templates

如果使用Groovy模板,请将spring.groovy.template.cache设置为FALSE。有关href=“0”>GroovyTemplateAutoConfiguration的其他定制选项,请参阅

14.3. Fast Application Restarts

Spring-Boot-DevTools模块包括对应用程序自动重启的支持。虽然没有JRebel这样的技术快,但它通常比“冷启动”快得多。在研究本文后面讨论的一些更复杂的重载选项之前,您可能应该先试一试。

有关更多详细信息,请参阅using.html部分。

14.4. Reload Java Classes without Restarting the Container

许多现代的IDE(Eclipse、IDEA和其他)都支持字节码的热交换。因此,如果您所做的更改不会影响类或方法签名,则应该干净地重新加载,不会有任何副作用。

15. Testing

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

15.1. Testing With Spring Security

Spring Security支持以特定用户身份运行测试。例如,下面代码片断中的测试将以具有admin角色的经过身份验证的用户运行。

Java
Kotlin
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测试的全面集成,在使用@WebMvcTest切片和MockMvc测试控制器时也可以使用。

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

15.2. Use Testcontainers for Integration Testing

Testtainers库提供了一种管理在Docker容器内运行的服务的方法。它与JUnit集成,允许您编写一个测试类,该类可以在任何测试运行之前启动容器。Testtainers对于编写与真正的后端服务(如MySQL、MongoDB、Cassandra等)对话的集成测试特别有用。在Spring Boot测试中可以使用TestContainers,如下所示:

Java
Kotlin
import org.junit.jupiter.api.Test; import org.testcontainers.containers.Neo4jContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest @Testcontainers class MyIntegrationTests { @Container static Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:4.2"); @Test void myTest() { // ... } } 
            
            

这将在运行任何测试之前启动运行Neo4j的停靠容器(如果Docker在本地运行)。在大多数情况下,您需要使用运行容器的详细信息来配置应用程序,例如容器IP或端口。

这可以通过静态@DynamicPropertySource方法来完成,该方法允许将动态属性值添加到Spring Environment。

Java
Kotlin
import org.junit.jupiter.api.Test; import org.testcontainers.containers.Neo4jContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; @SpringBootTest @Testcontainers class MyIntegrationTests { @Container static Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:4.2"); @Test void myTest() { // ... } @DynamicPropertySource static void neo4jProperties(DynamicPropertyRegistry registry) { registry.add("spring.neo4j.uri", neo4j::getBoltUrl); } } 
            
            

上面的配置允许应用程序中与Neo4j相关的Bean与运行在Testtainers管理的Docker容器中的Neo4j通信。

15.3. Structure @Configuration classes for inclusion in slice tests

切片测试的工作原理是将Spring框架的组件扫描限制为基于组件类型的有限组件集。对于任何不是通过组件扫描创建的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,您可能希望在应用程序上下文中有SecurityFilterChainBean,这样您就可以测试您的控制器端点是否得到了适当的保护。但是,@WebMvcTest的组件扫描筛选器不会拾取MyConfiguration,因为它与筛选器指定的任何类型都不匹配。您可以通过使用@Import(MyConfiguration.class)注释测试类来显式地包含配置。这将加载MyConfiguration中的所有Bean,包括测试Web层时不需要的BasicDataSourceBean。将配置类一分为二将允许仅导入安全配置。

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的多个粒度类,可以仅为特定的切片测试导入它们。

16. Build

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

16.1. Generate Build Information

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

要使用Maven生成构建信息,请添加对Build-Info目标的执行,如下例所示:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>3.0.0</version>
            <executions>
                <execution>
                    <goals>
                        <goal>build-info</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
            
            
See the Spring Boot Maven Plugin documentation for more details.

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

springBoot {
    buildInfo()
}
            
            
See the Spring Boot Gradle Plugin documentation for more details.

16.2. Generate Git Information

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

对于Maven用户,SpringBoot-starter-ParentPOM包括一个预配置的插件,用于生成git.properties文件。要使用它,请将以下Git Commit ID插件声明添加到您的POM中:

<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.3.2"
}
            
            

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

The commit time in git.properties is expected to match the following format: yyyy-MM-dd’T’HH:mm:ssZ. This is the default format for both plugins listed above. Using this format lets the time be parsed into a Date and its format, when serialized to JSON, to be controlled by Jackson’s date serialization configuration settings.

16.3. Customize Dependency Versions

SpringBoot-DependentsPOM管理常见依赖项的版本。Maven和Gradle的Spring Boot插件允许使用构建属性定制这些托管依赖项版本。

Each Spring Boot release is designed and tested against this specific set of third-party dependencies. Overriding versions may cause compatibility issues.

要用Maven覆盖依赖项版本,请参阅Maven插件文档的本节。

要覆盖Gradle中的依赖项版本,请参阅Gradle插件文档的这一节。

16.4. Create an Executable JAR with Maven

SpringBoot-maven-plugin可用于创建可执行的“胖”JAR。如果您使用Spring-Boot-starter-ParentPOM,您可以声明插件,并按如下方式重新打包您的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>{spring-boot-version}</version>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
            
            

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

16.5. Use a Spring Boot Application as a Dependency

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

16.6. Extract Specific Libraries When an Executable Jar Runs

可执行JAR中的大多数嵌套库不需要解压缩即可运行。但是,某些库可能会出现问题。例如,JRuby包括它自己的嵌套JAR支持,这假设jruby-plee.jar始终作为文件本身直接可用。

要处理任何有问题的库,您可以标记在可执行JAR第一次运行时应该自动解压特定的嵌套JAR。此类嵌套JAR被写入由java.io.tmpdir系统属性标识的临时目录下。

Care should be taken to ensure that your operating system is configured so that it will not delete the jars that have been unpacked to the temporary directory while the application is still running.

例如,要指示应该使用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. Create a Non-executable JAR with Exclusions

通常,如果您将一个可执行文件和一个非可执行文件JAR作为两个单独的构建产品,则可执行文件版本具有库JAR中不需要的附加配置文件。例如,可以从非可执行JAR中排除Applation.yml配置文件。

在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.yml</exclude>
                        </excludes>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
            
            

16.8. Remote Debug a Spring Boot Application Started with Maven

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

有关详细信息,请参阅此示例

16.9. Build an Executable Archive From Ant without Using spring-boot-antlib

要使用Ant构建,您需要获取依赖项、编译,然后创建一个JAR或WAR归档。要使其可执行,您可以使用SpringBoot-antlib模块,也可以按照以下说明操作:

  1. 如果您正在构建JAR,请将应用程序的类和资源打包到嵌套的引导-INF/CLASSES目录中。如果您正在构建WAR,请像往常一样将应用程序的类打包到嵌套的WEB-INF/CLASSES目录中。

  2. 将运行时依赖项添加到嵌套的Boot-INF/lib目录(对于JAR)或WEB-INF/lib目录(对于WAR)。记住Not压缩存档中的条目。

  3. 提供的(嵌入式容器)依赖项添加到嵌套的Boot-INF/lib目录中(对于JAR)或WEB-INF/lib提供的目录(对于WAR)。记住Not压缩存档中的条目。

  4. 在归档文件的根目录下添加SpringBoot-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. Traditional Deployment

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

17.1. Create a Deployable War File

Because Spring WebFlux does not strictly depend on the servlet API and applications are deployed by default on an embedded Reactor Netty server, War deployment is not supported for WebFlux applications.

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

Java
Kotlin
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和SpringBoot-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 is preferred to Gradle’s compileOnly configuration. Among other limitations, compileOnly dependencies are not on the test classpath, so any web-based integration tests fail.

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

17.2. Convert an Existing Application to Spring Boot

要将现有的非Web Spring应用程序转换为Spring Boot应用程序,请替换创建ApplicationContext的代码,并将其替换为对SpringApplicationBuilderSpringApplicationBuilder的调用。Spring MVC Web应用程序通常可以先创建可部署的WAR应用程序,然后再将其迁移到可执行的WAR或JAR。请参阅入门指南,了解如何将JAR转换为WAR

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

Java
Kotlin
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 (via @SpringBootApplication) // we actually do not need to override this method. return application; } } 
            
            

请记住,您放在源代码中的任何内容都只是一个SpringApplicationContext。正常情况下,任何已经起作用的东西都应该在这里起作用。可能有一些Bean可以在以后删除,并让Spring Boot为它们提供自己的缺省值,但在您需要这样做之前,应该可以让一些东西运行起来。

静态资源可以移到类路径根目录中的/public(或/静态/resource/META-INF/resource)。这同样适用于Messages.Properties(Spring Boot会在类路径的根目录中自动检测到它)。

简单地使用SpringDispatcherServlet和Spring Security应该不需要进一步的更改。如果您的应用程序中有其他功能(例如,使用其他Servlet或筛选器),则可能需要向应用程序上下文添加一些配置,方法是替换web.xml中的那些元素,如下所示:

  • ServletServletRegistrationBean类型的@Bean将该Bean安装在容器中,就像它是web.xml中的Servlet/和;Servlet映射/

  • FilterFilterRegistrationBean类型的@Bean的行为类似(作为;筛选器/&>和<;筛选器映射/)。

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

WAR文件工作后,您可以通过向应用程序添加一个main方法使其可执行,如下例所示:

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

            
            

如果要将应用程序作为WAR或可执行应用程序启动,则需要在SpringBootServletInitializer回调和main方法的类中共享构建器的自定义设置:

Java
Kotlin
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上使用标记SpringBoot提问。

17.3. Deploying a WAR to WebLogic

要将Spring Boot应用程序部署到WebLogic,您必须确保您的Servlet初始化器直接实现WebApplicationInitializer(即使您从已经实现它的基类扩展)。

WebLogic的典型初始值设定项应类似于以下示例:

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