“作方法”指南
1. Spring Boot 应用程序
本节包括与 Spring Boot 应用程序直接相关的主题。
1.1. 创建自己的 FailureAnalyzer
FailureAnalyzer
是在启动时拦截异常并将其转换为人类可读的消息的好方法,并包装在FailureAnalysis
.
Spring Boot 为与应用程序上下文相关的异常、JSR-303 验证等提供了这样的分析器。
您也可以创建自己的。
AbstractFailureAnalyzer
是FailureAnalyzer
检查要处理的异常中是否存在指定的异常类型。
您可以从中扩展,以便您的实现只有在异常实际存在时才有机会处理异常。
如果出于某种原因无法处理异常,则返回null
让另一个实现有机会处理异常。
FailureAnalyzer
实现必须在META-INF/spring.factories
.
以下示例寄存器ProjectConstraintViolationFailureAnalyzer
:
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.example.ProjectConstraintViolationFailureAnalyzer
如果您需要访问BeanFactory 或Environment 你FailureAnalyzer 可以实现BeanFactoryAware 或EnvironmentAware 分别。 |
1.2. 自动配置故障排除
Spring Boot 自动配置会尽最大努力“做正确的事”,但有时事情会失败,而且很难说出原因。
有一个非常有用的ConditionEvaluationReport
在任何 Spring Boot 中可用ApplicationContext
.
如果启用DEBUG
日志记录输出。
如果您使用spring-boot-actuator
(参见执行器一章),还有一个conditions
以 JSON 格式呈现报表的端点。
使用该端点调试应用程序,并查看 Spring Boot 在运行时添加了哪些功能(以及哪些尚未添加)。
通过查看源代码和 Javadoc 可以回答更多问题。 阅读代码时,请记住以下经验法则:
-
查找名为
*AutoConfiguration
并阅读他们的来源。 特别注意@Conditional*
注释,以了解它们启用了哪些功能以及何时启用。 加--debug
到命令行或系统属性-Ddebug
在控制台上获取在应用中做出的所有自动配置决策的日志。 在启用了执行器的运行应用程序中,查看conditions
端点 (/actuator/conditions
或 JMX 等效产品)以获取相同的信息。 -
寻找符合以下条件的类
@ConfigurationProperties
(例如ServerProperties
),然后从那里读取可用的外部配置选项。 这@ConfigurationProperties
注释有一个name
充当外部属性前缀的属性。 因此ServerProperties
有prefix="server"
其配置属性为server.port
,server.address
,等。 在启用了执行器的运行应用程序中,查看configprops
端点。 -
寻找
bind
方法Binder
将配置值显式提取出Environment
以轻松的方式。 它通常与前缀一起使用。 -
查找
@Value
直接绑定到Environment
. -
查找
@ConditionalOnExpression
响应 SpEL 表达式打开和关闭特征的注释,通常使用从Environment
.
1.3. 在启动之前自定义环境或 ApplicationContext
一个SpringApplication
有ApplicationListeners
和ApplicationContextInitializers
用于将自定义应用于上下文或环境。
Spring Boot 加载了许多此类自定义项以供内部使用META-INF/spring.factories
.
注册其他自定义项的方法不止一种:
-
以编程方式,每个应用程序通过调用
addListeners
和addInitializers
方法SpringApplication
在运行它之前。 -
以声明方式,通过每个应用程序将
context.initializer.classes
或context.listener.classes
性能。 -
以声明方式,对于所有应用程序,通过添加
META-INF/spring.factories
以及打包应用程序都用作库的 jar 文件。
这SpringApplication
发送一些特殊的ApplicationEvents
到侦听器(有些甚至在创建上下文之前),然后注册侦听器以获取ApplicationContext
也。
有关完整列表,请参阅“Spring Boot 功能”部分中的“应用程序事件和侦听器”。
也可以自定义Environment
在使用EnvironmentPostProcessor
.
每个实现都应在META-INF/spring.factories
,如以下示例所示:
org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor
该实现可以加载任意文件并将它们添加到Environment
.
例如,以下示例从类路径加载 YAML 配置文件:
public class 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);
}
}
}
class MyEnvironmentPostProcessor : EnvironmentPostProcessor {
private val loader = YamlPropertySourceLoader()
override fun postProcessEnvironment(environment: ConfigurableEnvironment, application: SpringApplication) {
val path: Resource = ClassPathResource("com/example/myapp/config.yml")
val propertySource = loadYaml(path)
environment.propertySources.addLast(propertySource)
}
private fun loadYaml(path: Resource): PropertySource<*> {
Assert.isTrue(path.exists()) { "Resource $path does not exist" }
return try {
loader.load("custom-resource", path)[0]
} catch (ex: IOException) {
throw IllegalStateException("Failed to load yaml configuration from $path", ex)
}
}
}
这Environment 已经准备好了 Spring Boot 默认加载的所有常用属性源。
因此,可以从环境中获取文件的位置。
前面的示例将custom-resource 属性源,以便在任何通常的其他位置中定义的键优先。
自定义实现可以定义另一个顺序。 |
使用@PropertySource 在您的@SpringBootApplication 似乎是在Environment ,我们不推荐它。
此类属性源不会添加到Environment 直到刷新应用程序上下文。
这为时已晚,无法配置某些属性,例如logging.* 和spring.main.* 在刷新开始之前读取。 |
1.4. 构建 ApplicationContext 层次结构(添加父上下文或根上下文)
您可以使用ApplicationBuilder
类创建父/子ApplicationContext
层次 结构。
有关更多信息,请参阅“Spring Boot 功能”部分中的“features.html”。
1.5. 创建非 Web 应用程序
并非所有 Spring 应用程序都必须是 Web 应用程序(或 Web 服务)。
如果你想在main
方法,但也可以引导一个 Spring 应用程序来设置要使用的基础设施,你可以使用SpringApplication
Spring Boot 的功能。
一个SpringApplication
更改其ApplicationContext
类,具体取决于它是否认为它需要 Web 应用程序。
为了帮助它,您可以做的第一件事是将与服务器相关的依赖项(例如 servlet API)从类路径中剔除。
如果无法做到这一点(例如,从同一代码库运行两个应用程序),则可以显式调用setWebApplicationType(WebApplicationType.NONE)
在您的SpringApplication
实例或将applicationContextClass
属性(通过 Java API 或使用外部属性)。
要作为业务逻辑运行的应用程序代码可以实现为CommandLineRunner
并作为@Bean
定义。
2. 属性和配置
本节包括有关设置和读取属性和配置设置及其与 Spring Boot 应用程序交互的主题。
2.1. 在构建时自动扩展属性
无需对项目的生成配置中也指定的某些属性进行硬编码,而是可以使用现有生成配置来自动扩展它们。 这在 Maven 和 Gradle 中都是可能的。
2.1.1. 使用 Maven 自动属性扩展
您可以使用资源筛选从 Maven 项目自动扩展属性。
如果您使用spring-boot-starter-parent
,然后你可以使用@..@
占位符,如以下示例所示:
app:
encoding: "@project.build.sourceEncoding@"
java:
version: "@java.version@"
只有生产配置以这种方式过滤(换句话说,不应用过滤src/test/resources ). |
如果您启用addResources flag,则spring-boot:run 目标可以添加src/main/resources 直接到类路径(用于热重载目的)。
这样做可以规避资源筛选和此功能。
相反,您可以使用exec:java 目标或自定义插件的配置。
有关更多详细信息,请参阅插件使用页面。 |
如果您不使用起始父级,则需要在<build/>
元素的pom.xml
:
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
您还需要在<plugins/>
:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<configuration>
<delimiters>
<delimiter>@</delimiter>
</delimiters>
<useDefaultDelimiters>false</useDefaultDelimiters>
</configuration>
</plugin>
这useDefaultDelimiters 如果您使用标准 Spring 占位符(例如${placeholder} ) 在您的配置中。
如果该属性未设置为false ,这些可能会通过构建进行扩展。 |
2.1.2. 使用 Gradle 自动属性扩展
您可以通过配置 Java 插件的processResources
任务,如以下示例所示:
tasks.named('processResources') {
expand(project.properties)
}
然后,您可以使用占位符引用 Gradle 项目的属性,如以下示例所示:
app.name=${name}
app.description=${description}
app:
name: "${name}"
description: "${description}"
Gradle 的expand 方法使用 Groovy 的SimpleTemplateEngine ,这会变换${..} Tokens。
这${..} style 与 Spring 自己的属性占位符机制冲突。
要将 Spring 属性占位符与自动扩展一起使用,请转义 Spring 属性占位符,如下所示:\${..} . |
2.2. 外部化 SpringApplication 的配置
一个SpringApplication
具有 bean 属性设置器,因此您可以在创建应用程序时使用其 Java API 来修改其行为。
或者,您可以通过在spring.main.*
.
例如,在application.properties
,您可能有以下设置:
spring.main.web-application-type=none
spring.main.banner-mode=off
spring:
main:
web-application-type: "none"
banner-mode: "off"
然后,启动时不会打印 Spring Boot 横幅,并且应用程序不会启动嵌入式 Web 服务器。
外部配置中定义的属性会覆盖和替换 Java API 指定的值,但主要源代码除外。
主要来源是提供给SpringApplication
构造 函数:
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MyApplication.class);
application.setBannerMode(Banner.Mode.OFF);
application.run(args);
}
}
@SpringBootApplication
object MyApplication {
@JvmStatic
fun main(args: Array<String>) {
val application = SpringApplication(MyApplication::class.java)
application.setBannerMode(Banner.Mode.OFF)
application.run(*args)
}
}
或者sources(…)
方法SpringApplicationBuilder
:
public class MyApplication {
public static void main(String[] args) {
new SpringApplicationBuilder()
.bannerMode(Banner.Mode.OFF)
.sources(MyApplication.class)
.run(args);
}
}
object MyApplication {
@JvmStatic
fun main(args: Array<String>) {
SpringApplicationBuilder()
.bannerMode(Banner.Mode.OFF)
.sources(MyApplication::class.java)
.run(*args)
}
}
给定上面的示例,如果我们有以下配置:
spring.main.sources=com.example.MyDatabaseConfig,com.example.MyJmsConfig
spring.main.banner-mode=console
spring:
main:
sources: "com.example.MyDatabaseConfig,com.example.MyJmsConfig"
banner-mode: "console"
实际应用程序将显示横幅(由配置覆盖),并使用ApplicationContext
.
应用程序来源是:
-
MyApplication
(来自代码) -
MyDatabaseConfig
(来自外部配置) -
MyJmsConfig
(来自外部配置)
2.3. 更改应用程序外部属性的位置
默认情况下,来自不同来源的属性将添加到 SpringEnvironment
按定义的顺序(有关确切顺序,请参阅“Spring Boot 功能”部分中的“features.html”)。
您还可以提供以下系统属性(或环境变量)来更改行为:
-
spring.config.name
(SPRING_CONFIG_NAME
):默认为application
作为文件名的根目录。 -
spring.config.location
(SPRING_CONFIG_LOCATION
):要加载的文件(例如类路径资源或 URL)。 一个单独的Environment
属性源是为本文档设置的,它可以被系统属性、环境变量或命令行覆盖。
无论您在环境中设置什么,Spring Boot 始终加载application.properties
如上所述。
默认情况下,如果使用 YAML,则扩展名为“.yaml”和“.yml”的文件也会添加到列表中。
如果需要有关正在加载的文件的详细信息,可以将日志记录级别设置为org.springframework.boot.context.config 自trace . |
2.4. 使用“短”命令行参数
有些人喜欢使用(例如)--port=9000
而不是--server.port=9000
在命令行上设置配置属性。
您可以使用application.properties
,如以下示例所示:
server.port=${port:8080}
server:
port: "${port:8080}"
如果您继承自spring-boot-starter-parent POM,默认的过滤器Tokensmaven-resources-plugins 已从 更改为 (即,${*} @ @maven.token@ 而不是${maven.token} )以防止与 Spring 样式占位符发生冲突。
如果您已为application.properties 直接,您可能还想更改默认过滤器Tokens以使用其他分隔符。 |
在这种特定情况下,端口绑定在 PaaS 环境中工作,例如 Heroku 或 Cloud Foundry。
在这两个平台中,PORT 环境变量是自动设置的,Spring可以绑定到大写的同义词Environment 性能。 |
2.5. 将 YAML 用于外部属性
YAML 是 JSON 的超集,因此是一种方便的语法,用于以分层格式存储外部属性,如以下示例所示:
spring:
application:
name: "cruncher"
datasource:
driver-class-name: "com.mysql.jdbc.Driver"
url: "jdbc:mysql://localhost/test"
server:
port: 9000
创建一个名为application.yaml
并将其放在类路径的根目录中。
然后添加snakeyaml
到你的依赖项(Maven 坐标org.yaml:snakeyaml
,如果您使用spring-boot-starter
).
YAML 文件被解析为 JavaMap<String,Object>
(如 JSON 对象),并且 Spring Boot 将映射展平,使其具有一级深度并具有句点分隔的键,就像许多人习惯的那样Properties
Java 中的文件。
前面的示例 YAML 对应于以下内容application.properties
文件:
spring.application.name=cruncher
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost/test
server.port=9000
有关 YAML 的更多信息,请参阅“Spring Boot 功能”部分中的“features.html”。
2.6. 设置活动的 Spring 配置文件
SpringEnvironment
有一个 API,但您通常会设置一个 System 属性 (spring.profiles.active
) 或作系统环境变量 (SPRING_PROFILES_ACTIVE
).
此外,您可以使用-D
参数(记得放在主类或jar存档之前),如下所示:
$ java -jar -Dspring.profiles.active=production demo-0.0.1-SNAPSHOT.jar
在 Spring Boot 中,您还可以在application.properties
,如以下示例所示:
spring.profiles.active=production
spring:
profiles:
active: "production"
以这种方式设置的值将被 System 属性或环境变量设置替换,但不会被SpringApplicationBuilder.profiles()
方法。 因此,后一个 Java API 可用于在不更改默认值的情况下扩充配置文件。
有关更多信息,请参阅“Spring Boot 功能”部分中的“features.html”。
2.7. 设置默认配置文件名称
默认配置文件是在没有处于活动状态的配置文件时启用的配置文件。默认情况下,默认配置文件的名称为default
,但可以使用 System 属性 (spring.profiles.default
) 或作系统环境变量 (SPRING_PROFILES_DEFAULT
).
在 Spring Boot 中,您还可以在application.properties
,如以下示例所示:
spring.profiles.default=dev
spring:
profiles:
default: "dev"
有关更多信息,请参阅“Spring Boot 功能”部分中的“features.html”。
2.8. 根据环境更改配置
Spring Boot 支持多文档 YAML 和属性文件(有关详细信息,请参阅 features.html),这些文件可以根据活动配置文件有条件地激活。
如果文档包含spring.config.activate.on-profile
键,则将 profiles 值(以逗号分隔的配置文件列表或配置文件表达式)输入到 SpringEnvironment.acceptsProfiles()
方法。
如果配置文件表达式匹配,则该文档将包含在最终合并中(否则,则不包括在内),如以下示例所示:
server.port=9000
#---
spring.config.activate.on-profile=development
server.port=9001
#---
spring.config.activate.on-profile=production
server.port=0
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。 如果“生产”处于活动状态,则端口为 0。
文档将按照遇到它们的顺序进行合并。 较晚的值将覆盖较早的值。 |
2.9. 发现外部属性的内置选项
Spring Boot 将外部属性从application.properties
(或 YAML 文件和其他位置)在运行时转换为应用程序。
在单个位置没有(从技术上讲也不可能)所有受支持属性的详尽列表,因为贡献可能来自类路径上的其他 jar 文件。
具有 Actuator 功能的正在运行的应用程序具有configprops
端点,显示所有可用的绑定和可绑定属性@ConfigurationProperties
.
附录包括一个application.properties
示例,其中包含 Spring Boot 支持的最常见属性的列表。
最终列表来自搜索源代码@ConfigurationProperties
和@Value
注释以及偶尔使用Binder
.
有关加载属性的确切顺序的更多信息,请参阅“features.html”。
3. 嵌入式 Web 服务器
每个 Spring Boot Web 应用程序都包含一个嵌入式 Web 服务器。 此功能会导致许多作方法问题,包括如何更改嵌入式服务器以及如何配置嵌入式服务器。 本节回答这些问题。
3.1. 使用另一个 Web 服务器
许多 Spring Boot Starters都包含默认的嵌入式容器。
-
对于 servlet 堆栈应用程序,
spring-boot-starter-web
通过包含 Tomcatspring-boot-starter-tomcat
,但您可以使用spring-boot-starter-jetty
或spring-boot-starter-undertow
相反。 -
对于响应式堆栈应用程序,
spring-boot-starter-webflux
通过包含 Reactor Nettyspring-boot-starter-reactor-netty
,但您可以使用spring-boot-starter-tomcat
,spring-boot-starter-jetty
或spring-boot-starter-undertow
相反。
切换到不同的 HTTP 服务器时,您需要将默认依赖项交换为所需的依赖项。 为了帮助完成此过程,Spring Boot 为每个受支持的 HTTP 服务器提供了一个单独的Starters。
以下 Maven 示例显示了如何为 Spring MVC 排除 Tomcat 并包含 Jetty:
<properties>
<servlet-api.version>3.1.0</servlet-api.version>
</properties>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!-- Exclude the Tomcat dependency -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Use Jetty instead -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
servlet API 的版本已被覆盖,因为与 Tomcat 9 和 Undertow 2 不同,Jetty 9.4 不支持 servlet 4.0。 |
如果您希望使用支持 servlet 4.0 的 Jetty 10,您可以按照以下示例所示进行作:
<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 Starters外,还需要排除一些特定于 Jetty9 的依赖项。
以下 Gradle 示例配置了必要的依赖项和模块替换,以使用 Undertow 代替 Spring WebFlux 的 Reactor 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 需要使用WebClient 类,因此即使您需要包含不同的 HTTP 服务器,您也可能需要保持对 Netty 的依赖。 |
3.2. 禁用 Web 服务器
如果您的类路径包含启动 Web 服务器所需的位,Spring Boot 将自动启动它。
要禁用此行为,请配置WebApplicationType
在你的application.properties
,如以下示例所示:
spring.main.web-application-type=none
spring:
main:
web-application-type: "none"
3.3. 更改 HTTP 端口
在独立应用程序中,主 HTTP 端口默认为8080
但可以使用server.port
(例如,在application.properties
或作为系统属性)。
得益于宽松的绑定Environment
值,也可以使用SERVER_PORT
(例如,作为作系统环境变量)。
要完全关闭 HTTP 端点,但仍创建WebApplicationContext
用server.port=-1
(这样做有时对测试很有用)。
有关更多详细信息,请参阅“Spring Boot 功能”部分中的“web.html”,或ServerProperties
源代码。
3.5. 在运行时发现 HTTP 端口
您可以从日志输出或WebServerApplicationContext
通过其WebServer
. 获取它并确保它已初始化的最佳方法是添加一个@Bean
类型ApplicationListener<WebServerInitializedEvent>
并在发布事件时将容器从事件中拉出。
使用@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
还可以使用@LocalServerPort
注释,如以下示例所示:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyWebIntegrationTests {
@LocalServerPort
int port;
// ...
}
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyWebIntegrationTests {
@LocalServerPort
var port = 0
// ...
}
|
3.6. 启用 HTTP 响应压缩
Jetty、Tomcat、Reactor Netty 和 Undertow 支持 HTTP 响应压缩。它可以在application.properties
如下:
server.compression.enabled=true
server:
compression:
enabled: true
默认情况下,响应的长度必须至少为 2048 字节才能执行压缩。您可以通过将server.compression.min-response-size
财产。
默认情况下,仅当响应的内容类型为以下内容类型之一时,才会压缩响应:
-
text/html
-
text/xml
-
text/plain
-
text/css
-
text/javascript
-
application/javascript
-
application/json
-
application/xml
您可以通过设置server.compression.mime-types
财产。
3.7. 配置 SSL
SSL 可以通过设置各种server.ssl.*
属性,通常在application.properties
或application.yaml
.
以下示例显示使用 Java KeyStore 文件设置 SSL 属性:
server.port=8443
server.ssl.key-store=classpath:keystore.jks
server.ssl.key-store-password=secret
server.ssl.key-password=another-secret
server:
port: 8443
ssl:
key-store: "classpath:keystore.jks"
key-store-password: "secret"
key-password: "another-secret"
使用上述示例等配置意味着应用程序不再支持端口 8080 处的纯 HTTP 连接器。
Spring Boot 不支持通过 HTTP 连接器和 HTTPS 连接器的配置application.properties
.
如果要同时拥有两者,则需要以编程方式配置其中一个。
我们建议使用application.properties
配置 HTTPS,因为 HTTP 连接器是两者中更容易以编程方式配置的。
3.7.1. 使用 PEM 编码文件
您可以使用 PEM 编码的文件而不是 Java KeyStore 文件。
应尽可能使用 PKCS#8 密钥文件。
PEM 编码的 PKCS#8 密钥文件以-----BEGIN PRIVATE KEY-----
或-----BEGIN ENCRYPTED PRIVATE KEY-----
页眉。
如果您有其他格式的文件,例如 PKCS#1 (-----BEGIN RSA PRIVATE KEY-----
) 或 SEC 1 (-----BEGIN EC PRIVATE KEY-----
),您可以使用 OpenSSL 将它们转换为 PKCS#8:
openssl pkcs8 -topk8 -nocrypt -in <input file> -out <output file>
以下示例显示使用 PEM 编码的证书和私钥文件设置 SSL 属性:
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
server:
port: 8443
ssl:
certificate: "classpath:my-cert.crt"
certificate-private-key: "classpath:my-cert.key"
trust-certificate: "classpath:ca-cert.crt"
看Ssl
有关所有受支持属性的详细信息。
3.8. 配置 HTTP/2
您可以使用 Spring Boot 应用程序中的 HTTP/2 支持server.http2.enabled
configuration 属性。
双h2
(基于 TLS 的 HTTP/2)和h2c
(基于 TCP 的 HTTP/2)。
使用h2
,还必须启用 SSL。
未启用 SSL 时,h2c
将被使用。
例如,您可能想要使用h2c
当应用程序在执行 TLS 终止的代理服务器后面运行时。
的细节h2
支持取决于所选的 Web 服务器和应用程序环境,因为并非所有 JDK 8 版本都支持该协议。
3.8.1. HTTP/2 与 Tomcat
Spring Boot 默认附带 Tomcat 9.0.x,它支持h2c
开箱即用和h2
使用 JDK 9 或更高版本时开箱即用。
或者h2
可以在 JDK 8 上使用,如果libtcnative
库及其依赖项安装在主机作系统上。
库目录必须可用于 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. 带 Jetty 的 HTTP/2
对于 HTTP/2 支持,Jetty 需要额外的org.eclipse.jetty.http2:http2-server
Dependency。 使用h2c
不需要其他依赖项。使用h2
,您还需要选择以下依赖项之一,具体取决于您的部署:
-
org.eclipse.jetty:jetty-alpn-java-server
适用于在 JDK9+ 上运行的应用程序 -
org.eclipse.jetty:jetty-alpn-openjdk8-server
用于在 JDK8u252+ 上运行的应用程序 -
org.eclipse.jetty:jetty-alpn-conscrypt-server
以及没有 JDK 要求的 Conscrypt 库
3.8.3. HTTP/2 与 Reactor Netty
这spring-boot-webflux-starter
默认使用 Reactor Netty 作为服务器。Reactor Netty 支持h2c
使用 JDK 8 或更高版本,没有额外的依赖项。Reactor Netty 支持h2
将 JDK 支持与 JDK 9 或更高版本一起使用。对于 JDK 8 环境,或为了获得最佳运行时性能,此服务器还支持h2
使用本机库。要实现这一点,您的应用程序需要具有额外的依赖项。
Spring Boot 管理io.netty:netty-tcnative-boringssl-static
“uber jar”,包含适用于所有平台的本机库。
开发人员可以选择使用分类器仅导入所需的依赖项(参见 Netty 官方文档)。
3.9. 配置 Web 服务器
通常,您应该首先考虑使用许多可用的配置密钥之一,并通过在application.properties
或application.yaml
文件。
请参阅“发现外部属性的内置选项”)。
这server.*
命名空间在这里非常有用,它包括像server.tomcat.*
,server.jetty.*
和其他,用于特定于服务器的功能。
请参阅application-properties.html列表。
前面的部分已经涵盖了许多常见用例,例如压缩、SSL 或 HTTP/2。
但是,如果您的用例不存在配置密钥,则应查看WebServerFactoryCustomizer
.
您可以声明这样的组件并访问与您的选择相关的服务器工厂:您应该为所选服务器(Tomcat、Jetty、Reactor Netty、Undertow)和所选 Web 堆栈(servlet 或响应式)选择变体。
下面的示例适用于 Tomcat,其中spring-boot-starter-web
(servlet 堆栈):
@Component
public class MyTomcatWebServerCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
@Override
public void customize(TomcatServletWebServerFactory factory) {
// customize the factory here
}
}
@Component
class MyTomcatWebServerCustomizer : WebServerFactoryCustomizer<TomcatServletWebServerFactory?> {
override fun customize(factory: TomcatServletWebServerFactory?) {
// customize the factory here
}
}
Spring Boot 在内部使用该基础设施来自动配置服务器。
自动配置WebServerFactoryCustomizer 豆子的顺序为0 并将在任何用户定义的定制器之前进行处理,除非它有另有说明的显式顺序。 |
一旦您有权访问WebServerFactory
使用定制器,您可以使用它来配置特定部分,例如连接器、服务器资源或服务器本身 - 所有这些都使用特定于服务器的 API。
此外,Spring Boot 还提供:
服务器 | Servlet 堆栈 | 响应式堆栈 |
---|---|---|
Tomcat |
|
|
Jetty |
|
|
Undertow |
|
|
反应器 |
不适用 |
|
作为最后的手段,您也可以声明自己的WebServerFactory
bean,它将覆盖 Spring Boot 提供的那个。
执行此作时,自动配置的定制器仍会应用于自定义工厂,因此请谨慎使用该选项。
3.10. 将 Servlet、过滤器或侦听器添加到应用程序
在 servlet 堆栈应用程序中,即使用spring-boot-starter-web
,有两种方式可以添加Servlet
,Filter
,ServletContextListener
,以及 Servlet API 支持的其他侦听器到您的应用程序:
3.10.1. 使用 Spring Bean 添加 Servlet、过滤器或侦听器
要添加一个Servlet
,Filter
或 Servlet*Listener
通过使用 Spring bean,您必须提供@Bean
它的定义。
当您想要注入配置或依赖项时,这样做可能非常有用。
但是,您必须非常小心,不要让它们导致太多其他 bean 的急切初始化,因为它们必须在应用程序生命周期的早期安装在容器中。
(例如,让他们依赖您的DataSource
或 JPA 配置。
您可以通过在首次使用时而不是在初始化时延迟初始化 Bean 来绕过此类限制。
对于过滤器和 servlet,您还可以通过添加FilterRegistrationBean
或ServletRegistrationBean
而不是底层组件或附加组件。
如果没有 |
与任何其他 Spring Bean 一样,您可以定义 servlet 过滤 Bean 的顺序;请务必检查“web.html”部分。
禁用 Servlet 或过滤器的注册
如前所述,任何Servlet
或Filter
Bean 会自动注册到 Servlet 容器中。
禁用特定Filter
或Servlet
bean,为其创建一个注册 bean 并将其标记为禁用,如以下示例所示:
@Configuration(proxyBeanMethods = false)
public class MyFilterConfiguration {
@Bean
public FilterRegistrationBean<MyFilter> registration(MyFilter filter) {
FilterRegistrationBean<MyFilter> registration = new FilterRegistrationBean<>(filter);
registration.setEnabled(false);
return registration;
}
}
@Configuration(proxyBeanMethods = false)
class MyFilterConfiguration {
@Bean
fun registration(filter: MyFilter): FilterRegistrationBean<MyFilter> {
val registration = FilterRegistrationBean(filter)
registration.isEnabled = false
return registration
}
}
3.11. 配置访问日志记录
可以通过各自的命名空间为 Tomcat、Undertow 和 Jetty 配置访问日志。
例如,以下设置使用自定义模式记录 Tomcat 上的访问。
server.tomcat.basedir=my-tomcat
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%t %a %r %s (%D ms)
server:
tomcat:
basedir: "my-tomcat"
accesslog:
enabled: true
pattern: "%t %a %r %s (%D ms)"
日志的默认位置是logs 相对于 Tomcat 基本目录的目录。
默认情况下,logs 目录是一个临时目录,因此您可能希望修复 Tomcat 的基目录或使用日志的绝对路径。
在前面的示例中,日志在my-tomcat/logs 相对于应用程序的工作目录。 |
可以以类似的方式配置 Undertow 的访问日志记录,如以下示例所示:
server.undertow.accesslog.enabled=true
server.undertow.accesslog.pattern=%t %a %r %s (%D ms)
server.undertow.options.server.record-request-start-time=true
server:
undertow:
accesslog:
enabled: true
pattern: "%t %a %r %s (%D ms)"
options:
server:
record-request-start-time: true
请注意,除了启用访问日志记录和配置其模式外,还启用了记录请求开始时间。
当包括响应时间 (%D
) 在访问日志模式中。
日志存储在logs
相对于应用程序工作目录的目录。
您可以通过设置server.undertow.accesslog.dir
财产。
最后,Jetty 的访问日志记录也可以配置如下:
server.jetty.accesslog.enabled=true
server.jetty.accesslog.filename=/var/log/jetty-access.log
server:
jetty:
accesslog:
enabled: true
filename: "/var/log/jetty-access.log"
默认情况下,日志被重定向到System.err
.
有关更多详细信息,请参阅 Jetty 文档。
3.12. 在前端代理服务器后面运行
如果您的应用程序在代理、负载均衡器或云中运行,则请求信息(如主机、端口、方案等)可能会在此过程中发生变化。
您的应用程序可能在10.10.10.10:8080
,但 HTTP 客户端应该只看到example.org
.
RFC7239“转发标头”定义了Forwarded
HTTP 标头;代理可以使用此标头提供有关原始请求的信息。
您可以将应用程序配置为读取这些标头,并在创建链接并将其发送到 HTTP 302 响应、JSON 文档或 HTML 页面中的客户端时自动使用该信息。
还有非标准标头,例如X-Forwarded-Host
,X-Forwarded-Port
,X-Forwarded-Proto
,X-Forwarded-Ssl
和X-Forwarded-Prefix
.
如果代理将常用的X-Forwarded-For
和X-Forwarded-Proto
标题, 设置server.forward-headers-strategy
自NATIVE
足以支持这些。
使用此选项,Web 服务器本身本身支持此功能;您可以查看他们的特定文档以了解具体行为。
如果这还不够,Spring Framework 为 servlet 堆栈提供了 ForwardedHeaderFilter,为响应式堆栈提供了 ForwardedHeaderTransformer。
您可以通过设置server.forward-headers-strategy
自FRAMEWORK
.
如果您使用 Tomcat 并在代理处终止 SSL,server.tomcat.redirect-context-root 应设置为false .
这允许X-Forwarded-Proto 标头。 |
如果您的应用程序在 Cloud Foundry、Heroku 或 Kubernetes 中运行,则server.forward-headers-strategy 属性默认为NATIVE .
在所有其他情况下,它默认为NONE . |
3.12.1. 自定义 Tomcat 的代理配置
如果使用 Tomcat,则可以额外配置用于携带“转发”信息的标头的名称,如以下示例所示:
server.tomcat.remoteip.remote-ip-header=x-your-remote-ip-header
server.tomcat.remoteip.protocol-header=x-your-protocol-header
server:
tomcat:
remoteip:
remote-ip-header: "x-your-remote-ip-header"
protocol-header: "x-your-protocol-header"
Tomcat 还配置了一个正则表达式,该正则表达式与要信任的内部代理匹配。
请参阅server.tomcat.remoteip.internal-proxies
附录中的条目为其默认值。
您可以通过添加一个条目来自定义阀门的配置application.properties
,如以下示例所示:
server.tomcat.remoteip.internal-proxies=192\\.168\\.\\d{1,3}\\.\\d{1,3}
server:
tomcat:
remoteip:
internal-proxies: "192\\.168\\.\\d{1,3}\\.\\d{1,3}"
您可以通过设置internal-proxies 清空(但在生产中不要这样做)。 |
您可以完全控制 Tomcat 的RemoteIpValve
通过关闭自动按钮(为此,请将server.forward-headers-strategy=NONE
)并使用WebServerFactoryCustomizer
豆。
3.13. 使用 Tomcat 启用多个连接器
您可以添加一个org.apache.catalina.connector.Connector
到TomcatServletWebServerFactory
,可以允许多个连接器,包括 HTTP 和 HTTPS 连接器,如以下示例所示:
@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;
}
}
@Configuration(proxyBeanMethods = false)
class MyTomcatConfiguration {
@Bean
fun connectorCustomizer(): WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
return WebServerFactoryCustomizer { tomcat: TomcatServletWebServerFactory ->
tomcat.addAdditionalTomcatConnectors(
createConnector()
)
}
}
private fun createConnector(): Connector {
val connector = Connector("org.apache.coyote.http11.Http11NioProtocol")
connector.port = 8081
return connector
}
}
3.14. 使用 Tomcat 的 LegacyCookieProcessor
默认情况下,Spring Boot 使用的嵌入式 Tomcat 不支持 Cookie 格式的“版本 0”,因此您可能会看到以下错误:
java.lang.IllegalArgumentException: An invalid character [32] was present in the Cookie value
如果可能的话,您应该考虑更新代码以仅存储符合更高 Cookie 规范的值。
但是,如果您无法更改 cookie 的写入方式,则可以将 Tomcat 配置为使用LegacyCookieProcessor
.
要切换到LegacyCookieProcessor
,请使用WebServerFactoryCustomizer
bean 添加TomcatContextCustomizer
,如以下示例所示:
@Configuration(proxyBeanMethods = false)
public class MyLegacyCookieProcessorConfiguration {
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> cookieProcessorCustomizer() {
return (factory) -> factory
.addContextCustomizers((context) -> context.setCookieProcessor(new LegacyCookieProcessor()));
}
}
@Configuration(proxyBeanMethods = false)
class MyLegacyCookieProcessorConfiguration {
@Bean
fun cookieProcessorCustomizer(): WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
return WebServerFactoryCustomizer { factory: TomcatServletWebServerFactory ->
factory
.addContextCustomizers(TomcatContextCustomizer { context: Context ->
context.cookieProcessor = LegacyCookieProcessor()
})
}
}
}
3.15. 启用 Tomcat 的 MBean 注册表
默认情况下,嵌入式 Tomcat 的 MBean 注册表处于禁用状态。
这最大限度地减少了 Tomcat 的内存占用。
例如,如果您想使用 Tomcat 的 MBean,以便 Micrometer 可以使用它们来公开指标,则必须使用server.tomcat.mbeanregistry.enabled
属性来执行此作,如以下示例所示:
server.tomcat.mbeanregistry.enabled=true
server:
tomcat:
mbeanregistry:
enabled: true
3.16. 使用 Undertow 启用多个监听器
添加一个UndertowBuilderCustomizer
到UndertowServletWebServerFactory
并将监听器添加到Builder
,如以下示例所示:
@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");
}
}
@Configuration(proxyBeanMethods = false)
class MyUndertowConfiguration {
@Bean
fun undertowListenerCustomizer(): WebServerFactoryCustomizer<UndertowServletWebServerFactory> {
return WebServerFactoryCustomizer { factory: UndertowServletWebServerFactory ->
factory.addBuilderCustomizers(
UndertowBuilderCustomizer { builder: Undertow.Builder -> addHttpListener(builder) })
}
}
private fun addHttpListener(builder: Undertow.Builder): Undertow.Builder {
return builder.addHttpListener(8080, "0.0.0.0")
}
}
3.17. 使用 @ServerEndpoint 创建 WebSocket 端点
如果你想使用@ServerEndpoint
在使用嵌入式容器的 Spring Boot 应用程序中,您必须声明单个ServerEndpointExporter
@Bean
,如以下示例所示:
@Configuration(proxyBeanMethods = false)
public class MyWebSocketConfiguration {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
@Configuration(proxyBeanMethods = false)
class MyWebSocketConfiguration {
@Bean
fun serverEndpointExporter(): ServerEndpointExporter {
return ServerEndpointExporter()
}
}
前面示例中显示的 bean 注册任何@ServerEndpoint
带有底层 WebSocket 容器的 Comments Bean。
当部署到独立的 servlet 容器时,此角色由 servlet 容器初始值设定项执行,并且ServerEndpointExporter
不需要 bean。
4. 弹簧MVC
Spring Boot 有许多Starters,其中包括 Spring MVC。 请注意,一些Starters包含对 Spring MVC 的依赖,而不是直接包含它。 本节回答有关 Spring MVC 和 Spring Boot 的常见问题。
4.1. 编写JSON REST服务
任何弹簧@RestController
在 Spring Boot 应用程序中,只要 Jackson2 在类路径上,就应该默认呈现 JSON 响应,如以下示例所示:
@RestController
public class MyController {
@RequestMapping("/thing")
public MyThing thing() {
return new MyThing();
}
}
@RestController
class MyController {
@RequestMapping("/thing")
fun thing(): MyThing {
return MyThing()
}
}
只要MyThing
可以由 Jackson2 序列化(对于普通的 POJO 或 Groovy 对象为 true),然后localhost:8080/thing
默认情况下,提供它的 JSON 表示形式。
请注意,在浏览器中,您有时可能会看到 XML 响应,因为浏览器倾向于发送首选 XML 的接受标头。
4.2. 编写 XML REST 服务
如果您有 Jackson XML 扩展 (jackson-dataformat-xml
) 在类路径上,您可以使用它来呈现 XML 响应。
我们用于 JSON 的前面示例可以工作。
要使用 Jackson XML 渲染器,请向项目添加以下依赖项:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
如果 Jackson 的 XML 扩展不可用,而 JAXB 可用,则可以呈现 XML 并具有MyThing
注释为@XmlRootElement
,如以下示例所示:
@XmlRootElement
public class MyThing {
private String name;
}
@XmlRootElement
class MyThing {
var name: String? = null
}
JAXB 仅在 Java 8 中开箱即用。 如果您使用较新的一代 Java,请向项目添加以下依赖项:
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
</dependency>
要让服务器呈现 XML 而不是 JSON,您可能需要发送Accept: text/xml 标头(或使用浏览器)。 |
4.3. 自定义 Jackson ObjectMapper
Spring MVC(客户端和服务器端)使用HttpMessageConverters
在 HTTP 交换中协商内容转换。
如果 Jackson 在类路径上,则您已经获得了由Jackson2ObjectMapperBuilder
,其实例是自动配置的。
这ObjectMapper
(或XmlMapper
对于 Jackson XML 转换器)实例(默认创建)具有以下自定义属性:
-
MapperFeature.DEFAULT_VIEW_INCLUSION
已禁用 -
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
已禁用 -
SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
已禁用 -
SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS
已禁用
Spring Boot 还具有一些功能,可以更轻松地自定义此行为。
您可以配置ObjectMapper
和XmlMapper
实例。
Jackson 提供了一套广泛的开/关功能,可用于配置其处理的各个方面。
这些功能在六个枚举(在 Jackson 中)中描述,这些枚举映射到环境中的属性:
枚举 | 属性 | 值 |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
例如,要启用漂亮打印,请将spring.jackson.serialization.indent_output=true
.
请注意,由于使用了宽松的绑定,因此indent_output
不必匹配相应枚举常量的大小写,即INDENT_OUTPUT
.
此基于环境的配置应用于自动配置的Jackson2ObjectMapperBuilder
bean 并适用于使用构建器创建的任何映射器,包括自动配置的ObjectMapper
豆。
上下文的Jackson2ObjectMapperBuilder
可由一个或多个定制Jackson2ObjectMapperBuilderCustomizer
豆。
可以对此类定制器 bean 进行排序(Boot 自己的定制器的顺序为 0),以便在 Boot 的自定义之前和之后应用额外的自定义。
任何类型的 beancom.fasterxml.jackson.databind.Module
自动注册到自动配置的Jackson2ObjectMapperBuilder
并适用于任何ObjectMapper
它创建的实例。
这提供了一种全局机制,用于在向应用程序添加新功能时贡献自定义模块。
如果要替换默认值ObjectMapper
完全,要么定义一个@Bean
并将其标记为@Primary
或者,如果您更喜欢基于构建器的方法,请定义一个Jackson2ObjectMapperBuilder
@Bean
.
请注意,无论哪种情况,这样做都会禁用ObjectMapper
.
如果您提供任何@Beans
类型MappingJackson2HttpMessageConverter
,它们替换了 MVC 配置中的默认值。
另外,一种方便的豆子HttpMessageConverters
(如果您使用默认 MVC 配置,则始终可用)。
它有一些有用的方法来访问默认和用户增强的消息转换器。
请参阅“自定义@ResponseBody渲染”部分和WebMvcAutoConfiguration
源代码了解更多详情。
4.4. 自定义@ResponseBody渲染
弹簧用途HttpMessageConverters
渲染@ResponseBody
(或来自@RestController
).
您可以通过在 Spring Boot 上下文中添加适当类型的 bean 来贡献其他转换器。
如果您添加的 bean 的类型无论如何都会被默认包含(例如MappingJackson2HttpMessageConverter
对于 JSON 转换),它会替换默认值。
一种方便的豆子HttpMessageConverters
提供,并且如果您使用默认 MVC 配置,则始终可用。
它有一些有用的方法来访问默认和用户增强的消息转换器(例如,如果您想将它们手动注入到自定义RestTemplate
).
与正常的 MVC 用法一样,任何WebMvcConfigurer
您提供的 bean 也可以通过覆盖configureMessageConverters
方法。
但是,与普通 MVC 不同的是,您只能提供所需的其他转换器(因为 Spring Boot 使用相同的机制来贡献其默认值)。
最后,如果您通过提供自己的 MVC 配置来选择退出 Spring Boot 默认 MVC 配置@EnableWebMvc
配置,您可以完全控制并使用getMessageConverters
从WebMvcConfigurationSupport
.
请参阅WebMvcAutoConfiguration
源代码了解更多详情。
4.5. 处理多部分文件上传
Spring Boot 采用 servlet 3javax.servlet.http.Part
支持上传文件的 API。
默认情况下,Spring Boot 将 Spring MVC 配置为每个文件的最大大小为 1MB,单个请求中最多 10MB 的文件数据。
您可以覆盖这些值,即中间数据存储的位置(例如,到/tmp
目录),以及使用中公开的属性将数据刷新到磁盘的阈值MultipartProperties
类。
例如,如果要指定文件不受限制,请将spring.servlet.multipart.max-file-size
属性设置为-1
.
当您想要接收多部分编码的文件数据作为@RequestParam
-annotated 类型的参数MultipartFile
在 Spring MVC 控制器处理程序方法中。
请参阅MultipartAutoConfiguration
来源了解更多详情。
建议使用容器对分段上传的内置支持,而不是引入额外的依赖项,例如 Apache Commons 文件上传。 |
4.6. 关闭 Spring MVC DispatcherServlet
默认情况下,所有内容都从应用程序的根目录 () 提供。
如果您希望映射到不同的路径,可以按如下方式配置一个路径:/
spring.mvc.servlet.path=/mypath
spring:
mvc:
servlet:
path: "/mypath"
如果你有其他 servlet,你可以声明一个@Bean
类型Servlet
或ServletRegistrationBean
对于每个,Spring Boot 会将它们透明地注册到容器中。
因为 servlet 是以这种方式注册的,所以它们可以映射到DispatcherServlet
而不调用它。
配置DispatcherServlet
你自己很不寻常,但如果你真的需要这样做,一个@Bean
类型DispatcherServletPath
还必须提供自定义的路径DispatcherServlet
.
4.8. 自定义ViewResolver
一个ViewResolver
是 Spring MVC 的核心组件,将视图名称翻译为@Controller
到实际View
实现。
请注意ViewResolvers
主要用于 UI 应用程序,而不是 REST 风格的服务(View
不用于渲染@ResponseBody
).
有很多实现ViewResolver
可供选择,Spring 本身对您应该使用哪些并不固执己见。
另一方面,Spring Boot 会为您安装一两个,具体取决于它在类路径和应用程序上下文中找到的内容。
这DispatcherServlet
使用它在应用程序上下文中找到的所有解析器,依次尝试每个解析器,直到得到结果。
如果您添加自己的解析器,则必须了解添加解析器的顺序和位置。
WebMvcAutoConfiguration
添加以下内容ViewResolvers
到你的上下文:
-
一
InternalResourceViewResolver
名为 'defaultViewResolver' 。 此按钮可查找可使用DefaultServlet
(包括静态资源和 JSP 页面,如果您使用它们)。 它将前缀和后缀应用于视图名称,然后在 servlet 上下文中查找具有该路径的物理资源(默认值均为空,但可以通过外部配置访问spring.mvc.view.prefix
和spring.mvc.view.suffix
). 您可以通过提供相同类型的 bean 来覆盖它。 -
一个
BeanNameViewResolver
名为 'beanNameViewResolver'。 这是视图解析器链的有用成员,并选择与View
正在解决。 没有必要覆盖或替换它。 -
一个
ContentNegotiatingViewResolver
仅当实际存在类型为View
目前。 这是一个复合解析器,委托给所有其他解析器,并尝试查找与客户端发送的“Accept”HTTP 标头匹配的解析器。 有一个有用的博客 关于ContentNegotiatingViewResolver
您可能想学习以了解更多信息,并且还可以查看源代码以获取详细信息。 您可以关闭自动配置的ContentNegotiatingViewResolver
通过定义一个名为“viewResolver”的 bean。 -
如果您使用百里叶烟,您还有一个
ThymeleafViewResolver
命名为“thymeleafViewResolver”。 它通过用前缀和后缀包围视图名称来查找资源。 前缀是spring.thymeleaf.prefix
,后缀为spring.thymeleaf.suffix
. 前缀和后缀的值分别默认为 'classpath:/templates/' 和 '.html'。 您可以覆盖ThymeleafViewResolver
通过提供同名的 bean。 -
如果您使用 FreeMarker,您还有一个
FreeMarkerViewResolver
名为 'freeMarkerViewResolver'。 它在加载器路径中查找资源(外部化为spring.freemarker.templateLoaderPath
并且默认值为 'classpath:/templates/'),方法是用前缀和后缀将视图名称括起来。 前缀被外部化为spring.freemarker.prefix
,后缀被外部化为spring.freemarker.suffix
. 前缀和后缀的默认值分别为空和“.ftlh”。 您可以覆盖FreeMarkerViewResolver
通过提供同名的 bean。 -
如果您使用 Groovy 模板(实际上,如果
groovy-templates
在您的类路径上),您还有一个GroovyMarkupViewResolver
命名为 'groovyMarkupViewResolver'。 它通过用前缀和后缀(外部化为spring.groovy.template.prefix
和spring.groovy.template.suffix
). 前缀和后缀的默认值分别为 'classpath:/templates/' 和 '.tpl'。 您可以覆盖GroovyMarkupViewResolver
通过提供同名的 bean。 -
如果您使用 Mustache,您还有一个
MustacheViewResolver
名为 'mustacheViewResolver'。 它通过用前缀和后缀包围视图名称来查找资源。 前缀是spring.mustache.prefix
,后缀为spring.mustache.suffix
. 前缀和后缀的值分别默认为 'classpath:/templates/' 和 '.mustache'。 您可以覆盖MustacheViewResolver
通过提供同名的 bean。
有关更多详细信息,请参阅以下部分:
5. 球衣
5.1. 使用 Spring Security 保护 Jersey 端点
Spring Security 可用于保护基于Jersey的 Web 应用程序,其方式与用于保护基于 Spring MVC 的 Web 应用程序的方式大致相同。
但是,如果要将 Spring Security 的方法级安全性与 Jersey 一起使用,则必须将 Jersey 配置为setStatus(int)
而sendError(int)
.
这可以防止 Jersey 在 Spring Security 有机会向客户端报告身份验证或授权失败之前提交响应。
这jersey.config.server.response.setStatusOverSendError
属性必须设置为true
在应用程序的ResourceConfig
bean,如以下示例所示:
@Component
public class JerseySetStatusOverSendErrorConfig extends ResourceConfig {
public JerseySetStatusOverSendErrorConfig() {
register(Endpoint.class);
setProperties(Collections.singletonMap("jersey.config.server.response.setStatusOverSendError", true));
}
}
@Component
class JerseySetStatusOverSendErrorConfig : ResourceConfig() {
init {
register(Endpoint::class.java)
setProperties(Collections.singletonMap("jersey.config.server.response.setStatusOverSendError", true))
}
}
5.2. 将 Jersey 与其他 Web 框架一起使用
要将 Jersey 与另一个 Web 框架(例如 Spring MVC)一起使用,应对其进行配置,以便允许其他框架处理它无法处理的请求。
首先,通过配置spring.jersey.type
application 属性,值为filter
.
其次,配置您的ResourceConfig
转发可能导致 404 的请求,如以下示例所示。
@Component
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(Endpoint.class);
property(ServletProperties.FILTER_FORWARD_ON_404, true);
}
}
@Component
class JerseyConfig : ResourceConfig() {
init {
register(Endpoint::class.java)
property(ServletProperties.FILTER_FORWARD_ON_404, true)
}
}
6. HTTP 客户端
Spring Boot 提供了许多与 HTTP 客户端配合使用的Starters。 本节回答与使用它们相关的问题。
6.1. 配置 RestTemplate 以使用代理
如io.html中所述,您可以使用RestTemplateCustomizer
跟RestTemplateBuilder
构建自定义的RestTemplate
.
这是创建RestTemplate
配置为使用代理。
代理配置的确切详细信息取决于正在使用的基础客户端请求工厂。
6.2. 配置基于 Reactor Netty 的 WebClient 使用的 TcpClient
当 Reactor Netty 位于基于 Reactor Netty 的类路径上时WebClient
是自动配置的。
要自定义客户端对网络连接的处理,请提供ClientHttpConnector
豆。
以下示例配置了 60 秒的连接超时,并添加了一个ReadTimeoutHandler
:
@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);
}
}
@Configuration(proxyBeanMethods = false)
class MyReactorNettyClientConfiguration {
@Bean
fun clientHttpConnector(resourceFactory: ReactorResourceFactory): ClientHttpConnector {
val httpClient = HttpClient.create(resourceFactory.connectionProvider)
.runOn(resourceFactory.loopResources)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 60000)
.doOnConnected { connection ->
connection.addHandlerLast(ReadTimeoutHandler(60))
}
return ReactorClientHttpConnector(httpClient)
}
}
请注意ReactorResourceFactory 用于连接提供程序和事件循环资源。
这确保了接收请求的服务器和发出请求的客户端的资源高效共享。 |
7. 日志记录
Spring Boot 没有强制性的日志记录依赖项,除了 Commons Logging API,它通常由 Spring Framework 的spring-jcl
模块。
要使用 Logback,您需要将其包含在内,并且spring-jcl
在类路径上。
推荐的方法是通过Starters,这都依赖于Startersspring-boot-starter-logging
.
对于 Web 应用程序,您只需要spring-boot-starter-web
,因为它传递地依赖于日志记录Starters。
如果您使用 Maven,则以下依赖项会为您添加日志记录:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Spring Boot 有一个LoggingSystem
尝试根据类路径的内容配置日志记录的抽象。
如果 Logback 可用,它是首选。
如果您需要对日志记录进行的唯一更改是设置各种记录器的级别,则可以在application.properties
使用“logging.level”前缀,如以下示例所示:
logging.level.org.springframework.web=debug
logging.level.org.hibernate=error
logging:
level:
org.springframework.web: "debug"
org.hibernate: "error"
您还可以使用logging.file.name
.
要配置日志记录系统的更细粒度的设置,您需要使用LoggingSystem
有问题。
默认情况下,Spring Boot 从系统的默认位置(例如classpath:logback.xml
对于 Logback),但您可以使用logging.config
财产。
7.1. 配置日志记录的 Logback
如果您需要将自定义应用于日志备份,则超出了可以使用application.properties
,则需要添加一个标准的 logback 配置文件。您可以添加一个logback.xml
文件到你的类路径的根目录,以便 logback 查找。你也可以使用logback-spring.xml
如果您想使用 Spring Boot Logback 扩展。
Logback 文档有一个专门的部分,详细介绍了配置。 |
Spring Boot 提供了许多回登录配置,这些配置可以included
在您自己的配置中。这些包含旨在允许重新应用某些常见的 Spring Boot 约定。
以下文件在org/springframework/boot/logging/logback/
:
-
defaults.xml
- 提供转换规则、模式属性和常见的记录器配置。 -
console-appender.xml
- 添加一个ConsoleAppender
使用CONSOLE_LOG_PATTERN
. -
file-appender.xml
- 添加一个RollingFileAppender
使用FILE_LOG_PATTERN
和ROLLING_FILE_NAME_PATTERN
使用适当的设置。
此外,遗产base.xml
文件是为了与早期版本的 Spring Boot 兼容而提供的。
典型的习俗logback.xml
文件将如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
<logger name="org.springframework.web" level="DEBUG"/>
</configuration>
您的日志备份配置文件还可以使用系统属性,即LoggingSystem
负责为您创作:
-
${PID}
:当前进程 ID。 -
${LOG_FILE}
:是否logging.file.name
在 Boot 的外部配置中设置。 -
${LOG_PATH}
:是否logging.file.path
(表示日志文件所在的目录)是在 Boot 的外部配置中设置的。 -
${LOG_EXCEPTION_CONVERSION_WORD}
:是否logging.exception-conversion-word
在 Boot 的外部配置中设置。 -
${ROLLING_FILE_NAME_PATTERN}
:是否logging.pattern.rolling-file-name
在 Boot 的外部配置中设置。
Spring Boot 还通过使用自定义 Logback 转换器在控制台(但不是日志文件中)提供一些不错的 ANSI 颜色终端输出。
请参阅CONSOLE_LOG_PATTERN
在defaults.xml
配置。
如果 Groovy 在类路径上,您应该能够使用logback.groovy
也。
如果存在,则优先考虑此设置。
Groovy 配置不支持 Spring 扩展。
任何logback-spring.groovy 文件将不会被检测到。 |
7.1.1. 为仅文件输出配置日志返回
如果要禁用控制台日志记录并仅将输出写入文件,则需要自定义logback-spring.xml
该进口file-appender.xml
但不是console-appender.xml
,如以下示例所示:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>
您还需要添加logging.file.name
给你的application.properties
或application.yaml
,如以下示例所示:
logging.file.name=myapplication.log
logging:
file:
name: "myapplication.log"
7.2. 配置 Log4j 进行日志记录
如果 Log4j 2 位于类路径上,则 Spring Boot 支持 Log4j 2 进行日志记录配置。
如果您使用Starters来组装依赖项,则必须排除 Logback,然后包含 log4j 2。
如果您不使用Starters,则需要提供(至少)spring-jcl
除了 Log4j 2.
推荐的路径是通过Starters,尽管它需要一些抖动。 以下示例显示了如何在 Maven 中设置Starters:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
Gradle 提供了几种不同的方法来设置Starters。 一种方法是使用模块替换。 为此,请声明对 Log4j 2 Starters的依赖项,并告诉 Gradle 默认日志记录Starters的任何出现都应替换为 Log4j 2 Starters,如以下示例所示:
dependencies {
implementation "org.springframework.boot:spring-boot-starter-log4j2"
modules {
module("org.springframework.boot:spring-boot-starter-logging") {
replacedBy("org.springframework.boot:spring-boot-starter-log4j2", "Use Log4j2 instead of Logback")
}
}
}
Log4j Starters将常见日志记录要求的依赖项收集在一起(例如让 Tomcat 使用java.util.logging 但使用 Log4j 配置输出 2)。 |
要确保使用java.util.logging 路由到 Log4j 2 中,通过设置java.util.logging.manager 系统属性设置为org.apache.logging.log4j.jul.LogManager . |
7.2.1. 使用 YAML 或 JSON 配置 log4j 2
除了默认的 XML 配置格式外,Log4j 2 还支持 YAML 和 JSON 配置文件。 要将 Log4j 2 配置为使用替代配置文件格式,请将适当的依赖项添加到类路径,并命名配置文件以匹配您选择的文件格式,如以下示例所示:
格式 | 依赖 | 文件名 |
---|---|---|
YAML |
|
|
JSON |
|
|
8. 数据访问
Spring Boot 包括许多用于处理数据源的Starters。 本节回答与执行此作相关的问题。
8.1. 配置自定义数据源
配置您自己的DataSource
,定义一个@Bean
配置中的该类型。
Spring Boot 重用了DataSource
任何需要的地方,包括数据库初始化。
如果需要外部化某些设置,可以绑定DataSource
对环境的影响(参见“features.html”)。
以下示例显示了如何在 Bean 中定义数据源:
@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {
@Bean
@ConfigurationProperties(prefix = "app.datasource")
public SomeDataSource dataSource() {
return new SomeDataSource();
}
}
@Configuration(proxyBeanMethods = false)
class MyDataSourceConfiguration {
@Bean
@ConfigurationProperties(prefix = "app.datasource")
fun dataSource(): SomeDataSource {
return SomeDataSource()
}
}
以下示例演示如何通过设置属性来定义数据源:
app.datasource.url=jdbc:h2:mem:mydb
app.datasource.username=sa
app.datasource.pool-size=30
app:
datasource:
url: "jdbc:h2:mem:mydb"
username: "sa"
pool-size: 30
假设SomeDataSource
具有 URL、用户名和池大小的常规 JavaBean 属性,这些设置在DataSource
可用于其他组件。
Spring Boot 还提供了一个实用程序构建器类,称为DataSourceBuilder
,可用于创建标准数据源之一(如果它在类路径上)。
构建器可以根据类路径上可用的内容来检测要使用的那个。
它还会根据 JDBC URL 自动检测驱动程序。
以下示例演示如何使用DataSourceBuilder
:
@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {
@Bean
@ConfigurationProperties("app.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
}
@Configuration(proxyBeanMethods = false)
class MyDataSourceConfiguration {
@Bean
@ConfigurationProperties("app.datasource")
fun dataSource(): DataSource {
return DataSourceBuilder.create().build()
}
}
要运行该应用DataSource
,您所需要的只是连接信息。
还可以提供特定于池的设置。
检查将在运行时使用的实现以了解更多详细信息。
以下示例显示了如何通过设置属性来定义 JDBC 数据源:
app.datasource.url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.pool-size=30
app:
datasource:
url: "jdbc:mysql://localhost/test"
username: "dbuser"
password: "dbpass"
pool-size: 30
然而,有一个问题。
由于未公开连接池的实际类型,因此不会在自定义的元数据中生成任何密钥DataSource
并且 IDE 中没有可用的补全(因为DataSource
接口不公开任何属性)。
此外,如果您碰巧在类路径上有 Hikari,则此基本设置不起作用,因为 Hikari 没有url
属性(但确实有一个jdbcUrl
属性)。
在这种情况下,您必须按如下方式重写配置:
app.datasource.jdbc-url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.pool-size=30
app:
datasource:
jdbc-url: "jdbc:mysql://localhost/test"
username: "dbuser"
password: "dbpass"
pool-size: 30
您可以通过强制连接池使用并返回专用实现而不是DataSource
.
您无法在运行时更改实现,但选项列表将是显式的。
以下示例显示了如何创建HikariDataSource
跟DataSourceBuilder
:
@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {
@Bean
@ConfigurationProperties("app.datasource")
public HikariDataSource dataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
}
@Configuration(proxyBeanMethods = false)
class MyDataSourceConfiguration {
@Bean
@ConfigurationProperties("app.datasource")
fun dataSource(): HikariDataSource {
return DataSourceBuilder.create().type(HikariDataSource::class.java).build()
}
}
您甚至可以通过利用DataSourceProperties
为您做——也就是说,如果未提供 URL,则通过提供带有合理用户名和密码的默认嵌入式数据库。
您可以轻松初始化DataSourceBuilder
从任何状态DataSourceProperties
对象,因此您还可以注入 Spring Boot 自动创建的 DataSource。
但是,这会将您的配置拆分为两个命名空间:url
,username
,password
,type
和driver
上spring.datasource
其余的则位于自定义命名空间 (app.datasource
).
为避免这种情况,您可以重新定义自定义DataSourceProperties
,如以下示例所示:
@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();
}
}
@Configuration(proxyBeanMethods = false)
class MyDataSourceConfiguration {
@Bean
@Primary
@ConfigurationProperties("app.datasource")
fun dataSourceProperties(): DataSourceProperties {
return DataSourceProperties()
}
@Bean
@ConfigurationProperties("app.datasource.configuration")
fun dataSource(properties: DataSourceProperties): HikariDataSource {
return properties.initializeDataSourceBuilder().type(HikariDataSource::class.java).build()
}
}
此设置使您与 Spring Boot 默认为您执行的作同步,只是选择了一个专用连接池(在代码中)并且其设置在app.datasource.configuration
sub 命名空间。
因为DataSourceProperties
正在照顾url
/jdbcUrl
翻译,您可以按如下方式进行配置:
app.datasource.url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.configuration.maximum-pool-size=30
app:
datasource:
url: "jdbc:mysql://localhost/test"
username: "dbuser"
password: "dbpass"
configuration:
maximum-pool-size: 30
Spring Boot 将 Hikari 特定设置公开给spring.datasource.hikari .
此示例使用更通用的configuration sub 命名空间,因为示例不支持多个数据源实现。 |
因为您的自定义配置选择使用 Hikari,app.datasource.type 没有效果。
实际上,构建器会使用您可能在那里设置的任何值进行初始化,然后被调用.type() . |
请参阅“Spring Boot 功能”部分中的“data.html”和DataSourceAutoConfiguration
class 了解更多详情。
8.2. 配置两个数据源
如果需要配置多个数据源,可以应用上一节中所述的相同技巧。
但是,您必须标记其中一个DataSource
实例作为@Primary
,因为未来的各种自动配置都希望能够按类型获得一个。
如果您创建自己的DataSource
,则自动配置将回退。
在以下示例中,我们提供了与自动配置在主数据源上提供的完全相同的功能集:
@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();
}
}
@Configuration(proxyBeanMethods = false)
class MyDataSourcesConfiguration {
@Bean
@Primary
@ConfigurationProperties("app.datasource.first")
fun firstDataSourceProperties(): DataSourceProperties {
return DataSourceProperties()
}
@Bean
@Primary
@ConfigurationProperties("app.datasource.first.configuration")
fun firstDataSource(firstDataSourceProperties: DataSourceProperties): HikariDataSource {
return firstDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource::class.java).build()
}
@Bean
@ConfigurationProperties("app.datasource.second")
fun secondDataSource(): BasicDataSource {
return DataSourceBuilder.create().type(BasicDataSource::class.java).build()
}
}
firstDataSourceProperties 必须标记为@Primary 以便数据库初始值设定项功能使用您的副本(如果您使用初始值设定项)。 |
这两个数据源也绑定为高级自定义。 例如,您可以按如下方式配置它们:
app.datasource.first.url=jdbc:mysql://localhost/first
app.datasource.first.username=dbuser
app.datasource.first.password=dbpass
app.datasource.first.configuration.maximum-pool-size=30
app.datasource.second.url=jdbc:mysql://localhost/second
app.datasource.second.username=dbuser
app.datasource.second.password=dbpass
app.datasource.second.max-total=30
app:
datasource:
first:
url: "jdbc:mysql://localhost/first"
username: "dbuser"
password: "dbpass"
configuration:
maximum-pool-size: 30
second:
url: "jdbc:mysql://localhost/second"
username: "dbuser"
password: "dbpass"
max-total: 30
您可以将相同的概念应用于辅助DataSource
同样,如以下示例所示:
@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();
}
}
@Configuration(proxyBeanMethods = false)
class MyCompleteDataSourcesConfiguration {
@Bean
@Primary
@ConfigurationProperties("app.datasource.first")
fun firstDataSourceProperties(): DataSourceProperties {
return DataSourceProperties()
}
@Bean
@Primary
@ConfigurationProperties("app.datasource.first.configuration")
fun firstDataSource(firstDataSourceProperties: DataSourceProperties): HikariDataSource {
return firstDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource::class.java).build()
}
@Bean
@ConfigurationProperties("app.datasource.second")
fun secondDataSourceProperties(): DataSourceProperties {
return DataSourceProperties()
}
@Bean
@ConfigurationProperties("app.datasource.second.configuration")
fun secondDataSource(secondDataSourceProperties: DataSourceProperties): BasicDataSource {
return secondDataSourceProperties.initializeDataSourceBuilder().type(BasicDataSource::class.java).build()
}
}
前面的示例在自定义命名空间上配置了两个数据源,其逻辑与 Spring Boot 在自动配置中使用的逻辑相同。
请注意,每个configuration
子命名空间根据所选实现提供高级设置。
8.3. 使用 Spring Data Repositories
Spring Data 可以创建@Repository
各种口味的界面。
Spring Boot 会为您处理所有这些,只要这些@Repositories
包含在其中一个自动配置包中,通常是主应用程序类的包(或子包),该类的注释为@SpringBootApplication
或@EnableAutoConfiguration
.
对于许多应用程序,您所需要做的就是在类路径上放置正确的 Spring Data 依赖项。
有一个spring-boot-starter-data-jpa
对于 JPA,spring-boot-starter-data-mongodb
用于 Mongodb,以及支持技术的其他各种Starters。
首先,请创建一些存储库接口来处理@Entity
对象。
Spring Boot 确定您的@Repository
通过扫描自动配置包来定义。
要获得更多控制,请使用@Enable…Repositories
来自 Spring Data 的注释。
有关 Spring Data 的更多信息,请参阅 Spring Data 项目页面。
8.4. 将@Entity定义与 Spring 配置分开
Spring Boot 确定您的@Entity
通过扫描自动配置包来定义。
要获得更多控制,请使用@EntityScan
注释,如以下示例所示:
@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
@EntityScan(basePackageClasses = City.class)
public class MyApplication {
// ...
}
@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
@EntityScan(basePackageClasses = [City::class])
class MyApplication {
// ...
}
8.5. 配置JPA属性
Spring Data JPA 已经提供了一些独立于提供商的配置选项(例如用于 SQL 日志记录的选项),并且 Spring Boot 将这些选项以及 Hibernate 的更多选项公开为外部配置属性。 其中一些是根据上下文自动检测的,因此您不必设置它们。
这spring.jpa.hibernate.ddl-auto
是一种特殊情况,因为根据运行时条件,它具有不同的默认值。
如果使用嵌入式数据库,并且没有模式管理器(例如 Liquibase 或 Flyway)处理DataSource
,则默认为create-drop
.
在所有其他情况下,它默认为none
.
JPA 提供程序检测到要使用的方言。
如果您更喜欢自己设置方言,请将spring.jpa.database-platform
财产。
以下示例显示了最常见的设置选项:
spring.jpa.hibernate.naming.physical-strategy=com.example.MyPhysicalNamingStrategy
spring.jpa.show-sql=true
spring:
jpa:
hibernate:
naming:
physical-strategy: "com.example.MyPhysicalNamingStrategy"
show-sql: true
此外,中的所有属性spring.jpa.properties.*
当本地EntityManagerFactory
被创建。
您需要确保在 例如,如果要配置 Hibernate 的批量大小,则必须使用 |
如果您需要对 Hibernate 属性应用高级自定义,请考虑注册一个HibernatePropertiesCustomizer bean,该 bean 将在创建EntityManagerFactory .
这优先于自动配置应用的任何内容。 |
8.6. 配置休眠命名策略
Hibernate 使用两种不同的命名策略将对象模型中的名称映射到相应的数据库名称。
物理和隐式策略实现的完全限定类名可以通过设置spring.jpa.hibernate.naming.physical-strategy
和spring.jpa.hibernate.naming.implicit-strategy
属性。
或者,如果ImplicitNamingStrategy
或PhysicalNamingStrategy
bean 在应用程序上下文中可用,Hibernate 将自动配置为使用它们。
默认情况下,Spring Boot 使用CamelCaseToUnderscoresNamingStrategy
.
使用此策略,所有点都替换为下划线,驼峰大小写也替换为下划线。
此外,默认情况下,所有表名都以小写形式生成。
例如,一个TelephoneNumber
实体映射到telephone_number
桌子。
如果您的架构需要混合大小写标识符,请定义自定义CamelCaseToUnderscoresNamingStrategy
bean,如以下示例所示:
@Configuration(proxyBeanMethods = false)
public class MyHibernateConfiguration {
@Bean
public CamelCaseToUnderscoresNamingStrategy caseSensitivePhysicalNamingStrategy() {
return new CamelCaseToUnderscoresNamingStrategy() {
@Override
protected boolean isCaseInsensitive(JdbcEnvironment jdbcEnvironment) {
return false;
}
};
}
}
@Configuration(proxyBeanMethods = false)
class MyHibernateConfiguration {
@Bean
fun caseSensitivePhysicalNamingStrategy(): CamelCaseToUnderscoresNamingStrategy {
return object : CamelCaseToUnderscoresNamingStrategy() {
override fun isCaseInsensitive(jdbcEnvironment: JdbcEnvironment): Boolean {
return false
}
}
}
}
如果您更喜欢使用 Hibernate 5 的默认值,请设置以下属性:
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
或者,您可以配置以下 bean:
@Configuration(proxyBeanMethods = false)
class MyHibernateConfiguration {
@Bean
PhysicalNamingStrategyStandardImpl caseSensitivePhysicalNamingStrategy() {
return new PhysicalNamingStrategyStandardImpl();
}
}
@Configuration(proxyBeanMethods = false)
internal class MyHibernateConfiguration {
@Bean
fun caseSensitivePhysicalNamingStrategy(): PhysicalNamingStrategyStandardImpl {
return PhysicalNamingStrategyStandardImpl()
}
}
8.7. 配置休眠二级缓存
可以为一系列缓存提供程序配置 Hibernate 二级缓存。 与其将 Hibernate 配置为再次查找缓存提供者,不如尽可能提供上下文中可用的缓存提供者。
要使用 JCache 执行此作,请首先确保org.hibernate:hibernate-jcache
在类路径上可用。
然后,添加一个HibernatePropertiesCustomizer
bean,如以下示例所示:
@Configuration(proxyBeanMethods = false)
public class MyHibernateSecondLevelCacheConfiguration {
@Bean
public HibernatePropertiesCustomizer hibernateSecondLevelCacheCustomizer(JCacheCacheManager cacheManager) {
return (properties) -> properties.put(ConfigSettings.CACHE_MANAGER, cacheManager.getCacheManager());
}
}
@Configuration(proxyBeanMethods = false)
class MyHibernateSecondLevelCacheConfiguration {
@Bean
fun hibernateSecondLevelCacheCustomizer(cacheManager: JCacheCacheManager): HibernatePropertiesCustomizer {
return HibernatePropertiesCustomizer { properties ->
properties[ConfigSettings.CACHE_MANAGER] = cacheManager.cacheManager
}
}
}
此定制器将配置 Hibernate 以使用相同的CacheManager
作为应用程序使用的。
也可以单独使用CacheManager
实例。
有关详细信息,请参阅 Hibernate 用户指南。
8.8. 在Hibernate组件中使用依赖注入
默认情况下,Spring Boot 注册一个BeanContainer
使用BeanFactory
以便转换器和实体侦听器可以使用定期依赖注入。
您可以通过注册HibernatePropertiesCustomizer
删除或更改hibernate.resource.beans.container
财产。
8.9. 使用自定义 EntityManagerFactory
要完全控制EntityManagerFactory
,您需要添加一个@Bean
名为“entityManagerFactory”。
Spring Boot 自动配置在存在该类型的 bean 时关闭其实体管理器。
8.10. 使用多个 EntityManagerFactories
如果您需要对多个数据源使用 JPA,您可能需要一个EntityManagerFactory
每个数据源。
这LocalContainerEntityManagerFactoryBean
from Spring ORM 允许您配置EntityManagerFactory
满足您的需求。
您还可以重复使用JpaProperties
为每个EntityManagerFactory
,如以下示例所示:
@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();
}
}
@Configuration(proxyBeanMethods = false)
class MyEntityManagerFactoryConfiguration {
@Bean
@ConfigurationProperties("app.jpa.first")
fun firstJpaProperties(): JpaProperties {
return JpaProperties()
}
@Bean
fun firstEntityManagerFactory(
firstDataSource: DataSource?,
firstJpaProperties: JpaProperties
): LocalContainerEntityManagerFactoryBean {
val builder = createEntityManagerFactoryBuilder(firstJpaProperties)
return builder.dataSource(firstDataSource).packages(Order::class.java).persistenceUnit("firstDs").build()
}
private fun createEntityManagerFactoryBuilder(jpaProperties: JpaProperties): EntityManagerFactoryBuilder {
val jpaVendorAdapter = createJpaVendorAdapter(jpaProperties)
return EntityManagerFactoryBuilder(jpaVendorAdapter, jpaProperties.properties, null)
}
private fun createJpaVendorAdapter(jpaProperties: JpaProperties): JpaVendorAdapter {
// ... map JPA properties as needed
return HibernateJpaVendorAdapter()
}
}
上面的示例创建了一个EntityManagerFactory
使用DataSource
名为 beanfirstDataSource
.
它扫描位于与Order
.
可以使用app.first.jpa
Namespace。
当您为LocalContainerEntityManagerFactoryBean 您自己,在创建自动配置期间应用的任何自定义LocalContainerEntityManagerFactoryBean 丢失了。
例如,在 Hibernate 的情况下,在spring.jpa.hibernate 前缀不会自动应用于您的LocalContainerEntityManagerFactoryBean .
如果您依赖这些属性来配置命名策略或 DDL 模式等内容,则需要在创建LocalContainerEntityManagerFactoryBean 豆。 |
您应该为需要 JPA 访问权限的任何其他数据源提供类似的配置。
要完成图片,您需要配置一个JpaTransactionManager
对于每个EntityManagerFactory
也。
或者,您可以使用跨两者的 JTA 事务管理器。
如果使用 Spring Data,则需要配置@EnableJpaRepositories
因此,如以下示例所示:
@Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(basePackageClasses = Order.class, entityManagerFactoryRef = "firstEntityManagerFactory")
public class OrderConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(basePackageClasses = [Order::class], entityManagerFactoryRef = "firstEntityManagerFactory")
class OrderConfiguration
@Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(basePackageClasses = Customer.class, entityManagerFactoryRef = "secondEntityManagerFactory")
public class CustomerConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(basePackageClasses = [Customer::class], entityManagerFactoryRef = "secondEntityManagerFactory")
class CustomerConfiguration
8.11. 使用传统的persistence.xml文件
Spring Boot 不会搜索或使用META-INF/persistence.xml
默认情况下。
如果您更喜欢使用传统的persistence.xml
,您需要定义自己的@Bean
类型LocalEntityManagerFactoryBean
(ID 为 'entityManagerFactory') 并在其中设置持久性单元名称。
看JpaBaseConfiguration
为默认设置。
8.12. 使用 Spring Data JPA 和 Mongo 存储库
Spring Data JPA 和 Spring Data Mongo 都可以自动创建Repository
为您实现。
如果它们都存在于类路径上,则可能需要执行一些额外的配置来告诉 Spring Boot 要创建哪些存储库。
最明确的方法是使用标准的 Spring Data@EnableJpaRepositories
和@EnableMongoRepositories
注释并提供您的位置Repository
接口。
还有标志(spring.data.*.repositories.enabled
和spring.data.*.repositories.type
),可用于在外部配置中打开和关闭自动配置的存储库。
这样做很有用,例如,如果您想关闭 Mongo 存储库并仍然使用自动配置的MongoTemplate
.
其他自动配置的 Spring Data 存储库类型(Elasticsearch、Solr 等)也存在相同的障碍和相同的功能。 要使用它们,请相应地更改注释和标志的名称。
8.13. 自定义 Spring Data 的 Web 支持
Spring Data 提供 Web 支持,可简化 Web 应用程序中 Spring Data 存储库的使用。
Spring Boot 在spring.data.web
命名空间,用于自定义其配置。
请注意,如果您使用的是 Spring Data REST,则必须使用spring.data.rest
命名空间。
8.14. 将 Spring 数据存储库公开为 REST 端点
Spring Data REST 可以公开Repository
实现作为 REST 端点,
前提是已为应用程序启用了 Spring MVC。
Spring Boot 公开了一组有用的属性(从spring.data.rest
命名空间),自定义RepositoryRestConfiguration
.
如果需要提供额外的自定义,则应使用RepositoryRestConfigurer
豆。
如果您未在自定义中指定任何订单RepositoryRestConfigurer ,它运行在 Spring Boot 内部使用的那个之后。
如果您需要指定订单,请确保它大于 0。 |
8.15. 配置 JPA 使用的组件
如果要配置 JPA 使用的组件,那么需要确保该组件在 JPA 之前初始化。 当组件自动配置时,Spring Boot 会为您处理此问题。 例如,当 Flyway 自动配置时,Hibernate 被配置为依赖于 Flyway,以便 Flyway 有机会在 Hibernate 尝试使用它之前初始化数据库。
如果您自己配置组件,则可以使用EntityManagerFactoryDependsOnPostProcessor
子类作为设置必要依赖项的便捷方式。
例如,如果您使用 Hibernate Search 和 Elasticsearch 作为其索引管理器,则任何EntityManagerFactory
bean 必须配置为依赖于elasticsearchClient
bean,如以下示例所示:
/**
* {@link EntityManagerFactoryDependsOnPostProcessor} that ensures that
* {@link EntityManagerFactory} beans depend on the {@code elasticsearchClient} bean.
*/
@Component
public class ElasticsearchEntityManagerFactoryDependsOnPostProcessor
extends EntityManagerFactoryDependsOnPostProcessor {
public ElasticsearchEntityManagerFactoryDependsOnPostProcessor() {
super("elasticsearchClient");
}
}
@Component
class ElasticsearchEntityManagerFactoryDependsOnPostProcessor :
EntityManagerFactoryDependsOnPostProcessor("elasticsearchClient")
8.16. 使用两个数据源配置 jOOQ
如果您需要将 jOOQ 与多个数据源一起使用,您应该创建自己的DSLContext
对于每一个。
有关更多详细信息,请参阅 JooqAutoConfiguration。
特别JooqExceptionTranslator 和SpringTransactionProvider 可以重复使用,以提供与自动配置对单个DataSource . |
9. 数据库初始化
SQL 数据库可以通过不同的方式初始化,具体取决于堆栈是什么。 当然,您也可以手动执行此作,前提是数据库是一个单独的进程。 建议使用单一机制进行架构生成。
9.1. 使用 JPA 初始化数据库
JPA 具有用于生成 DDL 的功能,这些功能可以设置为在启动时针对数据库运行。 这通过两个外部属性进行控制:
-
spring.jpa.generate-ddl
(布尔值) 打开和关闭该功能,并且与提供商无关。 -
spring.jpa.hibernate.ddl-auto
(enum) 是一个 Hibernate 功能,它以更细粒度的方式控制行为。 本指南稍后将更详细地介绍此功能。
9.2. 使用Hibernate初始化数据库
您可以设置spring.jpa.hibernate.ddl-auto
显式的,标准的 Hibernate 属性值是none
,validate
,update
,create
和create-drop
.
Spring Boot 会根据它是否认为您的数据库是嵌入的,为您选择一个默认值。
它默认为create-drop
如果未检测到架构管理器或none
在所有其他情况下。
通过查看Connection
type 和 JDBC url。hsqldb
,h2
和derby
是候选人,而其他人则不是。
从内存中切换到“真实”数据库时要小心,不要对新平台中表和数据的存在做出假设。
您必须将ddl-auto
显式或使用其他机制之一来初始化数据库。
您可以通过启用org.hibernate.SQL 记录。
如果启用调试模式,则会自动为您完成此作。 |
此外,一个名为import.sql
如果 Hibernate 从头开始创建模式(即,如果ddl-auto
属性设置为create
或create-drop
).
如果您小心的话,这对于演示和测试很有用,但您可能不希望在生产中的类路径上使用。
这是 Hibernate 功能(与 Spring 无关)。
9.3. 使用基本SQL脚本初始化数据库
Spring Boot 可以自动创建 JDBC 的模式(DDL 脚本)DataSource
或 R2DBCConnectionFactory
并初始化其数据(DML 脚本)。
默认情况下,它从optional:classpath*:schema.sql
以及来自optional:classpath*:data.sql
.
这些架构和数据脚本的位置可以使用spring.sql.init.schema-locations
和spring.sql.init.data-locations
分别。
这optional:
前缀表示应用程序将在文件不存在时启动。
要使应用程序在文件不存在时无法启动,请删除optional:
前缀。
此外,Spring Boot 处理optional:classpath*:schema-${platform}.sql
和optional:classpath*:data-${platform}.sql
文件(如果存在),其中${platform}
是spring.sql.init.platform
.
这允许您在必要时切换到特定于数据库的脚本。
例如,您可以选择将其设置为数据库的提供商名称 (hsqldb
,h2
,oracle
,mysql
,postgresql
,依此类推)。
默认情况下,仅在使用嵌入式内存数据库时执行 SQL 数据库初始化。
要始终初始化 SQL 数据库,无论其类型如何,请将spring.sql.init.mode
自always
.
同样,要禁用初始化,请将spring.sql.init.mode
自never
.
默认情况下,Spring Boot 启用其基于脚本的数据库初始值设定项的故障快速功能。
这意味着,如果脚本导致异常,则应用程序无法启动。
您可以通过设置spring.sql.init.continue-on-error
.
基于脚本DataSource
缺省情况下,在任何 JPA 之前执行初始化EntityManagerFactory
bean 被创建。schema.sql
可用于为 JPA 管理的实体创建模式,并且data.sql
可用于填充它。
虽然我们不建议使用多个数据源初始化技术,但如果您想要基于脚本DataSource
initialization 以便能够基于 Hibernate 执行的模式创建进行构建,将spring.jpa.defer-datasource-initialization
自true
.
这会将数据源初始化推迟到任何EntityManagerFactory
bean 已创建并初始化。schema.sql
然后可用于对 Hibernate 执行的任何模式创建进行添加,并且data.sql
可用于填充它。
初始化脚本支持单行注释和块注释。
不支持其他注释格式。-- /* */ |
如果您使用的是更高级别的数据库迁移工具,例如 Flyway 或 Liquibase,则应单独使用它们来创建和初始化架构。
使用基本的schema.sql
和data.sql
不建议将脚本与 Flyway 或 Liquibase 一起使用,并且将在将来的版本中删除支持。
9.4. 初始化 Spring 批处理数据库
如果您使用 Spring Batch,它预打包了适用于大多数流行数据库平台的 SQL 初始化脚本。 Spring Boot 可以检测您的数据库类型并在启动时执行这些脚本。 如果您使用嵌入式数据库,则默认情况下会发生这种情况。 您还可以为任何数据库类型启用它,如以下示例所示:
spring.batch.jdbc.initialize-schema=always
spring:
batch:
jdbc:
initialize-schema: "always"
您还可以通过设置spring.batch.jdbc.initialize-schema
自never
.
9.5. 使用更高级别的数据库迁移工具
9.5.1. 在启动时执行 Flyway 数据库迁移
要在启动时自动运行 Flyway 数据库迁移,请将org.flywaydb:flyway-core
到你的类路径。
通常,迁移是格式为V<VERSION>__<NAME>.sql
(与<VERSION>
下划线分隔的版本,例如“1”或“2_1”)。默认情况下,它们位于名为classpath:db/migration
,但您可以通过将spring.flyway.locations
. 这是一个或多个以逗号分隔的列表classpath:
或filesystem:
地点。 例如,以下配置将在默认类路径位置和/opt/migration
目录:
spring.flyway.locations=classpath:db/migration,filesystem:/opt/migration
spring:
flyway:
locations: "classpath:db/migration,filesystem:/opt/migration"
您还可以添加特殊的{vendor}
占位符以使用特定于提供商的脚本。
假设以下情况:
spring.flyway.locations=classpath:db/migration/{vendor}
spring:
flyway:
locations: "classpath:db/migration/{vendor}"
而不是使用db/migration
,前面的配置根据数据库的类型(例如db/migration/mysql
对于 MySQL)。
支持的数据库列表可在DatabaseDriver
.
迁移也可以用 Java 编写。
Flyway 将自动配置为实现JavaMigration
.
FlywayProperties
提供了 Flyway 的大部分设置和一小部分附加属性,可用于禁用迁移或关闭位置检查。
如果您需要对配置进行更多控制,请考虑注册FlywayConfigurationCustomizer
豆。
Spring Boot 调用Flyway.migrate()
以执行数据库迁移。
如果您想要更多控制权,请提供@Bean
实现FlywayMigrationStrategy
.
Flyway 支持 SQL 和 Java 回调。
要使用基于 SQL 的回调,请将回调脚本放在classpath:db/migration
目录。
要使用基于 Java 的回调,请创建一个或多个实现Callback
.
任何此类 bean 都会自动注册到Flyway
.
可以使用以下命令订购它们@Order
或通过实现Ordered
.
实现已弃用的FlywayCallback
也可以检测接口,但不能与Callback
豆。
默认情况下,Flyway 会自动连接 (@Primary
) DataSource
并将其用于迁移。
如果您喜欢使用不同的DataSource
,您可以创建一个并标记其@Bean
如@FlywayDataSource
.
如果您这样做并想要两个数据源,请记住创建另一个数据源并将其标记为@Primary
.
或者,您可以使用 Flyway 的原生DataSource
通过设置spring.flyway.[url,user,password]
在外部属性中。
将spring.flyway.url
或spring.flyway.user
足以使 Flyway 使用自己的DataSource
.
如果尚未设置三个属性中的任何一个,则其等效属性的值spring.datasource
属性将被使用。
您还可以使用 Flyway 为特定场景提供数据。
例如,可以将特定于测试的迁移放在src/test/resources
并且它们仅在应用程序启动进行测试时运行。
此外,还可以使用特定于配置文件的配置来自定义spring.flyway.locations
以便某些迁移仅在特定配置文件处于活动状态时运行。
例如,在application-dev.properties
,您可以指定以下设置:
spring.flyway.locations=classpath:/db/migration,classpath:/dev/db/migration
spring:
flyway:
locations: "classpath:/db/migration,classpath:/dev/db/migration"
通过该设置,迁移dev/db/migration
仅当dev
配置文件处于活动状态。
9.5.2. 在启动时执行 Liquibase 数据库迁移
要在启动时自动运行 Liquibase 数据库迁移,请将org.liquibase:liquibase-core
到你的类路径。
当您添加 |
默认情况下,主更改日志是从db/changelog/db.changelog-master.yaml
,但您可以通过设置spring.liquibase.change-log
.
除了 YAML 之外,Liquibase 还支持 JSON、XML 和 SQL 更改日志格式。
默认情况下,Liquibase 会自动连接 (@Primary
) DataSource
并将其用于迁移。
如果您需要使用不同的DataSource
,您可以创建一个并标记其@Bean
如@LiquibaseDataSource
.
如果您这样做并且想要两个数据源,请记住创建另一个数据源并将其标记为@Primary
.
或者,您可以使用 Liquibase 的原生DataSource
通过设置spring.liquibase.[driver-class-name,url,user,password]
在外部属性中。
将spring.liquibase.url
或spring.liquibase.user
足以使 Liquibase 使用自己的DataSource
.
如果尚未设置三个属性中的任何一个,则其等效属性的值spring.datasource
属性将被使用。
看LiquibaseProperties
了解有关可用设置(如上下文、默认架构等)的详细信息。
9.5.3. 使用 Flyway 进行仅测试迁移
如果要创建填充测试数据库的 Flyway 迁移,请将它们放在src/test/resources/db/migration
.
名为src/test/resources/db/migration/V9999__test-data.sql
将在生产迁移后执行,并且仅在运行测试时执行。
您可以使用此文件创建所需的测试数据。
此文件不会打包在您的 uber jar 或容器中。
9.5.4. 使用 Liquibase 进行仅测试迁移
如果要创建填充测试数据库的 Liquibase 迁移,则必须创建一个测试变更日志,其中还包括生产变更日志。
首先,您需要将 Liquibase 配置为在运行测试时使用不同的变更日志。
一种方法是创建一个 Spring Boottest
profile 并将 Liquibase 属性放入其中。
为此,请创建一个名为src/test/resources/application-test.properties
并将以下属性放入其中:
spring.liquibase.change-log=classpath:/db/changelog/db.changelog-test.yaml
spring:
liquibase:
change-log: "classpath:/db/changelog/db.changelog-test.yaml"
这会将 Liquibase 配置为在test
轮廓。
现在在src/test/resources/db/changelog/db.changelog-test.yaml
:
databaseChangeLog:
- include:
file: classpath:/db/changelog/db.changelog-master.yaml
- changeSet:
runOrder: "last"
id: "test"
changes:
# Insert your changes here
此更新日志将在运行测试时使用,并且不会打包在您的 uber jar 或容器中。
它包括生产变更日志,然后声明一个新的变更集,其runOrder: last
设置指定它在运行所有生产变更集后运行。
例如,您现在可以使用插入变更集来插入数据,或使用 sql 变更集直接执行 SQL。
最后要做的是配置 Spring Boot 以激活test
配置文件。
为此,您可以添加@ActiveProfiles("test")
注释到你的@SpringBootTest
带注释的测试类。
9.6. 依赖于初始化的数据库
数据库初始化是在应用程序启动时执行的,作为应用程序上下文刷新的一部分。 为了允许在启动期间访问初始化的数据库,将自动检测充当数据库初始值设定项的 Bean 和需要该数据库已初始化的 Bean。 初始化依赖于已初始化的数据库的 Bean 被配置为依赖于初始化它的数据库。 如果在启动期间,应用程序尝试访问数据库,但尚未初始化数据库,那么可以配置对初始化数据库并要求数据库已初始化的 Bean 的其他检测。
9.6.1. 检测数据库初始值设定项
Spring Boot 将自动检测初始化 SQL 数据库的以下类型的 bean:
-
DataSourceScriptDatabaseInitializer
-
EntityManagerFactory
-
Flyway
-
FlywayMigrationInitializer
-
R2dbcScriptDatabaseInitializer
-
SpringLiquibase
如果您将第三方Starters用于数据库初始化库,它可能会提供一个检测器,以便也自动检测其他类型的 bean。要检测其他 bean,请注册DatabaseInitializerDetector
在META-INF/spring.factories
.
9.6.2. 检测依赖于数据库初始化的 Bean
Spring Boot将自动检测以下类型的bean,这些bean取决于数据库初始化:
-
AbstractEntityManagerFactoryBean
(除非spring.jpa.defer-datasource-initialization
设置为true
) -
DSLContext
(jOOQ) -
EntityManagerFactory
(除非spring.jpa.defer-datasource-initialization
设置为true
) -
JdbcOperations
-
NamedParameterJdbcOperations
如果您使用的是第三方入门数据访问库,它可能会提供一个检测器,以便也会自动检测其他类型的 bean。
要检测其他 bean,请注册DependsOnDatabaseInitializationDetector
在META-INF/spring.factories
.
或者,注释 bean 的类或其@Bean
方法@DependsOnDatabaseInitialization
.
10. 无SQL
Spring Boot 提供了许多支持 NoSQL 技术的Starters。 本节回答了将 NoSQL 与 Spring Boot 结合使用时出现的问题。
10.1. 用绝地代替生菜
默认情况下,Spring Boot Starters (spring-boot-starter-data-redis
)使用生菜。
您需要排除该依赖项并包含 Jedis 依赖项。
Spring Boot 管理这两个依赖项,因此您可以在不指定版本的情况下切换到 Jedis。
以下示例显示了如何在 Maven 中执行此作:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
以下示例展示了如何在 Gradle 中执行此作:
dependencies {
implementation('org.springframework.boot:spring-boot-starter-data-redis') {
exclude group: 'io.lettuce', module: 'lettuce-core'
}
implementation 'redis.clients:jedis'
// ...
}
11. 消息传递
Spring Boot 提供了许多Starters来支持消息传递。 本节回答了在 Spring Boot 中使用消息传递时出现的问题。
11.1. 禁用事务处理的 JMS 会话
如果您的 JMS 代理不支持交易会话,则必须完全禁用对事务的支持。
如果您创建自己的JmsListenerContainerFactory
,无事可做,因为默认情况下无法交易。
如果要使用DefaultJmsListenerContainerFactoryConfigurer
要重用 Spring Boot 的默认值,您可以禁用事务会话,如下所示:
@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;
}
}
@Configuration(proxyBeanMethods = false)
class MyJmsConfiguration {
@Bean
fun jmsListenerContainerFactory(connectionFactory: ConnectionFactory?,
configurer: DefaultJmsListenerContainerFactoryConfigurer): DefaultJmsListenerContainerFactory {
val listenerFactory = DefaultJmsListenerContainerFactory()
configurer.configure(listenerFactory, connectionFactory)
listenerFactory.setTransactionManager(null)
listenerFactory.setSessionTransacted(false)
return listenerFactory
}
}
前面的示例将替代默认工厂,并且应将其应用于应用程序定义的任何其他工厂(如果有)。
12. 批量申请
当人们在 Spring Boot 应用程序中使用 Spring Batch 时,经常会出现许多问题。 本节将解决这些问题。
12.1. 指定批处理数据源
默认情况下,批处理应用程序需要DataSource
以存储作业详细信息。
Spring Batch 需要单个DataSource
默认情况下。
要让它使用DataSource
除了应用程序的主要内容DataSource
,声明一个DataSource
bean,注释其@Bean
方法@BatchDataSource
.
如果您这样做并想要两个数据源,请记住标记另一个@Primary
.
要获得更好的控制权,请实施BatchConfigurer
.
看Javadoc 的@EnableBatchProcessing
了解更多详情。
有关 Spring Batch 的更多信息,请参阅 Spring Batch 项目页面。
12.2. 在启动时运行 Spring 批处理作业
Spring Batch 自动配置是通过添加@EnableBatchProcessing
给你的一个@Configuration
类。
默认情况下,它执行所有 Jobs
在启动时的应用程序上下文中(请参阅JobLauncherApplicationRunner
了解详情)。
您可以通过指定spring.batch.job.names
(采用逗号分隔的作业名称模式列表)。
有关更多详细信息,请参阅 BatchAutoConfiguration 和 @EnableBatchProcessing。
12.3. 从命令行运行
Spring Boot 将任何以开头的命令行参数转换为要添加到--
Environment
,请参阅访问命令行属性。
这不应用于将参数传递给批处理作业。
要在命令行上指定批处理参数,请使用常规格式(即没有 ),如以下示例所示:--
$ java -jar myapp.jar someParameter=someValue anotherParameter=anotherValue
如果您指定了Environment
在命令行上,作业会忽略它。
考虑以下命令:
$ java -jar myapp.jar --server.port=7070 someParameter=someValue
这仅为批处理作业提供一个参数:someParameter=someValue
.
12.4. 存储作业存储库
Spring Batch 需要一个数据存储,用于Job
存储 库。
如果您使用 Spring Boot,则必须使用实际的数据库。
请注意,它可以是内存数据库,请参阅配置作业存储库。
13. 执行器
Spring Boot 包括 Spring Boot 执行器。 本节回答了使用它时经常出现的问题。
13.1. 更改执行器端点的 HTTP 端口或地址
在独立应用程序中,执行器 HTTP 端口默认为与主 HTTP 端口相同。
要使应用程序侦听不同的端口,请设置 external 属性:management.server.port
.
要监听完全不同的网络地址(例如,当您有一个用于管理的内部网络和一个用于用户应用程序的外部网络时),您还可以将management.server.address
到服务器能够绑定到的有效 IP 地址。
有关更多详细信息,请参阅ManagementServerProperties
源代码和“生产就绪功能”部分中的“actuator.html”。
13.2. 自定义“白标”错误页面
Spring Boot 会安装一个“白标”错误页面,如果遇到服务器错误,您将在浏览器客户端中看到该页面(使用 JSON 和其他媒体类型的机器客户端应该会看到带有正确错误代码的合理响应)。
设置server.error.whitelabel.enabled=false 以关闭默认错误页面。
这样做将恢复您正在使用的 servlet 容器的默认值。
请注意,Spring Boot 仍然会尝试解决错误视图,因此您可能应该添加自己的错误页面,而不是完全禁用它。 |
使用您自己的错误页面覆盖错误页面取决于您使用的模板技术。
例如,如果您使用 Thymeleaf,则可以添加error.html
模板。
如果您使用 FreeMarker,您可以添加一个error.ftlh
模板。
一般来说,您需要一个View
以名称error
或@Controller
处理/error
路径。
除非您替换了一些默认配置,否则您应该找到一个BeanNameViewResolver
在你的ApplicationContext
,所以一个@Bean
叫error
将是做到这一点的一种方法。
看ErrorMvcAutoConfiguration
以获取更多选择。
有关如何在 servlet 容器中注册处理程序的详细信息,另请参阅有关“错误处理”的部分。
13.3. 清理敏感值
返回的信息env
和configprops
端点可能有些敏感,因此默认情况下会清理与某些模式匹配的键(即它们的值被替换为 )。
Spring Boot 对此类密钥使用合理的默认值:任何以单词 “password”、“secret”、“key”、“token”、“vcap_services”、“sun.java.command” 结尾的密钥都被完全清理。
此外,任何包含单词的键******
credentials
(配置为正则表达式,即.*credentials.*
) 作为密钥的一部分,也完全被清理。
此外,Spring Boot 会清理具有以下结尾之一的键的类似 URI 值的敏感部分:
-
address
-
addresses
-
uri
-
uris
-
url
-
urls
URI 的敏感部分使用以下格式进行标识<scheme>://<username>:<password>@<host>:<port>/
.
例如,对于属性myclient.uri=http://user1:password1@localhost:8081
,生成的清理值为http://user1:******@localhost:8081
.
13.3.1. 自定义清理
消毒可以通过两种不同的方式进行定制。
默认模式env
和configprops
可以使用以下命令替换端点management.endpoint.env.keys-to-sanitize
和management.endpoint.configprops.keys-to-sanitize
分别。
或者,可以使用management.endpoint.env.additional-keys-to-sanitize
和management.endpoint.configprops.additional-keys-to-sanitize
.
要更好地控制清理,请定义SanitizingFunction
豆。
这SanitizableData
调用函数时,可以使用该函数来访问键和值,以及PropertySource
他们来自那里。
例如,这允许您清理来自特定属性源的每个值。
每SanitizingFunction
按顺序调用,直到函数更改可清理数据的值。
如果没有函数更改其值,则执行内置的基于键的清理。
13.4. 将运行状况指标映射到千分尺指标
Spring Boot 运行状况指示器返回一个Status
类型以指示整体系统运行状况。
如果要监视特定应用程序的运行状况级别或发出警报,可以使用 Micrometer 将这些状态导出为度量。
默认情况下,Spring Boot 使用状态代码“UP”、“DOWN”、“OUT_OF_SERVICE”和“UNKNOWN”。
要导出这些,您需要将这些状态转换为一组数字,以便它们可以与千分尺一起使用Gauge
.
以下示例显示了编写此类导出器的一种方法:
@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;
}
}
@Configuration(proxyBeanMethods = false)
class MyHealthMetricsExportConfiguration(registry: MeterRegistry, healthEndpoint: HealthEndpoint) {
init {
// This example presumes common tags (such as the app) are applied elsewhere
Gauge.builder("health", healthEndpoint) { health ->
getStatusCode(health).toDouble()
}.strongReference(true).register(registry)
}
private fun getStatusCode(health: HealthEndpoint): Int {
return when (health.health().status) {
Status.UP -> 3
Status.OUT_OF_SERVICE -> 2
Status.DOWN -> 1
else -> 0
}
}
}
14. 安全
本节解决使用 Spring Boot 时有关安全性的问题,包括将 Spring Security 与 Spring Boot 一起使用时出现的问题。
有关 Spring Security 的更多信息,请参阅 Spring Security 项目页面。
14.1. 关闭 Spring Boot 安全配置
如果定义@Configuration
使用WebSecurityConfigurerAdapter
或SecurityFilterChain
bean 中,它会关闭 Spring Boot 中的默认 webapp 安全设置。
14.2. 更改 UserDetailsService 并添加用户帐户
如果您提供@Bean
类型AuthenticationManager
,AuthenticationProvider
或UserDetailsService
,默认值@Bean
为InMemoryUserDetailsManager
未创建。
这意味着您拥有可用的 Spring Security 的完整功能集(例如各种身份验证选项)。
添加用户帐户的最简单方法是提供您自己的帐户UserDetailsService
豆。
14.3. 在代理服务器后面运行时启用 HTTPS
确保所有主要端点只能通过 HTTPS 使用对于任何应用程序来说都是一项重要的工作。
如果使用 Tomcat 作为 servlet 容器,则 Spring Boot 会添加 Tomcat 自己的RemoteIpValve
如果它检测到某些环境设置,则自动执行,并且您应该能够依赖HttpServletRequest
报告它是否安全(甚至是处理实际 SSL 终止的代理服务器的下游)。
标准行为由某些请求标头(x-forwarded-for
和x-forwarded-proto
),其名称是常规的,因此它应该适用于大多数前端代理。
您可以通过添加一些条目来打开阀门application.properties
,如以下示例所示:
server.tomcat.remoteip.remote-ip-header=x-forwarded-for
server.tomcat.remoteip.protocol-header=x-forwarded-proto
server:
tomcat:
remoteip:
remote-ip-header: "x-forwarded-for"
protocol-header: "x-forwarded-proto"
(这些属性中的任何一个的存在都会在阀门上切换。
或者,您可以添加RemoteIpValve
通过自定义TomcatServletWebServerFactory
使用WebServerFactoryCustomizer
豆子。
要将 Spring Security 配置为要求所有(或部分)请求的安全通道,请考虑添加您自己的SecurityFilterChain
添加以下内容的 beanHttpSecurity
配置:
@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();
}
}
@Configuration
class MySecurityConfig {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
// Customize the application security ...
http.requiresChannel().anyRequest().requiresSecure()
return http.build()
}
}
15. 热插拔
Spring Boot 支持热插拔。 本节回答有关其工作原理的问题。
15.1. 重新加载静态内容
热重载有多种选择。
推荐的方法是使用spring-boot-devtools
,因为它提供了额外的开发时功能,例如支持快速应用程序重启和 LiveReload 以及合理的开发时配置(例如模板缓存)。
Devtools 的工作原理是监控类路径的更改。
这意味着必须“构建”静态资源更改才能使更改生效。
默认情况下,当您保存更改时,这会在 Eclipse 中自动发生。
在 IntelliJ IDEA 中,“制作项目”命令会触发必要的构建。
由于默认的重启排除项,对静态资源的更改不会触发应用程序的重启。
但是,它们确实会触发实时重新加载。
或者,在 IDE 中运行(尤其是在开启调试的情况下)是一种很好的开发方式(所有现代 IDE 都允许重新加载静态资源,并且通常还允许热插拔 Java 类更改)。
最后,可以配置 Maven 和 Gradle 插件(请参阅addResources
属性)以支持从命令行运行并直接从源代码重新加载静态文件。
如果您使用更高级别的工具编写该代码,则可以将其与外部 css/js 编译器进程一起使用。
15.2. 在不重新启动容器的情况下重新加载模板
Spring Boot 支持的大多数模板技术都包含用于禁用缓存的配置选项(本文档稍后将介绍)。
如果您使用spring-boot-devtools
模块,这些属性将在开发时自动为您配置。
15.2.1. 胸腺叶模板
如果您使用胸腺叶,请将spring.thymeleaf.cache
自false
.
看ThymeleafAutoConfiguration
用于其他百里叶定制选项。
15.2.2. FreeMarker 模板
如果您使用 FreeMarker,请将spring.freemarker.cache
自false
.
看FreeMarkerAutoConfiguration
用于其他 FreeMarker 自定义选项。
15.2.3. Groovy 模板
如果您使用 Groovy 模板,请将spring.groovy.template.cache
自false
.
看GroovyTemplateAutoConfiguration
用于其他 Groovy 自定义选项。
15.3. 快速应用程序重启
这spring-boot-devtools
模块包括对自动应用程序重启的支持。
虽然不如 JRebel 等技术快,但它通常比“冷启动”快得多。
在研究本文档后面讨论的一些更复杂的重新加载选项之前,您可能应该尝试一下。
有关更多详细信息,请参阅using.html部分。
16. 测试
Spring Boot 包括许多测试实用程序和支持类,以及提供常见测试依赖项的专用Starters。 本节回答有关测试的常见问题。
16.1. 使用 Spring Security 进行测试
Spring Security 支持以特定用户身份运行测试。
例如,下面代码段中的测试将使用具有ADMIN
角色。
@WebMvcTest(UserController.class)
class MySecurityTests {
@Autowired
private MockMvc mvc;
@Test
@WithMockUser(roles = "ADMIN")
void requestProtectedUrlWithUser() throws Exception {
this.mvc.perform(get("/"));
}
}
@WebMvcTest(UserController::class)
class MySecurityTests(@Autowired val mvc: MockMvc) {
@Test
@WithMockUser(roles = ["ADMIN"])
fun requestProtectedUrlWithUser() {
mvc.perform(MockMvcRequestBuilders.get("/"))
}
}
Spring Security 提供与 Spring MVC Test 的全面集成,这也可以在使用@WebMvcTest
slice 和MockMvc
.
有关 Spring Security 测试支持的其他详细信息,请参阅 Spring Security 的参考文档。
16.2. 使用 Testcontainers 进行集成测试
Testcontainers 库提供了一种管理在 Docker 容器内运行的服务的方法。 它与 JUnit 集成,允许您编写一个测试类,该类可以在任何测试运行之前启动容器。 Testcontainers 对于编写与真正的后端服务(如 MySQL、MongoDB、Cassandra 等)通信的集成测试特别有用。 Test容器可以在 Spring Boot 测试中使用,如下所示:
@SpringBootTest
@Testcontainers
class MyIntegrationTests {
@Container
static Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:5");
@Test
void myTest() {
// ...
}
}
@SpringBootTest
@Testcontainers
internal class MyIntegrationTests {
@Test
fun myTest() {
// ...
}
companion object {
@Container
var neo4j: Neo4jContainer<*> = Neo4jContainer<Nothing>("neo4j:5")
}
}
这将在运行任何测试之前启动一个运行 Neo4j 的 docker 容器(如果 Docker 在本地运行)。 在大多数情况下,您需要使用正在运行的容器中的详细信息(例如容器 IP 或端口)来配置应用程序。
这可以通过静态@DynamicPropertySource
允许向 Spring 环境添加动态属性值的方法。
@SpringBootTest
@Testcontainers
class MyIntegrationTests {
@Container
static Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:5");
@Test
void myTest() {
// ...
}
@DynamicPropertySource
static void neo4jProperties(DynamicPropertyRegistry registry) {
registry.add("spring.neo4j.uri", neo4j::getBoltUrl);
}
}
@SpringBootTest
@Testcontainers
internal class MyIntegrationTests {
@Test
fun myTest() {
// ...
}
companion object {
@Container
var neo4j: Neo4jContainer<*> = Neo4jContainer<Nothing>("neo4j:5")
@DynamicPropertySource
fun neo4jProperties(registry: DynamicPropertyRegistry) {
registry.add("spring.neo4j.uri") { neo4j.boltUrl }
}
}
}
上述配置允许应用程序中与 Neo4j 相关的 Bean 与在 Testcontainers 管理的 Docker 容器内运行的 Neo4j 进行通信。
16.3. 结构@Configuration
用于包含在切片测试中的类
切片测试的工作原理是根据组件类型将 Spring Framework 的组件扫描限制为一组有限的组件。
对于未通过组件扫描创建的任何 Bean,例如,使用@Bean
注释,切片测试将无法将它们包含在应用程序上下文中/排除。
考虑这个例子:
@Configuration(proxyBeanMethods = false)
public class MyConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeRequests((requests) -> requests.anyRequest().authenticated());
return http.build();
}
@Bean
@ConfigurationProperties("app.datasource.second")
public BasicDataSource secondDataSource() {
return DataSourceBuilder.create().type(BasicDataSource.class).build();
}
}
对于一个@WebMvcTest
对于具有上述条件的应用@Configuration
类,你可能会期望拥有SecurityFilterChain
bean 的 bean,以便您可以测试控制器端点是否得到适当的保护。
然而MyConfiguration
不会被@WebMvcTest的组件扫描过滤器拾取,因为它与过滤器指定的任何类型都不匹配。
您可以通过使用@Import(MyConfiguration.class)
.
这将加载所有 beanMyConfiguration
包括BasicDataSource
测试 Web 层时不需要的 bean。
将配置类拆分为两个将允许仅导入安全配置。
@Configuration(proxyBeanMethods = false)
public class MySecurityConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeRequests((requests) -> requests.anyRequest().authenticated());
return http.build();
}
}
@Configuration(proxyBeanMethods = false)
public class MyDatasourceConfiguration {
@Bean
@ConfigurationProperties("app.datasource.second")
public BasicDataSource secondDataSource() {
return DataSourceBuilder.create().type(BasicDataSource.class).build();
}
}
当需要将某个域的 Bean 包含在切片测试中时,使用单个配置类可能会效率低下。 相反,将应用程序的配置构建为具有特定域的 Bean 的多个粒度类,可以仅为特定的切片测试导入它们。
17. 构建
Spring Boot 包括 Maven 和 Gradle 的构建插件。 本节回答有关这些插件的常见问题。
17.1. 生成构建信息
Maven 插件和 Gradle 插件都允许生成包含项目坐标、名称和版本的构建信息。
还可以将插件配置为通过配置添加其他属性。
当存在这样的文件时,Spring Boot 会自动配置一个BuildProperties
豆。
要使用 Maven 生成构建信息,请为build-info
目标,如以下示例所示:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.18</version>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
有关更多详细信息,请参阅 Spring Boot Maven 插件文档。 |
以下示例对 Gradle 执行相同的作:
springBoot {
buildInfo()
}
有关更多详细信息,请参阅 Spring Boot Gradle 插件文档。 |
17.2. 生成 Git 信息
Maven 和 Gradle 都允许生成git.properties
文件,其中包含有关您的状态的信息git
生成项目时的源代码存储库。
对于 Maven 用户,spring-boot-starter-parent
POM 包括一个预配置的插件,用于生成git.properties
文件。
要使用它,请为Git Commit Id Plugin
到你的 POM:
<build>
<plugins>
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
</plugin>
</plugins>
</build>
Gradle 用户可以通过使用gradle-git-properties
插件,如以下示例所示:
plugins {
id "com.gorylenko.gradle-git-properties" version "2.4.1"
}
Maven 和 Gradle 插件都允许git.properties
待配置。
中的提交时间git.properties 应匹配以下格式:yyyy-MM-dd’T’HH:mm:ssZ .
这是上面列出的两个插件的默认格式。
使用这种格式可以将时间解析为Date 及其格式,当序列化为 JSON 时,由 Jackson 的日期序列化配置设置控制。 |
17.3. 自定义依赖版本
这spring-boot-dependencies
POM 管理常见依赖项的版本。
Maven 和 Gradle 的 Spring Boot 插件允许使用构建属性自定义这些托管依赖项版本。
每个 Spring Boot 版本都是针对这组特定的第三方依赖项进行设计和测试的。 覆盖版本可能会导致兼容性问题。 |
要使用 Maven 覆盖依赖版本,请参阅 Maven 插件文档的这一部分。
如需覆盖 Gradle 中的依赖项版本,请参阅 Gradle 插件文档的这一部分。
17.4. 使用 Maven 创建可执行 JAR
这spring-boot-maven-plugin
可用于创建可执行的“胖”JAR。
如果您使用spring-boot-starter-parent
POM,您可以声明插件,并且您的 jar 将按如下方式重新打包:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
如果您不使用父 POM,您仍然可以使用该插件。
但是,您必须额外添加一个<executions>
部分,如下所示:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{spring-boot-version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
有关完整的使用详细信息,请参阅插件文档。
17.5. 使用 Spring Boot 应用程序作为依赖项
与 war 文件一样,Spring Boot 应用程序不打算用作依赖项。 如果您的应用程序包含要与其他项目共享的类,建议的方法是将该代码移动到单独的模块中。 然后,您的应用程序和其他项目可以依赖单独的模块。
如果您无法按照上述建议重新排列代码,则必须将 Spring Boot 的 Maven 和 Gradle 插件配置为生成适合用作依赖项的单独工件。
可执行存档不能用作依赖项,因为可执行 jar 格式将应用程序类打包在BOOT-INF/classes
.
这意味着当可执行 jar 用作依赖项时,找不到它们。
要生成两个工件,一个可用作依赖项,一个可执行,必须指定分类器。 此分类器应用于可执行存档的名称,保留默认存档作为依赖项使用。
要配置exec
在 Maven 中,您可以使用以下配置:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
</plugins>
</build>
17.6. 在可执行 jar 运行时提取特定库
可执行 jar 中的大多数嵌套库不需要解压缩即可运行。
但是,某些库可能存在问题。
例如,JRuby 包含自己的嵌套 jar 支持,它假设jruby-complete.jar
始终以文件的形式直接提供。
要处理任何有问题的库,您可以标记在可执行 jar 首次运行时应自动解压缩特定的嵌套 jar。
此类嵌套 jar 写在由java.io.tmpdir
系统属性。
应注意确保您的作系统已配置,以便在应用程序仍在运行时不会删除已解压缩到临时目录的 jar。 |
例如,要指示应使用 Maven 插件标记 JRuby 以进行解包,您可以添加以下配置:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<requiresUnpack>
<dependency>
<groupId>org.jruby</groupId>
<artifactId>jruby-complete</artifactId>
</dependency>
</requiresUnpack>
</configuration>
</plugin>
</plugins>
</build>
17.7. 创建具有排除项的不可执行 JAR
通常,如果您将可执行文件和不可执行 jar 作为两个单独的构建产品,则可执行文件版本具有库 jar 中不需要的其他配置文件。
例如,application.yaml
配置文件可能会从不可执行的 JAR 中排除。
在Maven中,可执行的jar必须是主工件,您可以为库添加一个分类的jar,如下所示:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>lib</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>lib</classifier>
<excludes>
<exclude>application.yaml</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
17.8. 远程调试使用 Maven 启动的 Spring Boot 应用程序
要将远程调试器附加到使用 Maven 启动的 Spring Boot 应用程序,您可以使用jvmArguments
Maven 插件的属性。
有关更多详细信息,请参阅此示例。
17.9. 在不使用 spring-boot-antlib 的情况下从 Ant 构建可执行存档
要使用 Ant 进行构建,您需要抓取依赖项,编译,然后创建一个 jar 或 war 存档。
要使其可执行,您可以使用spring-boot-antlib
模块,或者您可以按照以下说明进行作:
-
如果您正在构建一个 jar,请将应用程序的类和资源打包在嵌套的
BOOT-INF/classes
目录。 如果您正在构建 war,请将应用程序的类打包在嵌套的WEB-INF/classes
目录。 -
在嵌套的
BOOT-INF/lib
目录或WEB-INF/lib
为了一场战争。 请记住不要压缩存档中的条目。 -
添加
provided
(嵌入式容器)依赖项BOOT-INF/lib
目录或WEB-INF/lib-provided
为了一场战争。 请记住不要压缩存档中的条目。 -
添加
spring-boot-loader
类(以便Main-Class
可用)。 -
使用适当的Starters(例如
JarLauncher
对于 jar 文件)作为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>
18. 传统部署
Spring Boot 支持传统部署以及更现代的部署形式。 本部分回答有关传统部署的常见问题。
18.1. 创建可部署的 war 文件
由于 Spring WebFlux 并不严格依赖于 servlet API,并且应用程序默认部署在嵌入式 Reactor Netty 服务器上,因此 WebFlux 应用程序不支持 War 部署。 |
生成可部署的 war 文件的第一步是提供一个SpringBootServletInitializer
子类并覆盖其configure
方法。
这样做利用了 Spring Framework 的 servlet 3.0 支持,并允许您在 servlet 容器启动应用程序时配置应用程序。
通常,您应该更新应用程序的主类以扩展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);
}
}
@SpringBootApplication
class MyApplication : SpringBootServletInitializer() {
override fun configure(application: SpringApplicationBuilder): SpringApplicationBuilder {
return application.sources(MyApplication::class.java)
}
}
fun main(args: Array<String>) {
runApplication<MyApplication>(*args)
}
下一步是更新您的构建配置,以便您的项目生成一个 war 文件而不是一个 jar 文件。
如果您使用 Maven 和spring-boot-starter-parent
(为你配置 Maven 的 war 插件),你需要做的就是修改pom.xml
要将包装更改为 WAR,如下所示:
<packaging>war</packaging>
如果您使用 Gradle,则需要修改build.gradle
将 war 插件应用于项目,如下所示:
apply plugin: 'war'
该过程的最后一步是确保嵌入式 Servlet 容器不会干扰部署 war 文件的 Servlet 容器。 为此,您需要将嵌入式 servlet 容器依赖项标记为已提供。
如果您使用 Maven,则以下示例将 servlet 容器(在本例中为 Tomcat)标记为已提供:
<dependencies>
<!-- ... -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- ... -->
</dependencies>
如果您使用 Gradle,则以下示例将 servlet 容器(在本例中为 Tomcat)标记为已提供:
dependencies {
// ...
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
// ...
}
providedRuntime 比 Gradle 的compileOnly 配置。
除其他限制外,compileOnly 依赖项不在测试类路径上,因此任何基于 Web 的集成测试都失败。 |
如果您使用 Spring Boot 构建工具,则将嵌入式 servlet 容器依赖项标记为提供会生成一个可执行的 war 文件,其中包含打包在lib-provided
目录。
这意味着,除了可部署到 servlet 容器之外,您还可以使用java -jar
在命令行上。
18.2. 将现有应用程序转换为 Spring Boot
要将现有的非 Web Spring 应用程序转换为 Spring Boot 应用程序,请替换创建ApplicationContext
并将其替换为SpringApplication
或SpringApplicationBuilder
.
Spring MVC Web 应用程序通常适合首先创建一个可部署的 war 应用程序,然后再将其迁移到可执行的 war 或 jar。
请参阅将 jar 转换为 war 的入门指南。
通过扩展来创造一场可部署的战争SpringBootServletInitializer
(例如,在名为Application
) 并添加 Spring Boot@SpringBootApplication
注释,请使用类似于以下示例中所示的代码:
@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
// Customize the application or call application.sources(...) to add sources
// Since our example is itself a @Configuration class (through
// @SpringBootApplication)
// we actually do not need to override this method.
return application;
}
}
@SpringBootApplication
class MyApplication : SpringBootServletInitializer() {
override fun configure(application: SpringApplicationBuilder): SpringApplicationBuilder {
// Customize the application or call application.sources(...) to add sources
// Since our example is itself a @Configuration class (through @SpringBootApplication)
// we actually do not need to override this method.
return application
}
}
请记住,无论您放入什么sources
只是一个SpringApplicationContext
.
通常,任何已经有效的东西都应该在这里工作。
您可能稍后可以删除一些 bean,让 Spring Boot 为它们提供自己的默认值,但在您需要这样做之前,应该可以让一些东西正常工作。
静态资源可以移动到/public
(或/static
或/resources
或/META-INF/resources
) 在类路径根目录中。
这同样适用于messages.properties
(Spring Boot 在类路径的根目录中自动检测到)。
Spring 的原版用法DispatcherServlet
并且 Spring Security 不需要进一步更改。
如果您的应用程序中有其他功能(例如,使用其他 servlet 或过滤器),您可能需要向Application
context,通过替换web.xml
如下:
-
一个
@Bean
类型Servlet
或ServletRegistrationBean
将该 bean 安装在容器中,就好像它是<servlet/>
和<servlet-mapping/>
在web.xml
. -
一个
@Bean
类型Filter
或FilterRegistrationBean
行为类似(作为<filter/>
和<filter-mapping/>
). -
一
ApplicationContext
可以在 XML 文件中添加@ImportResource
在你的Application
. 或者,可以在几行中重新创建已经大量使用的注释配置的情况,如@Bean
定义。
war 文件工作后,您可以通过添加main
方法到你的Application
,如以下示例所示:
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
fun main(args: Array<String>) {
runApplication<MyApplication>(*args)
}
如果您打算将应用程序作为 war 或可执行应用程序启动,则需要在 Java
Kotlin
|
应用程序可以分为多个类别:
-
Servlet 3.0+ 应用程序,没有
web.xml
. -
具有
web.xml
. -
具有上下文层次结构的应用程序。
-
没有上下文层次结构的应用程序。
所有这些都应该适合翻译,但每个可能需要略有不同的技术。
如果 Servlet 3.0+ 应用程序已经使用 Spring Servlet 3.0+ 初始值设定项支持类,它们可能很容易翻译。
通常,现有WebApplicationInitializer
可以移动到SpringBootServletInitializer
.
如果现有应用程序有多个ApplicationContext
(例如,如果它使用AbstractDispatcherServletInitializer
),那么您也许可以将所有上下文源合并为一个SpringApplication
.
您可能遇到的主要复杂情况是组合不起作用,并且您需要维护上下文层次结构。
有关示例,请参阅有关构建层次结构的条目。
包含特定于 Web 的功能的现有父上下文通常需要分解,以便所有ServletContextAware
组件位于子上下文中。
还不是 Spring 应用程序的应用程序可以转换为 Spring Boot 应用程序,前面提到的指南可能会有所帮助。
但是,您可能还会遇到问题。
在这种情况下,我们建议在 Stack Overflow 上提问,标签为spring-boot
.
18.3. 将 WAR 部署到 WebLogic
要将 Spring Boot 应用程序部署到 WebLogic,您必须确保您的 servlet 初始值设定项直接实现WebApplicationInitializer
(即使您从已经实现它的基类扩展)。
WebLogic 的典型初始值设定项应类似于以下示例:
@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer implements WebApplicationInitializer {
}
@SpringBootApplication
class MyApplication : SpringBootServletInitializer(), 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>