“操作方法”指南
1. Spring Boot 应用程序
本节包括与 Spring Boot 应用程序直接相关的主题。
1.1. 创建您自己的 FailureAnalyzer
FailureAnalyzer
是在启动时拦截异常并将其转换为人类可读的消息,包装在 FailureAnalysis
中的好方法。
Spring Boot 为与应用程序上下文相关的异常、JSR-303 验证等提供了这样的分析器。
您也可以创建自己的。
AbstractFailureAnalyzer
是一个方便的扩展,用于检查要处理的异常中是否存在指定的异常类型。
您可以从该 API 进行扩展,以便您的 implementation 仅在实际存在异常时才有机会处理异常。
如果由于某种原因无法处理异常,则返回以给另一个实现处理异常的机会。FailureAnalyzer
null
FailureAnalyzer
实施必须在 中注册。
以下示例 registers :META-INF/spring.factories
ProjectConstraintViolationFailureAnalyzer
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.example.ProjectConstraintViolationFailureAnalyzer
如果需要访问 或 ,请在实现中将它们声明为构造函数参数。BeanFactory Environment FailureAnalyzer |
1.2. 自动配置故障排除
Spring Boot 自动配置会尽最大努力“做正确的事情”,但有时事情会失败,而且很难说出原因。
任何 Spring Boot 中都有一个非常有用的可用。
如果启用日志记录输出,则可以看到它。
如果你使用(参见 Actuator 章节),还有一个端点以 JSON 形式呈现报告。
使用该端点调试应用程序并查看 Spring Boot 在运行时添加了哪些功能(以及尚未添加哪些功能)。ConditionEvaluationReport
ApplicationContext
DEBUG
spring-boot-actuator
conditions
通过查看源代码和 Javadoc 可以回答更多问题。 阅读代码时,请记住以下经验法则:
-
查找 called 的类并读取它们的源代码。 请特别注意注释,以了解它们启用的功能以及何时启用。 添加到命令行或 System 属性,以在控制台上获取应用程序中做出的所有自动配置决策的日志。 在启用了 actuator 的正在运行的应用程序中,查看端点(或 JMX 等效项)以获取相同的信息。
*AutoConfiguration
@Conditional*
--debug
-Ddebug
conditions
/actuator/conditions
-
查找 Class(例如
ServerProperties
)并从中读取可用的外部配置选项。 该 annotation 具有一个属性,该属性充当外部属性的前缀。 因此, has 及其配置属性为 、 和 others。 在启用了 actuator 的正在运行的应用程序中,查看 endpoint。@ConfigurationProperties
@ConfigurationProperties
name
ServerProperties
prefix="server"
server.port
server.address
configprops
-
查找 method on 上的用法 to 以宽松的方式显式地从 中提取配置值。 它通常与前缀一起使用。
bind
Binder
Environment
-
查找直接绑定到 .
@Value
Environment
-
查找为响应 SpEL 表达式而打开和关闭功能的注释,通常使用从 .
@ConditionalOnExpression
Environment
1.3. 在启动之前自定义 Environment 或 ApplicationContext
具有 和 ,用于将自定义项应用于上下文或环境。
Spring Boot 加载了许多此类自定义项,以便在内部使用 。
有多种方法可以注册其他自定义项:SpringApplication
ApplicationListeners
ApplicationContextInitializers
META-INF/spring.factories
-
以编程方式,每个应用程序,通过在运行之前调用 and 方法。
addListeners
addInitializers
SpringApplication
-
通过设置 or 属性,以声明方式为每个应用程序。
context.initializer.classes
context.listener.classes
-
以声明方式,对于所有应用程序,通过添加 a 并打包一个 jar 文件,所有应用程序都将其用作库。
META-INF/spring.factories
它会向侦听器发送一些特殊消息(有些甚至在创建上下文之前),然后也会为 消息器发布的事件注册侦听器。
有关完整列表,请参阅“Spring Boot 功能”部分中的“应用程序事件和侦听器”。SpringApplication
ApplicationEvents
ApplicationContext
还可以使用 在刷新应用程序上下文之前自定义 。
每个实现都应在 中注册,如以下示例所示:Environment
EnvironmentPostProcessor
META-INF/spring.factories
org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor
该实现可以加载任意文件并将它们添加到 .
例如,以下示例从 Classpath 加载 YAML 配置文件:Environment
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)
}
}
}
已经准备好了 Spring Boot 默认加载的所有常用属性源。
因此,可以从环境中获取文件的位置。
前面的示例在列表的末尾添加了 property source,以便在任何其他通常的位置中定义的键优先。
自定义实现可以定义另一个 order。Environment custom-resource |
虽然使用 on your 似乎是在 中加载自定义资源的便捷方法,但我们不建议这样做。
在刷新应用程序上下文之前,不会将此类属性源添加到 中。
现在配置某些属性(例如,在刷新开始之前读取的 and)为时已晚。@PropertySource @SpringBootApplication Environment Environment logging.* spring.main.* |
1.4. 构建ApplicationContext层次结构(添加父上下文或根上下文)
您可以使用该类创建父/子层次结构。
有关更多信息,请参阅“Spring Boot 功能”部分中的“features.html”。ApplicationBuilder
ApplicationContext
1.5. 创建非 Web 应用程序
并非所有 Spring 应用程序都必须是 Web 应用程序(或 Web 服务)。
如果您想在方法中执行一些代码,但同时引导 Spring 应用程序以设置要使用的基础设施,则可以使用 Spring Boot 的功能。
A 更改其类,具体取决于它是否认为它需要一个 Web 应用程序。
为了帮助它,您可以做的第一件事是将与服务器相关的依赖项(例如 servlet API)从 Classpath 中排除。
如果无法执行此操作(例如,从同一代码库运行两个应用程序),则可以显式调用实例或设置属性(通过 Java API 或使用外部属性)。
要作为业务逻辑运行的应用程序代码可以作为 实现,并作为定义放入上下文中。main
SpringApplication
SpringApplication
ApplicationContext
setWebApplicationType(WebApplicationType.NONE)
SpringApplication
applicationContextClass
CommandLineRunner
@Bean
2. 属性和配置
本节包括有关设置和读取属性和配置设置以及它们与 Spring Boot 应用程序的交互的主题。
2.1. 在构建时自动扩展属性
您可以使用现有的构建配置来自动扩展这些属性,而不是对项目的构建配置中指定的某些属性进行硬编码。 这在 Maven 和 Gradle 中都是可能的。
2.1.1. 使用 Maven 自动扩展属性
您可以使用资源筛选自动扩展 Maven 项目中的属性。
如果使用 ,则可以用占位符引用 Maven 的“项目属性”,如以下示例所示:spring-boot-starter-parent
@..@
app:
encoding: "@project.build.sourceEncoding@"
java:
version: "@java.version@"
仅以这种方式过滤 生产配置 (换句话说,不应用过滤 )。src/test/resources |
如果启用该标志,则 goal 可以直接添加到 Classpath 中(用于热重载目的)。
这样做会规避资源筛选和此功能。
相反,您可以使用目标或自定义插件的配置。
有关更多详细信息,请参阅插件使用页面。addResources spring-boot:run src/main/resources exec:java |
如果您不使用 starter 父级,则需要在 :<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>
如果您在配置中使用标准 Spring 占位符(例如 ),则该属性非常重要。
如果该属性未设置为 ,则内部版本可能会扩展这些属性。useDefaultDelimiters ${placeholder} false |
2.1.2. 使用 Gradle 自动扩展属性
您可以通过配置 Java 插件的任务来自动扩展 Gradle 项目中的属性,如以下示例所示:processResources
tasks.named('processResources') {
expand(project.properties)
}
然后,您可以使用占位符引用 Gradle 项目的属性,如以下示例所示:
app.name=${name}
app.description=${description}
app:
name: "${name}"
description: "${description}"
Gradle 的方法使用 Groovy 的 ,它转换令牌。
该样式与 Spring 自己的属性占位符机制冲突。
要将 Spring 属性占位符与自动扩展一起使用,请按如下方式转义 Spring 属性占位符:。expand SimpleTemplateEngine ${..} ${..} \${..} |
2.2. 外部化 SpringApplication 的配置
A 具有 Bean 属性 setter,因此您可以在创建应用程序时使用其 Java API 来修改其行为。
或者,也可以通过在 中设置属性来外部化配置。
例如,在 中,您可能有以下设置:SpringApplication
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)
}
}
Or to 方法 :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. 更改应用程序的外部属性的位置
默认情况下,来自不同来源的属性将按照定义的顺序添加到 Spring 中(有关确切顺序,请参阅“Spring Boot 功能”部分中的“features.html”)。Environment
您还可以提供以下 System 属性(或环境变量)来更改行为:
-
spring.config.name
(SPRING_CONFIG_NAME
):默认为文件名的根目录。application
-
spring.config.location
(SPRING_CONFIG_LOCATION
):要加载的文件(例如类路径资源或 URL)。 为此文档设置了一个单独的属性源,它可以被系统属性、环境变量或命令行覆盖。Environment
无论你在环境中设置什么, Spring Boot 始终如上所述加载。
默认情况下,如果使用 YAML,则扩展名为 '.yaml' 和 '.yml的文件也会添加到列表中。application.properties
如果需要有关正在加载的文件的详细信息,可以将 的日志记录级别设置为 。org.springframework.boot.context.config trace |
2.4. 使用 'short' 命令行参数
有些人喜欢在命令行上使用 (例如) 而不是设置配置属性。
您可以通过在 中使用占位符来启用此行为,如以下示例所示:--port=9000
--server.port=9000
application.properties
server.port=${port:8080}
server:
port: "${port:8080}"
如果从 POM 继承,则 default filter token 的 this 已从 更改为 (即,而不是 ),以防止与 Spring 样式占位符冲突。
如果您已为直接启用了 Maven 筛选,则可能还需要更改默认筛选条件令牌以使用其他分隔符。spring-boot-starter-parent maven-resources-plugins ${*} @ @maven.token@ ${maven.token} application.properties |
在此特定情况下,端口绑定在 PaaS 环境(如 Heroku 或 Cloud Foundry)中工作。
在这两个平台中,环境变量是自动设置的,Spring 可以绑定到属性的大写同义词。PORT 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
创建一个名为 的文件,并将其放在 Classpath 的根目录中。
然后添加到您的依赖项中(Maven 坐标 ,如果您使用 ,则已包含)。
YAML 文件被解析为 Java(如 JSON 对象),Spring Boot 将 Map 展平,使其深度为一层,并具有句点分隔的键,就像许多人习惯于 Java 中的文件一样。application.yaml
snakeyaml
org.yaml:snakeyaml
spring-boot-starter
Map<String,Object>
Properties
前面的示例 YAML 对应于以下文件:application.properties
spring.application.name=cruncher
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost/test
server.port=9000
有关 YAML 的更多信息,请参阅“Spring Boot 功能”部分中的“features.html”。
2.6. 设置活动的 Spring 配置文件
Spring 有一个 API 来实现这一点,但你通常会设置一个 System 属性 () 或一个 OS 环境变量 () 。
此外,您可以使用参数启动应用程序(请记住将其放在主类或 jar 存档之前),如下所示:Environment
spring.profiles.active
SPRING_PROFILES_ACTIVE
-D
$ 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 属性或环境变量设置,而不是 method。
因此,后一个 Java API 可用于在不更改默认值的情况下扩充配置文件。SpringApplicationBuilder.profiles()
有关更多信息,请参阅“Spring Boot 功能”部分中的“features.html”。
2.7. 设置默认配置文件名称
默认配置文件是在没有活动配置文件时启用的配置文件。
默认情况下,默认配置文件的名称为 ,但可以使用 System 属性 () 或 OS 环境变量 () 进行更改。default
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),这些文件可以根据活动配置文件有条件地激活。
如果文档包含键,则 profiles 值(以逗号分隔的 profiles 列表或 profile 表达式)将馈送到 Spring 方法中。
如果配置文件表达式匹配,则该文档将包含在最终合并中(否则,它不是),如以下示例所示:spring.config.activate.on-profile
Environment.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。 如果 'production' 处于活动状态,则端口为 0。
文档将按遇到它们的顺序进行合并。 较晚的值将覆盖较早的值。 |
2.9. 发现外部属性的内置选项
Spring Boot 在运行时将外部属性(或 YAML 文件和其他地方)绑定到应用程序中。
没有(从技术上讲也不可能)在一个位置包含所有受支持属性的详尽列表,因为贡献可能来自 Classpath 上的其他 jar 文件。application.properties
具有 Actuator 功能的正在运行的应用程序具有一个端点,该端点显示通过 .configprops
@ConfigurationProperties
附录包括一个application.properties
示例,其中包含 Spring Boot 支持的最常见属性的列表。
最终列表来自搜索源代码和注释以及偶尔使用 .
有关 loading 属性的确切顺序的更多信息,请参阅 “features.html”。@ConfigurationProperties
@Value
Binder
3. 嵌入式 Web 服务器
每个 Spring Boot Web 应用程序都包含一个嵌入式 Web 服务器。 此功能会导致许多操作问题,包括如何更改嵌入式服务器以及如何配置嵌入式服务器。 本节将回答这些问题。
3.1. 使用其他 Web 服务器
许多 Spring Boot Starters包括默认的嵌入式容器。
-
对于 servlet 堆栈应用程序,通过 include 来包含 Tomcat,但您可以改用 or。
spring-boot-starter-web
spring-boot-starter-tomcat
spring-boot-starter-jetty
spring-boot-starter-undertow
-
对于反应式堆栈应用程序,它通过包含 、 来包含 Reactor Netty,但你可以使用 、 或 代替。
spring-boot-starter-webflux
spring-boot-starter-reactor-netty
spring-boot-starter-tomcat
spring-boot-starter-jetty
spring-boot-starter-undertow
切换到其他 HTTP 服务器时,您需要将默认依赖项交换为所需的依赖项。 为了帮助完成此过程, Spring Boot 为每个受支持的 HTTP 服务器提供了一个单独的Starters。
下面的 Maven 示例展示了如何排除 Tomcat 并包括 Jetty for Spring MVC:
<properties>
<jakarta-servlet.version>5.0.0</jakarta-servlet.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>
Jakarta Servlet API 的版本已被覆盖,因为与 Tomcat 10 和 Undertow 2.3 不同,Jetty 11 不支持 Servlet 6.0。 |
将 Servlet API 降级到 5.0 会破坏 Spring Framework 的 Servlet 相关 mock! 由于 Jetty 需要 Servlet API 5.0,因此您有两种工作安排:
如果您的应用程序的测试需要混合使用 Web 环境,则您的测试设置可能需要进行一些结构更改,以严格分离这两个 Web 环境。 |
下面的 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 是必须使用该类的,因此即使需要包含不同的 HTTP 服务器,也可能需要保持对 Netty 的依赖。WebClient |
3.2. 禁用 Web 服务器
如果你的 Classpath 包含启动 Web 服务器所需的位,Spring Boot 将自动启动它。
要禁用此行为,请在 中配置 ,如以下示例所示:WebApplicationType
application.properties
spring.main.web-application-type=none
spring:
main:
web-application-type: "none"
3.3. 更改 HTTP 端口
在独立应用程序中,主 HTTP 端口默认为,但可以使用 (例如,in 或 as a System 属性) 进行设置。
由于值的松散绑定,您还可以使用 (例如,作为 OS 环境变量)。8080
server.port
application.properties
Environment
SERVER_PORT
要完全关闭 HTTP 端点,但仍创建 , use(这样做有时对测试很有用)。WebApplicationContext
server.port=-1
有关更多详细信息,请参阅“Spring Boot 功能”部分中的“web.html”或 ServerProperties
源代码。
3.5. 在运行时发现 HTTP 端口
您可以从日志输出或通过其 访问运行服务器的端口。
获取该容器并确保其已初始化的最佳方法是添加 of 类型,并在发布事件时将容器从事件中拉出。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。
以下示例显示了使用 Java KeyStore 文件设置 SSL 属性:server.ssl.*
application.properties
application.yaml
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 连接器的配置。
如果要同时拥有两者,则需要以编程方式配置其中一个。
我们建议使用 来配置 HTTPS,因为 HTTP 连接器是两者中更容易以编程方式配置的。application.properties
application.properties
3.7.1. 使用 PEM 编码的文件
您可以使用 PEM 编码的文件,而不是 Java KeyStore 文件。
您应该尽可能使用 PKCS#8 密钥文件。
PEM 编码的 PKCS#8 密钥文件以 or 标头开头。-----BEGIN PRIVATE KEY-----
-----BEGIN ENCRYPTED PRIVATE KEY-----
如果您有其他格式的文件,例如 PKCS#1 () 或 SEC 1 (),您可以使用 OpenSSL 将它们转换为 PKCS#8:-----BEGIN RSA PRIVATE KEY-----
-----BEGIN EC PRIVATE KEY-----
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 捆绑包中配置 SSL 信任材料并应用于 Web 服务器,如以下示例所示:
server.port=8443
server.ssl.bundle=example
server:
port: 8443
ssl:
bundle: "example"
该属性不能与 下的 discrete Java KeyStore 或 PEM 属性选项结合使用。server.ssl.bundle server.ssl |
请参阅 Ssl
以了解有关所有受支持属性的详细信息。
3.8. 配置 HTTP/2
您可以使用 configuration 属性在 Spring Boot 应用程序中启用 HTTP/2 支持。
(基于 TLS 的 HTTP/2)和(基于 TCP 的 HTTP/2)均受支持。
要使用 ,还必须启用 SSL。
如果未启用 SSL 时,将使用 SSL。
例如,您可能希望在应用程序在执行 TLS 终止的代理服务器后面运行时使用。server.http2.enabled
h2
h2c
h2
h2c
h2c
3.8.1. 使用 Tomcat 的 HTTP/2
Spring Boot 默认附带 Tomcat 10.1.x,它支持并且开箱即用。
或者,如果库及其依赖项安装在主机操作系统上,则可以使用 for support。h2c
h2
libtcnative
h2
库目录必须可用于 JVM 库路径(如果尚未可用)。
您可以使用 JVM 参数(如 .
更多相关信息,请参阅 Tomcat 官方文档。-Djava.library.path=/usr/local/opt/tomcat-native/lib
3.8.2. 使用 Jetty 的 HTTP/2
对于 HTTP/2 支持,Jetty 需要额外的依赖项。
要使用,不需要其他依赖项。
要使用 ,您还需要根据您的部署选择以下依赖项之一:org.eclipse.jetty.http2:http2-server
h2c
h2
-
org.eclipse.jetty:jetty-alpn-java-server
使用 JDK 内置支持 -
org.eclipse.jetty:jetty-alpn-conscrypt-server
和 Conscrypt 库
3.8.3. 使用 Reactor Netty 的 HTTP/2
默认情况下,它使用 Reactor Netty 作为服务器。
Reactor Netty 支持且开箱即用。
为了实现最佳的运行时性能,此服务器还支持本机库。
要启用此功能,您的应用程序需要具有额外的依赖项。spring-boot-webflux-starter
h2c
h2
h2
Spring Boot 管理“uber jar”的版本,其中包含所有平台的本机库。
开发人员可以选择使用分类器仅导入所需的依赖项(参见 Netty 官方文档)。io.netty:netty-tcnative-boringssl-static
3.9. 配置 Web 服务器
通常,您应该首先考虑使用众多可用配置键之一,并通过在 or 文件中添加新条目来自定义您的 Web 服务器。
请参阅“发现外部属性的内置选项”)。
命名空间在这里非常有用,它包括像 、 和其他命名空间,用于特定于服务器的功能。
请参阅application-properties.html列表。application.properties
application.yaml
server.*
server.tomcat.*
server.jetty.*
前面的部分已经涵盖了许多常见使用案例,例如压缩、SSL 或 HTTP/2。
但是,如果您的用例不存在配置键,则应查看WebServerFactoryCustomizer
。
您可以声明这样的组件并访问与您选择的相关的服务器工厂:您应该为所选服务器(Tomcat、Jetty、Reactor Netty、Undertow)和所选的 Web 堆栈(servlet 或 reactive)选择变体。
以下示例适用于具有 (servlet 堆栈) 的 Tomcat:spring-boot-starter-web
@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 在内部使用该基础结构来自动配置服务器。
自动配置的 bean 具有 order of 并将在任何用户定义的定制器之前进行处理,除非它具有明确的顺序,另有说明。WebServerFactoryCustomizer 0 |
使用定制器访问 后,您可以使用它来配置特定部分,例如连接器、服务器资源或服务器本身 - 所有这些都使用特定于服务器的 API。WebServerFactory
此外,Spring Boot 还提供:
服务器 | Servlet 堆栈 | 反应式堆栈 |
---|---|---|
Tomcat |
|
|
Jetty |
|
|
Undertow |
|
|
反应器 |
不适用 |
|
作为最后的手段,您还可以声明自己的 bean,这将覆盖 Spring Boot 提供的 bean。
执行此操作时,自动配置的定制器仍会应用于您的自定义工厂,因此请谨慎使用该选项。WebServerFactory
3.10. 向应用程序添加 Servlet、Filter 或 Listener
在 Servlet 堆栈应用程序中,即使用 ,有两种方法可以将 、 、 以及 Servlet API 支持的其他侦听器添加到应用程序中:spring-boot-starter-web
Servlet
Filter
ServletContextListener
3.10.1. 使用 Spring bean 添加 servlet、过滤器或侦听器
要使用 Spring Bean 添加 、 或 Servlet,必须为其提供定义。
当您想要注入配置或依赖项时,这样做可能非常有用。
但是,您必须非常小心,不要让它们引起太多其他 bean 的急切初始化,因为它们必须在应用程序生命周期的早期就安装在容器中。
(例如,让它们依赖于 your 或 JPA 配置不是一个好主意。
您可以通过在首次使用时而不是在初始化时延迟初始化 bean 来解决此类限制。Servlet
Filter
*Listener
@Bean
DataSource
对于过滤器和 Servlet,您还可以通过添加 a 或 a 来添加映射和 init 参数,而不是底层组件,或者添加底层组件。FilterRegistrationBean
ServletRegistrationBean
如果未在筛选器注册上指定 no,则使用 。
这与 Servlet 规范的默认 dispatcher 类型一致。 |
与任何其他 Spring bean 一样,您可以定义 servlet 过滤器 bean 的顺序;请务必查看“web.html”部分。
禁用 Servlet 或过滤器的注册
如前所述,任何 或 bean 都会自动注册到 servlet 容器中。
要禁用特定 bean 或 bean 的注册,请为其创建一个注册 bean 并将其标记为已禁用,如以下示例所示:Servlet
Filter
Filter
Servlet
@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. 配置 Access Logging
可以通过 Tomcat、Undertow 和 Jetty 各自的命名空间为 Tomcat、Undertow 和 Jetty 配置访问日志。
例如,以下设置使用自定义模式记录对 Tomcat 的访问。
server.tomcat.basedir=my-tomcat
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%t %a %r %s (%D microseconds)
server:
tomcat:
basedir: "my-tomcat"
accesslog:
enabled: true
pattern: "%t %a %r %s (%D microseconds)"
日志的默认位置是相对于 Tomcat 基目录的目录。
默认情况下,该目录是一个临时目录,因此您可能需要修复 Tomcat 的基目录或使用日志的绝对路径。
在前面的示例中,日志相对于应用程序的工作目录可用。logs logs my-tomcat/logs |
Undertow 的访问日志记录可以采用类似的方式进行配置,如以下示例所示:
server.undertow.accesslog.enabled=true
server.undertow.accesslog.pattern=%t %a %r %s (%D milliseconds)
server.undertow.options.server.record-request-start-time=true
server:
undertow:
accesslog:
enabled: true
pattern: "%t %a %r %s (%D milliseconds)"
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"
默认情况下,日志将重定向到 。
有关更多详细信息,请参阅 Jetty 文档。System.err
3.12. 在前端代理服务器后面运行
如果您的应用程序在代理、负载均衡器或云中运行,则请求信息(如主机、端口、方案等)可能会在此过程中发生变化。
您的应用程序可能正在 上运行,但 HTTP 客户端应该只能看到 。10.10.10.10:8080
example.org
RFC7239 “Forwarded Headers” 定义 HTTP 标头;代理可以使用此标头提供有关原始请求的信息。
您可以将应用程序配置为读取这些标头,并在创建链接并将其发送到 HTTP 302 响应、JSON 文档或 HTML 页面中的客户端时自动使用该信息。
还有非标准标头,如 、 和 。Forwarded
X-Forwarded-Host
X-Forwarded-Port
X-Forwarded-Proto
X-Forwarded-Ssl
X-Forwarded-Prefix
如果代理添加了常用的 and 标头,则设置为 to 就足以支持这些标头。
使用此选项,Web 服务器本身本身支持此功能;您可以查看他们的特定文档以了解特定行为。X-Forwarded-For
X-Forwarded-Proto
server.forward-headers-strategy
NATIVE
如果这还不够,Spring 框架为 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}"
您可以通过将 设置为 empty 来信任所有代理(但在 production 中不要这样做)。internal-proxies |
您可以通过关闭自动配置(为此,请设置 )并使用 bean 添加新的 Valve 实例来完全控制 Tomcat 的配置。RemoteIpValve
server.forward-headers-strategy=NONE
WebServerFactoryCustomizer
3.13. 使用 Tomcat 启用多个连接器
您可以向 添加 ,这样可以允许多个连接器,包括 HTTP 和 HTTPS 连接器,如以下示例所示:org.apache.catalina.connector.Connector
TomcatServletWebServerFactory
@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 的 MBean 注册表
默认情况下,Embedded Tomcat 的 MBean 注册表处于禁用状态。
这样可以最大程度地减少 Tomcat 的内存占用。
例如,如果要使用 Tomcat 的 MBean,以便 Micrometer 可以使用它们来公开度量,则必须使用该属性来执行此操作,如以下示例所示:server.tomcat.mbeanregistry.enabled
server.tomcat.mbeanregistry.enabled=true
server:
tomcat:
mbeanregistry:
enabled: true
3.15. 使用 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.16. 使用 @ServerEndpoint 创建 WebSocket 端点
如果要在使用嵌入式容器的 Spring Boot 应用程序中使用,则必须声明单个,如以下示例所示:@ServerEndpoint
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 将任何带注释的 bean 注册到底层 WebSocket 容器。
当部署到独立的 servlet 容器时,此角色由 servlet 容器初始值设定项执行,并且不需要 bean。@ServerEndpoint
ServerEndpointExporter
4. Spring MVC
Spring Boot 有许多Starters,包括 Spring MVC。 请注意,一些 starters 包含对 Spring MVC 的依赖,而不是直接包含它。 本节回答有关 Spring MVC 和 Spring Boot 的常见问题。
4.1. 编写 JSON REST 服务
只要 Jackson2 在 Classpath 上,Spring Boot 应用程序中的任何 Spring 都应该默认呈现 JSON 响应,如以下示例所示:@RestController
@RestController
public class MyController {
@RequestMapping("/thing")
public MyThing thing() {
return new MyThing();
}
}
@RestController
class MyController {
@RequestMapping("/thing")
fun thing(): MyThing {
return MyThing()
}
}
只要可以被 Jackson2 序列化(对于普通的 POJO 或 Groovy 对象来说是如此),那么默认情况下会提供它的 JSON 表示。
请注意,在浏览器中,您有时可能会看到 XML 响应,因为浏览器倾向于发送首选 XML 的 accept 标头。MyThing
localhost:8080/thing
4.2. 编写 XML REST 服务
如果 Classpath 上有 Jackson XML 扩展 (),则可以使用它来呈现 XML 响应。
我们用于 JSON 的上一个示例将起作用。
要使用 Jackson XML 渲染器,请将以下依赖项添加到您的项目中:jackson-dataformat-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 库是项目的一部分,例如通过添加:
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
</dependency>
要让服务器呈现 XML 而不是 JSON,您可能必须发送标头(或使用浏览器)。Accept: text/xml |
4.3. 自定义 Jackson ObjectMapper
Spring MVC(客户端和服务器端)用于在 HTTP 交换中协商内容转换。
如果 Jackson 在 classpath 上,则您已经获得了 提供的默认转换器,其实例已为您自动配置。HttpMessageConverters
Jackson2ObjectMapperBuilder
(或 for Jackson XML 转换器)实例(默认创建)具有以下自定义属性:ObjectMapper
XmlMapper
-
MapperFeature.DEFAULT_VIEW_INCLUSION
已禁用 -
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
已禁用 -
SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
已禁用 -
SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS
已禁用
Spring Boot 还具有一些功能,可以更轻松地自定义此行为。
您可以使用环境配置 和 实例。
Jackson 提供了一套广泛的开/关功能,可用于配置其处理的各个方面。
这些功能在 6 个枚举(在 Jackson 中)中进行了描述,这些枚举映射到环境中的属性:ObjectMapper
XmlMapper
枚举 | 财产 | 值 |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
例如,要启用美颜打印,请将 .
请注意,由于使用了松弛绑定,case of 不必与相应的枚举常量的大小写匹配,即 。spring.jackson.serialization.indent_output=true
indent_output
INDENT_OUTPUT
这种基于环境的配置将应用于自动配置的 Bean,并应用于使用构建器创建的任何映射器,包括自动配置的 Bean。Jackson2ObjectMapperBuilder
ObjectMapper
上下文可以由一个或多个 bean 自定义。
可以对此类定制器 bean 进行排序(Boot 自己的定制器的 order 为 0),从而允许在 Boot 的定制之前和之后应用其他定制。Jackson2ObjectMapperBuilder
Jackson2ObjectMapperBuilderCustomizer
任何类型的 bean 都会自动注册到自动配置的 bean 中,并应用于它创建的任何实例。
这提供了一种全局机制,用于在向应用程序添加新功能时提供自定义模块。com.fasterxml.jackson.databind.Module
Jackson2ObjectMapperBuilder
ObjectMapper
如果要完全替换默认值,请定义该类型的 a 并将其标记为 ,或者如果您更喜欢基于生成器的方法,请定义 .
请注意,无论哪种情况,执行此操作都会禁用 .ObjectMapper
@Bean
@Primary
Jackson2ObjectMapperBuilder
@Bean
ObjectMapper
如果提供任何 type ,它们将替换 MVC 配置中的默认值。
此外,还提供了一个方便的 bean 类型(如果使用默认的 MVC 配置,则始终可用)。
它有一些有用的方法来访问默认和用户增强的消息转换器。@Beans
MappingJackson2HttpMessageConverter
HttpMessageConverters
有关更多详细信息,请参阅“自定义@ResponseBody渲染”部分和 WebMvcAutoConfiguration
源代码。
4.4. 自定义 @ResponseBody 渲染
Spring 用于渲染(或来自 的响应)。
您可以通过在 Spring Boot 上下文中添加适当类型的 bean 来贡献其他转换器。
如果您添加的 Bean 的类型无论如何都会包含在内(例如用于 JSON 转换),它将替换默认值。
提供了一个方便的 Bean 类型,如果您使用默认的 MVC 配置,那么该 Bean 始终可用。
它有一些有用的方法来访问默认和用户增强的消息转换器(例如,如果要手动将它们注入自定义 ),则可能很有用。HttpMessageConverters
@ResponseBody
@RestController
MappingJackson2HttpMessageConverter
HttpMessageConverters
RestTemplate
与正常的 MVC 用法一样,您提供的任何 bean 也可以通过覆盖该方法来提供转换器。
但是,与普通 MVC 不同的是,您只能提供所需的其他转换器(因为 Spring Boot 使用相同的机制来提供其默认值)。
最后,如果您通过提供自己的配置来选择退出 Spring Boot 默认 MVC 配置,则可以完全控制并使用 from 手动完成所有操作。WebMvcConfigurer
configureMessageConverters
@EnableWebMvc
getMessageConverters
WebMvcConfigurationSupport
有关更多详细信息,请参见WebMvcAutoConfiguration
源代码。
4.5. 处理 Multipart 文件上传
Spring Boot 采用 servlet 5 API 来支持上传文件。
默认情况下, Spring Boot 将 Spring MVC 配置为每个文件的最大大小为 1MB,在单个请求中的最大文件数据为 10MB。
您可以使用类中公开的属性覆盖这些值、中间数据存储的位置(例如,存储到目录)以及将数据刷新到磁盘的阈值。
例如,如果要指定文件不受限制,请将该属性设置为 。jakarta.servlet.http.Part
/tmp
MultipartProperties
spring.servlet.multipart.max-file-size
-1
当你想在 Spring MVC 控制器处理程序方法中将多部分编码文件数据作为 type 的 -annotated 参数接收时,multipart 支持非常有用。@RequestParam
MultipartFile
有关更多详细信息,请参阅 MultipartAutoConfiguration
源。
建议使用容器的内置支持来进行分段上传,而不是引入额外的依赖项,例如 Apache Commons File Upload。 |
4.6. 关闭 Spring MVC DispatcherServlet
默认情况下,所有内容都从应用程序的根目录 () 提供。
如果您希望映射到其他路径,则可以按如下方式配置一个路径:/
spring.mvc.servlet.path=/mypath
spring:
mvc:
servlet:
path: "/mypath"
如果你有其他 servlet,你可以声明一个 of type 或 for each,Spring Boot 会以透明的方式将它们注册到容器。
由于 Servlet 是以这种方式注册的,因此它们可以映射到 的子上下文,而无需调用它。@Bean
Servlet
ServletRegistrationBean
DispatcherServlet
配置 自己 是不寻常的,但如果您确实需要这样做,还必须提供 type 的 to provide the path of your custom .DispatcherServlet
@Bean
DispatcherServletPath
DispatcherServlet
4.7. 关闭默认 MVC 配置
完全控制 MVC 配置的最简单方法是提供您自己的 Comments。
这样做会将所有 MVC 配置都掌握在您手中。@Configuration
@EnableWebMvc
4.8. 自定义 ViewResolver
A 是 Spring MVC 的核心组件,将视图名称转换为实际实现。
请注意,它们主要用于 UI 应用程序,而不是 REST 样式的服务(a 不用于呈现 a )。
有许多实现可供选择,Spring 本身并不拘泥于您应该使用哪些实现。
另一方面, Spring Boot 会为您安装一两个,具体取决于它在 Classpath 和应用程序上下文中找到的内容。
它使用它在应用程序上下文中找到的所有解析程序,依次尝试每个解析程序,直到得到结果。
如果您添加自己的解析程序,则必须了解添加解析程序的顺序和位置。ViewResolver
@Controller
View
ViewResolvers
View
@ResponseBody
ViewResolver
DispatcherServlet
WebMvcAutoConfiguration
将以下内容添加到您的上下文中:ViewResolvers
-
一个名为 'defaultViewResolver'。 此 API 查找可使用 (包括静态资源和 JSP 页,如果使用它们) 呈现的物理资源。 它将前缀和后缀应用于视图名称,然后在 servlet 上下文中查找具有该路径的物理资源(默认值都为空,但可以通过 和 进行外部配置)。 您可以通过提供相同类型的 bean 来覆盖它。
InternalResourceViewResolver
DefaultServlet
spring.mvc.view.prefix
spring.mvc.view.suffix
-
一个名为 'beanNameViewResolver' 的。 这是视图解析器链中的一个有用成员,可以拾取与正在解析的 bean 同名的任何 bean。 应该没有必要覆盖或替换它。
BeanNameViewResolver
View
-
仅当实际存在 bean 类型时,才会添加命名的 'viewResolver'。 这是一个复合解析器,委托给所有其他解析器,并尝试查找与客户端发送的 'Accept' HTTP 标头的匹配项。 有一个关于
ContentNegotiatingViewResolver
的有用博客,您可能想学习以了解更多信息,您还可以查看源代码以获取详细信息。 你可以通过定义一个名为 'viewResolver' 的 bean 来关闭自动配置。ContentNegotiatingViewResolver
View
ContentNegotiatingViewResolver
-
如果你使用 Thymeleaf,你还有一个名为 'thymeleafViewResolver' 。 它通过用前缀和后缀将视图名称括起来来查找资源。 前缀为 ,后缀为 。 前缀和后缀的值分别默认为 'classpath:/templates/' 和 '.html' 。 您可以通过提供同名的 bean 来覆盖。
ThymeleafViewResolver
spring.thymeleaf.prefix
spring.thymeleaf.suffix
ThymeleafViewResolver
-
如果您使用 FreeMarker,则还有一个名为 'freeMarkerViewResolver'。 它通过在视图名称周围加上前缀和后缀来查找加载器路径(该路径已外部化,默认值为 'classpath:/templates/')。 前缀外部化为 ,后缀外部化为 。 前缀和后缀的默认值分别为 empty 和 '.ftlh'。 您可以通过提供同名的 bean 来覆盖。
FreeMarkerViewResolver
spring.freemarker.templateLoaderPath
spring.freemarker.prefix
spring.freemarker.suffix
FreeMarkerViewResolver
-
如果你使用 Groovy 模板(实际上,如果你在你的 classpath 上),你还有一个名为 'groovyMarkupViewResolver'。 它通过在视图名称周围加上前缀和后缀(externalized to 和 )来查找加载器路径中的资源。 前缀和后缀的默认值分别为 'classpath:/templates/' 和 '.tpl'。 您可以通过提供同名的 bean 来覆盖。
groovy-templates
GroovyMarkupViewResolver
spring.groovy.template.prefix
spring.groovy.template.suffix
GroovyMarkupViewResolver
-
如果您使用 Mustache,那么您还有一个名为 'mustacheViewResolver'。 它通过用前缀和后缀将视图名称括起来来查找资源。 前缀为 ,后缀为 。 前缀和后缀的值分别默认为 'classpath:/templates/' 和 '.mustache'。 您可以通过提供同名的 bean 来覆盖。
MustacheViewResolver
spring.mustache.prefix
spring.mustache.suffix
MustacheViewResolver
有关更多详细信息,请参阅以下部分:
5. Jersey
5.1. 使用 Spring Security 保护 Jersey 端点
Spring Security 可用于保护基于 Jersey 的 Web 应用程序,其方式与用于保护基于 Spring MVC 的 Web 应用程序的方式大致相同。
但是,如果要将 Spring Security 的方法级安全性与 Jersey 一起使用,则必须将 Jersey 配置为使用 rather .
这可以防止 Jersey 在 Spring Security 有机会向 Client 端报告身份验证或授权失败之前提交响应。setStatus(int)
sendError(int)
该属性必须设置为在应用程序的 Bean 上,如以下示例所示:jersey.config.server.response.setStatusOverSendError
true
ResourceConfig
@Component
public class JerseySetStatusOverSendErrorConfig extends ResourceConfig {
public JerseySetStatusOverSendErrorConfig() {
register(Endpoint.class);
setProperties(Collections.singletonMap("jersey.config.server.response.setStatusOverSendError", true));
}
}
5.2. 将 Jersey 与另一个 Web 框架一起使用
要将 Jersey 与其他 Web 框架(如 Spring MVC)一起使用,应对其进行配置,以便允许其他框架处理它无法处理的请求。
首先,通过将 application 属性配置为值 .
其次,配置您的请求以转发会导致 404 的请求,如以下示例所示。spring.jersey.type
filter
ResourceConfig
@Component
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(Endpoint.class);
property(ServletProperties.FILTER_FORWARD_ON_404, true);
}
}
6. HTTP 客户端
Spring Boot 提供了许多与 HTTP 客户端一起使用的Starters。 本节回答了与使用它们相关的问题。
6.1. 配置 RestTemplate 以使用代理
如 io.html中所述,您可以使用 with 构建自定义的 .
这是创建配置为使用代理的推荐方法。RestTemplateCustomizer
RestTemplateBuilder
RestTemplate
RestTemplate
代理配置的确切细节取决于正在使用的底层客户端请求工厂。
6.2. 配置基于 Reactor Netty 的 WebClient 使用的 TcpClient
当 Reactor Netty 位于 Classpath 上时,将自动配置基于 Reactor Netty 的 Reactor Netty。
要自定义客户端对网络连接的处理,请提供 Bean。
以下示例配置了 60 秒的连接超时,并添加了一个 :WebClient
ClientHttpConnector
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)
}
}
请注意 for the connection provider 和 event loop 资源的使用。
这确保了接收请求的服务器和发出请求的客户端有效地共享资源。ReactorResourceFactory |
7. 日志记录
Spring Boot 没有强制性的日志记录依赖项,除了 Commons Logging API,它通常由 Spring Framework 的模块提供。
要使用 Logback,您需要将其包含在 Classpath 中。
推荐的方法是通过 starters,这都依赖于 .
对于 Web 应用程序,您只需要 ,因为它在传递上依赖于日志记录Starters。
如果您使用 Maven,则以下依赖项会为您添加日志记录:spring-jcl
spring-jcl
spring-boot-starter-logging
spring-boot-starter-web
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Spring Boot 有一个抽象,它尝试根据 Classpath 的内容配置日志记录。
如果 Logback 可用,则它是首选。LoggingSystem
如果你需要对日志记录进行的唯一更改是设置各种 Logger 的级别,则可以使用 “logging.level” 前缀来执行此操作,如以下示例所示:application.properties
logging.level.org.springframework.web=debug
logging.level.org.hibernate=error
logging:
level:
org.springframework.web: "debug"
org.hibernate: "error"
您还可以使用 设置要将日志写入的文件的位置(除了控制台之外)。logging.file.name
要配置日志记录系统的更精细设置,您需要使用相关系统支持的本机配置格式。
默认情况下, Spring Boot 从系统的默认位置(例如 Logback)获取本机配置,但您可以使用该属性设置配置文件的位置。LoggingSystem
classpath:logback.xml
logging.config
7.1. 配置 Logback 以进行日志记录
如果您需要将自定义应用于 logback,而不是使用 实现的自定义,则需要添加标准 logback 配置文件。
您可以将文件添加到 Classpath 的根目录,以便 logback 查找。
如果要使用 Spring Boot Logback 扩展,也可以使用。application.properties
logback.xml
logback-spring.xml
Logback 文档有一个专门的部分,其中详细介绍了配置。 |
Spring Boot 提供了许多 logback 配置,这些配置可以位于您自己的配置中。
这些 includes 旨在允许重新应用某些常见的 Spring Boot 约定。included
以下文件在 下提供: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
此外,还提供了一个遗留文件,以便与早期版本的 Spring Boot 兼容。base.xml
典型的自定义文件如下所示:logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
<logger name="org.springframework.web" level="DEBUG"/>
</configuration>
您的 logback 配置文件还可以使用负责为您创建的 System 属性:LoggingSystem
-
${PID}
:当前进程 ID。 -
${LOG_FILE}
:是否在 Boot 的外部配置中设置。logging.file.name
-
${LOG_PATH}
:是否在 Boot 的外部配置中设置了 (表示日志文件所在的目录)。logging.file.path
-
${LOG_EXCEPTION_CONVERSION_WORD}
:是否在 Boot 的外部配置中设置。logging.exception-conversion-word
-
${ROLLING_FILE_NAME_PATTERN}
:是否在 Boot 的外部配置中设置。logging.pattern.rolling-file-name
Spring Boot 还通过使用自定义 Logback 转换器在控制台上(但不在日志文件中)提供了一些不错的 ANSI 颜色终端输出。
有关示例,请参阅配置中的 。CONSOLE_LOG_PATTERN
defaults.xml
如果 Groovy 在 Classpath 上,则您也应该能够配置 Logback。
如果存在,则优先使用此设置。logback.groovy
Groovy 配置不支持 Spring 扩展。
不会检测到任何文件。logback-spring.groovy |
7.1.1. 为仅文件输出配置 Logback
如果要禁用控制台日志记录并仅将输出写入文件,则需要一个 imports 但不导入的自定义,如以下示例所示: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>
您还需要添加到 or 中,如以下示例所示:logging.file.name
application.properties
application.yaml
logging.file.name=myapplication.log
logging:
file:
name: "myapplication.log"
7.2. 配置 Log4j 进行日志记录
如果 Log4j 2 在 Classpath 上,则 Spring Boot 支持 Log4j 2 进行日志记录配置。
如果使用 starters 来组装依赖项,则必须排除 Logback,然后包含 Log4j 2。
如果您不使用Starters,则除了 Log4j 2 之外,还需要提供(至少)其他功能。spring-jcl
推荐的路径是通过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 提供了几种不同的方法来设置 Starter。 一种方法是使用模块替换。 为此,请声明对 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 但使用 Log4j 2 配置输出)的依赖项收集在一起。java.util.logging |
要确保将 using 执行的调试日志记录路由到 Log4j 2 中,请将 system 属性设置为 来配置其 JDK 日志记录适配器。java.util.logging java.util.logging.manager org.apache.logging.log4j.jul.LogManager |
7.2.1. 使用 YAML 或 JSON 配置 Log4j 2
除了默认的 XML 配置格式外,Log4j 2 还支持 YAML 和 JSON 配置文件。 要将 Log4j 2 配置为使用备用配置文件格式,请将相应的依赖项添加到 Classpath 中,并命名配置文件以匹配您选择的文件格式,如以下示例所示:
格式 | 依赖 | 文件名 |
---|---|---|
YAML |
|
|
JSON 格式 |
|
|
8. 数据访问
Spring Boot 包含许多用于处理数据源的 Starter。 本节回答与执行此操作相关的问题。
8.1. 配置自定义 DataSource
要配置您自己的 ,请在您的配置中定义该类型的 。
Spring Boot 在需要的地方重用你,包括数据库初始化。
如果需要外部化某些设置,可以将 绑定到环境(请参阅“features.html”)。DataSource
@Bean
DataSource
DataSource
以下示例显示了如何在 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
假设 具有 URL、用户名和池大小的常规 JavaBean 属性,则这些设置将在 可用于其他组件之前自动绑定。SomeDataSource
DataSource
Spring Boot 还提供了一个名为 的 Util builder 类,该类可用于创建标准数据源之一(如果它在 Classpath 上)。
构建器可以根据 Classpath 上可用的内容来检测要使用的 one。
它还会根据 JDBC URL 自动检测驱动程序。DataSourceBuilder
以下示例演示如何使用 :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
但是,有一个问题。
由于未公开连接池的实际类型,因此不会在自定义的元数据中生成任何键,并且 IDE 中也没有可用的完成(因为接口没有公开任何属性)。
此外,如果您碰巧在 Classpath 上有 Hikari,则此基本设置不起作用,因为 Hikari 没有属性(但确实有属性)。
在这种情况下,您必须按如下方式重写配置:DataSource
DataSource
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
以下示例显示了如何创建 with :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()
}
}
您甚至可以利用为您服务的功能来更进一步 — 也就是说,如果未提供 URL,则为默认嵌入式数据库提供合理的用户名和密码。
你可以轻松地从任何对象的 state 初始化一个,因此你也可以注入 Spring Boot 自动创建的DataSource。
但是,这会将您的配置拆分为两个命名空间: 、 、 、 和 on ,其余的在您的自定义命名空间 () 上。
为避免这种情况,您可以在自定义命名空间上重新定义自定义,如以下示例所示:DataSourceProperties
DataSourceBuilder
DataSourceProperties
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 默认为您执行的操作同步,除了选择了专用连接池(在代码中)并且其设置在子名称空间中公开。
因为 is 会为您处理 / 翻译,所以您可以按如下方式配置它:app.datasource.configuration
DataSourceProperties
url
jdbcUrl
app.datasource.url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.configuration.maximum-pool-size=30
app:
datasource:
url: "jdbc:mysql://localhost/test"
username: "dbuser"
password: "dbpass"
configuration:
maximum-pool-size: 30
Spring Boot 会将特定于 Hikari 的设置公开给 .
此示例使用更通用的子命名空间,因为该示例不支持多个数据源实施。spring.datasource.hikari configuration |
因为您的自定义配置选择与 Hikari 一起使用,所以没有效果。
在实践中,构建器会使用您可能在此处设置的任何值进行初始化,然后被对 .app.datasource.type .type() |
有关更多详细信息,请参见“Spring Boot 功能”部分中的“data.html”和DataSourceAutoConfiguration
类。
8.2. 配置两个 DataSource
如果需要配置多个数据源,则可以应用上一节中描述的相同技巧。
但是,您必须将其中一个实例标记为 ,因为未来的各种自动配置都希望能够按类型获取一个实例。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 在自动配置中使用的逻辑相同。
请注意,每个 sub 命名空间都根据所选实现提供高级设置。configuration
8.3. 使用 Spring 数据存储库
Spring Data 可以创建各种风格的接口的实现。
Spring Boot 会为您处理所有这些操作,只要这些包含在自动配置包之一中,通常是主应用程序类的包(或子包),该包用 or 注释。@Repository
@Repositories
@SpringBootApplication
@EnableAutoConfiguration
对于许多应用程序,您所需要做的就是将正确的 Spring Data 依赖项放在 Classpath 上。
有一个用于 JPA、用于 MongoDB 以及支持技术的各种其他Starters。
要开始使用,请创建一些存储库接口来处理您的对象。spring-boot-starter-data-jpa
spring-boot-starter-data-mongodb
@Entity
Spring Boot 通过扫描自动配置包来确定定义的位置。
要获得更多控制,请使用 Spring Data 中的 Comments。@Repository
@Enable…Repositories
有关 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 的更多选项公开为外部配置属性。 其中一些是根据上下文自动检测的,因此您不必设置它们。
这是一种特殊情况,因为根据运行时条件,它具有不同的默认值。
如果使用嵌入式数据库,并且没有架构管理器(如 Liquibase 或 Flyway)正在处理 ,则默认为 。
在所有其他情况下,它默认为 。spring.jpa.hibernate.ddl-auto
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
此外,在创建 local 时,中的所有属性都作为普通 JPA 属性(去掉前缀)传递。spring.jpa.properties.*
EntityManagerFactory
您需要确保 下定义的名称与 JPA 提供程序预期的名称完全匹配。
Spring Boot 不会尝试对这些条目进行任何类型的松散绑定。 例如,如果要配置 Hibernate 的批处理大小,则必须使用 .
如果使用其他形式(如 或 ),则 Hibernate 将不会应用该设置。 |
如果需要对 Hibernate 属性应用高级自定义,请考虑注册一个 Bean,该 Bean 将在创建 .
这优先于自动配置应用的任何内容。HibernatePropertiesCustomizer EntityManagerFactory |
8.6. 配置 Hibernate 命名策略
Hibernate 使用两种不同的命名策略将名称从对象模型映射到相应的数据库名称。
物理和隐式策略实现的完全限定类名可以通过分别设置 和 属性来配置。
或者,如果 bean 在应用程序上下文中可用,则 Hibernate 将自动配置为使用它们。spring.jpa.hibernate.naming.physical-strategy
spring.jpa.hibernate.naming.implicit-strategy
ImplicitNamingStrategy
PhysicalNamingStrategy
默认情况下, Spring Boot 使用 .
使用此策略,所有点都替换为下划线,驼峰大小写也替换为下划线。
此外,默认情况下,所有表名都以小写形式生成。
例如,实体映射到表。
如果您的架构需要大小写混合标识符,请定义自定义 Bean,如以下示例所示:CamelCaseToUnderscoresNamingStrategy
TelephoneNumber
telephone_number
CamelCaseToUnderscoresNamingStrategy
@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 的默认值,请设置以下属性:
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()
}
}
有关更多详细信息,请参见HibernateJpaAutoConfiguration
和JpaBaseConfiguration
。
8.7. 配置 Hibernate 二级缓存
可以为一系列缓存提供程序配置 Hibernate 二级缓存。 与其配置 Hibernate 再次查找缓存提供程序,不如尽可能提供上下文中可用的缓存提供程序。
要使用 JCache 执行此操作,首先确保它在 Classpath 上可用。
然后,添加一个 Bean,如以下示例所示:org.hibernate.orm:hibernate-jcache
HibernatePropertiesCustomizer
@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 以使用与应用程序使用的相同。
也可以使用单独的实例。
有关详细信息,请参阅 Hibernate 用户指南。CacheManager
CacheManager
8.8. 在 Hibernate 组件中使用依赖注入
默认情况下, Spring Boot 注册一个使用转换器和实体侦听器的实现,以便转换器和实体侦听器可以使用常规的依赖项注入。BeanContainer
BeanFactory
您可以通过注册 来禁用或优化此行为,该 用于删除或更改属性。HibernatePropertiesCustomizer
hibernate.resource.beans.container
8.9. 使用自定义 EntityManagerFactory
要完全控制 的配置,您需要添加一个名为 'entityManagerFactory' 的 。
Spring Boot 自动配置在存在该类型的 bean 时关闭其实体 manager。EntityManagerFactory
@Bean
8.10. 使用多个 EntityManagerFactories
如果您需要对多个数据源使用 JPA,则可能需要每个数据源一个。
from Spring ORM 允许您根据需要配置 an。
您还可以重复使用 以绑定每个 的设置,如以下示例所示:EntityManagerFactory
LocalContainerEntityManagerFactoryBean
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()
}
}
上面的示例使用名为 .
它扫描与数据包位于同一包中的实体。
可以使用命名空间映射其他 JPA 属性。EntityManagerFactory
DataSource
firstDataSource
Order
app.first.jpa
当您为自己创建 Bean 时,在创建自动配置的 bean 期间应用的任何自定义都将丢失。
例如,在 Hibernate 的情况下,前缀下的任何属性都不会自动应用于您的 .
如果您依赖这些属性来配置命名策略或 DDL 模式等内容,则需要在创建 bean 时显式配置这些属性。LocalContainerEntityManagerFactoryBean LocalContainerEntityManagerFactoryBean spring.jpa.hibernate LocalContainerEntityManagerFactoryBean LocalContainerEntityManagerFactoryBean |
您应该为需要 JPA 访问权限的任何其他数据源提供类似的配置。
要完成这张图片,您还需要为每个 for each 配置 a。
或者,您可以使用跨越两者的 JTA 事务 Management 器。JpaTransactionManager
EntityManagerFactory
如果使用 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 默认情况下不会搜索或使用a。
如果您更喜欢使用传统的 ,则需要定义自己的类型(ID 为 'entityManagerFactory')并在此处设置持久性单元名称。META-INF/persistence.xml
persistence.xml
@Bean
LocalEntityManagerFactoryBean
有关默认设置,请参见JpaBaseConfiguration
。
8.12. 使用 Spring Data JPA 和 Mongo 存储库
Spring Data JPA 和 Spring Data Mongo 都可以自动为您创建实现。
如果它们都存在于 Classpath 中,则可能必须进行一些额外的配置以告诉 Spring Boot 要创建哪些存储库。
最明确的方法是使用标准的 Spring Data 和 Comments,并提供接口的位置。Repository
@EnableJpaRepositories
@EnableMongoRepositories
Repository
还有一些标志 ( 和 ) 可用于在外部配置中打开和关闭自动配置的存储库。
这样做很有用,例如,如果您想关闭 Mongo 存储库并仍然使用 auto-configured .spring.data.*.repositories.enabled
spring.data.*.repositories.type
MongoTemplate
其他自动配置的 Spring Data 存储库类型(Elasticsearch、Redis 等)存在相同的障碍和相同的功能。 要使用它们,请相应地更改注释和标志的名称。
8.13. 自定义 Spring Data 的 Web 支持
Spring Data 提供 Web 支持,可简化 Spring Data 存储库在 Web 应用程序中的使用。
Spring Boot 在名称空间中提供了用于自定义其配置的属性。
请注意,如果您使用的是 Spring Data REST,则必须改用名称空间中的属性。spring.data.web
spring.data.rest
8.14. 将 Spring Data Repositories 公开为 REST 端点
Spring Data REST 可以为您公开 REST 端点的实现,
前提是已为应用程序启用了 Spring MVC。Repository
Spring Boot 公开了一组有用的属性(来自名称空间),用于自定义RepositoryRestConfiguration
。
如果需要提供其他自定义,则应使用RepositoryRestConfigurer
bean。spring.data.rest
如果未在 custom 上指定任何 order ,它将在 Spring Boot 内部使用的一个之后运行。
如果需要指定顺序,请确保顺序大于 0。RepositoryRestConfigurer |
8.15. 配置 JPA 使用的组件
如果要配置 JPA 使用的组件,则需要确保在 JPA 之前初始化该组件。 当组件被自动配置时, Spring Boot 会为你处理这个问题。 例如,当 Flyway 被自动配置时,Hibernate 被配置为依赖于 Flyway,以便 Flyway 有机会在 Hibernate 尝试使用数据库之前初始化数据库。
如果您自己配置组件,则可以使用 subclass 作为设置必要依赖项的便捷方式。
例如,如果你使用 Hibernate Search 和 Elasticsearch 作为其索引管理器,则必须将任何 bean 配置为依赖于该 bean,如以下示例所示:EntityManagerFactoryDependsOnPostProcessor
EntityManagerFactory
elasticsearchClient
/**
* {@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 与多个数据源一起使用,则应为每个数据源创建自己的数据源。
有关更多详细信息,请参阅 JooqAutoConfiguration 。DSLContext
特别是,可以重复使用以提供与自动配置对单个 .JooqExceptionTranslator SpringTransactionProvider DataSource |
9. 数据库初始化
SQL 数据库可以以不同的方式初始化,具体取决于您的堆栈是什么。 当然,您也可以手动执行此操作,前提是数据库是一个单独的过程。 建议使用单个机制来生成架构。
9.1. 使用 Hibernate 初始化数据库
您可以设置控制 Hibernate 的数据库初始化。
支持的值为 、 、 、 和 。
Spring Boot 根据您是否使用嵌入式数据库为您选择默认值。
嵌入式数据库是通过查看类型和 JDBC URL 来识别的。、 或 嵌入式数据库,而其他数据库则不是。
如果标识了嵌入式数据库,但未检测到架构管理器(Flyway 或 Liquibase),则默认为 .
在所有其他情况下,它默认为 。spring.jpa.hibernate.ddl-auto
none
validate
update
create
create-drop
Connection
hsqldb
h2
derby
ddl-auto
create-drop
none
从内存中切换到“真实”数据库时要小心,不要对新平台中存在表和数据做出假设。
您必须显式设置或使用其他机制之一来初始化数据库。ddl-auto
您可以通过启用 Logger 来输出 schema 创建。
如果您启用 debug 模式,则会自动为您完成此操作。org.hibernate.SQL |
此外,如果 Hibernate 从头开始创建模式(即,如果属性设置为 或 ),则在启动时执行 Classpath 根目录中命名的文件。
如果您小心,这对于演示和测试很有用,但可能不是您希望在 production 中的 Classpath 上的内容。
它是一个 Hibernate 功能(与 Spring 无关)。import.sql
ddl-auto
create
create-drop
9.2. 使用基本 SQL 脚本初始化数据库
Spring Boot 可以自动创建 JDBC 或 R2DBC 的模式(DDL 脚本)并初始化其数据(DML 脚本)。DataSource
ConnectionFactory
默认情况下,它从 中加载架构脚本,并从 中加载数据脚本。
这些架构和数据脚本的位置可以分别使用 和 进行自定义。
前缀表示应用程序将在文件不存在时启动。
要使应用程序在文件不存在时无法启动,请删除前缀。optional:classpath*:schema.sql
optional:classpath*:data.sql
spring.sql.init.schema-locations
spring.sql.init.data-locations
optional:
optional:
此外,Spring Boot 会处理 and 文件(如果存在),其中 是 的值。
这允许您在必要时切换到特定于数据库的脚本。
例如,您可以选择将其设置为数据库的供应商名称(、 等)。optional:classpath*:schema-${platform}.sql
optional:classpath*:data-${platform}.sql
${platform}
spring.sql.init.platform
hsqldb
h2
oracle
mysql
postgresql
默认情况下,仅在使用嵌入式内存数据库时执行 SQL 数据库初始化。
要始终初始化 SQL 数据库(无论其类型如何),请设置为 。
同样,要禁用初始化,请设置为 。
默认情况下, Spring Boot 启用其基于脚本的数据库初始化器的快速失败功能。
这意味着,如果脚本导致异常,应用程序将无法启动。
您可以通过设置 来调整该行为。spring.sql.init.mode
always
spring.sql.init.mode
never
spring.sql.init.continue-on-error
默认情况下,在创建任何 JPA bean 之前执行基于脚本的初始化。 可用于为 JPA 托管的实体创建架构,并可用于填充它。
虽然我们不建议使用多个数据源初始化技术,但如果您希望基于脚本的初始化能够基于 Hibernate 执行的架构创建进行构建,请将 .
这会将数据源初始化推迟到创建和初始化任何 bean 之后。 然后,可以用于对 Hibernate 执行的任何模式创建进行添加,并可用于填充它。DataSource
EntityManagerFactory
schema.sql
data.sql
DataSource
spring.jpa.defer-datasource-initialization
true
EntityManagerFactory
schema.sql
data.sql
初始化脚本支持单行注释和块注释。
不支持其他注释格式。-- /* */ |
如果您使用的是更高级别的数据库迁移工具,如 Flyway 或 Liquibase,则应单独使用它们来创建和初始化架构。
不建议将 basic 和 scripts 与 Flyway 或 Liquibase 一起使用,在未来版本中将删除支持。schema.sql
data.sql
9.3. 初始化 Spring Batch 数据库
如果您使用 Spring Batch,则它预打包了适用于大多数流行数据库平台的 SQL 初始化脚本。 Spring Boot 可以检测您的数据库类型并在启动时执行这些脚本。 如果您使用嵌入式数据库,则默认情况下会发生这种情况。 您还可以为任何数据库类型启用它,如以下示例所示:
spring.batch.jdbc.initialize-schema=always
spring:
batch:
jdbc:
initialize-schema: "always"
您还可以通过设置为 来显式关闭初始化。spring.batch.jdbc.initialize-schema
never
9.4. 使用更高级别的数据库迁移工具
9.4.1. 在启动时执行 Flyway 数据库迁移
要在启动时自动运行 Flyway 数据库迁移,请将 添加到你的 Classpath 中。org.flywaydb:flyway-core
通常,迁移是以下格式的脚本(带有下划线分隔的版本,例如 '1' 或 '2_1')。
默认情况下,它们位于名为 的目录中,但您可以通过设置 来修改该位置。
这是一个或多个 or locations 的逗号分隔列表。
例如,以下配置将在默认 Classpath 位置和目录中搜索脚本:V<VERSION>__<NAME>.sql
<VERSION>
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}"
前面的配置不是使用 ,而是根据数据库的类型(例如MySQL)设置要使用的目录。
支持的数据库列表在 DatabaseDriver
中提供。db/migration
db/migration/mysql
迁移也可以用 Java 编写。
Flyway 将自动配置任何实现 .JavaMigration
FlywayProperties
提供了 Flyway 的大部分设置和一小部分附加属性,可用于禁用迁移或关闭位置检查。
如果需要对配置进行更多控制,请考虑注册 Bean。FlywayConfigurationCustomizer
Spring Boot 调用来执行数据库迁移。
如果您想要更多控制,请提供实现 FlywayMigrationStrategy
的 一个。Flyway.migrate()
@Bean
Flyway 支持 SQL 和 Java 回调。
要使用基于 SQL 的回调,请将回调脚本放在目录中。
要使用基于 Java 的回调,请创建一个或多个实现 .
任何此类 bean 都会自动注册到 。
可以使用 或 implementation 对它们进行排序。
也可以检测到实现已弃用接口的 Bean,但是它们不能与 Bean 一起使用。classpath:db/migration
Callback
Flyway
@Order
Ordered
FlywayCallback
Callback
默认情况下,Flyway 会在您的上下文中自动连接 () 并将其用于迁移。
如果您想使用不同的 ,您可以创建一个并将其标记为 。
如果您这样做并且需要两个数据源,请记住创建另一个数据源并将其标记为 .
或者,您可以通过在外部属性中设置来使用 Flyway 的原生。
设置 or 足以使 Flyway 使用自己的 .
如果尚未设置这三个属性中的任何一个,则将使用其等效属性的值。@Primary
DataSource
DataSource
@Bean
@FlywayDataSource
@Primary
DataSource
spring.flyway.[url,user,password]
spring.flyway.url
spring.flyway.user
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.4.2. 启动时执行 Liquibase 数据库迁移
要在启动时自动运行 Liquibase 数据库迁移,请将 添加到你的 Classpath 中。org.liquibase:liquibase-core
将 the 添加到 classpath 时,默认情况下,数据库迁移将在应用程序启动期间和测试运行之前运行。
可以使用 property 自定义此行为,在 和 配置中设置不同的值。
不能使用两种不同的方法来初始化数据库(例如,Liquibase 用于应用程序启动,JPA 用于测试运行)。 |
默认情况下,主更改日志是从 中读取的,但您可以通过设置 来更改位置。
除了 YAML,Liquibase 还支持 JSON、XML 和 SQL 更改日志格式。db/changelog/db.changelog-master.yaml
spring.liquibase.change-log
默认情况下,Liquibase 在你的上下文中自动连接 () 并将其用于迁移。
如果需要使用不同的 ,可以创建一个并将其标记为 。
如果您这样做并且需要两个数据源,请记住创建另一个数据源并将其标记为 .
或者,您可以通过设置外部属性来使用 Liquibase 的 native。
设置 or 足以使 Liquibase 使用其自己的 .
如果尚未设置这三个属性中的任何一个,则将使用其等效属性的值。@Primary
DataSource
DataSource
@Bean
@LiquibaseDataSource
@Primary
DataSource
spring.liquibase.[driver-class-name,url,user,password]
spring.liquibase.url
spring.liquibase.user
DataSource
spring.datasource
请参阅 LiquibaseProperties
以了解有关可用设置(如上下文、默认架构等)的详细信息。
9.4.3. 使用 Flyway 进行仅测试迁移
如果要创建填充测试数据库的 Flyway 迁移,请将它们放在 .
例如,名为 的 file 将在生产迁移后执行,并且仅在您运行测试时执行。
您可以使用此文件创建所需的测试数据。
此文件不会打包到您的 uber jar 或容器中。src/test/resources/db/migration
src/test/resources/db/migration/V9999__test-data.sql
9.4.4. 使用 Liquibase 进行仅测试迁移
如果要创建填充测试数据库的 Liquibase 迁移,则必须创建一个测试更改日志,其中还包括生产更改日志。
首先,您需要将 Liquibase 配置为在运行测试时使用不同的更改日志。
一种方法是创建一个 Spring Boot 配置文件并将 Liquibase 属性放入其中。
为此,请创建一个名为 的文件,并将以下属性放入其中:test
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
现在在 中创建 changelog 文件: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 或容器中。
它包括 production changelog,然后声明一个新的 changeset,其设置指定它在所有 production changeset 都运行之后运行。
例如,您现在可以使用 insert 变更集来插入数据,或者使用 sql 变更集直接执行 SQL。runOrder: last
最后要做的是配置 Spring Boot 以在运行测试时激活配置文件。
为此,您可以将 annotation 添加到带 Comments 的测试类中。test
@ActiveProfiles("test")
@SpringBootTest
9.5. 依赖于初始化的数据库
数据库初始化是在应用程序启动时作为应用程序上下文刷新的一部分执行的。 为了允许在启动期间访问已初始化的数据库,将自动检测充当数据库初始值设定项的 bean 和需要初始化该数据库的 bean。 其初始化依赖于已初始化数据库的 Bean 被配置为依赖于初始化它的 Bean。 如果在启动期间,应用程序尝试访问数据库,但尚未初始化数据库,则可以配置对 bean 的其他检测,这些 bean 初始化数据库并要求已初始化数据库。
9.5.1. 检测数据库初始化器
Spring Boot 将自动检测初始化 SQL 数据库的以下类型的 bean:
-
DataSourceScriptDatabaseInitializer
-
EntityManagerFactory
-
Flyway
-
FlywayMigrationInitializer
-
R2dbcScriptDatabaseInitializer
-
SpringLiquibase
如果你将第三方Starters用于数据库初始化库,它可能会提供一个检测器,以便也自动检测其他类型的 bean。
要检测其他 bean,请在 中注册 的实现。DatabaseInitializerDetector
META-INF/spring.factories
9.5.2. 检测依赖于数据库初始化的 bean
Spring Boot 将自动检测依赖于数据库初始化的以下类型的 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
@DependsOnDatabaseInitialization
10. 无SQL
Spring Boot 提供了许多支持 NoSQL 技术的Starters。 本节回答了将 NoSQL 与 Spring Boot 结合使用时出现的问题。
10.1. 用 Jedis 代替 Lettuce
默认情况下,Spring Boot starter () 使用 Lettuce。
您需要排除该依赖项并包含 Jedis 依赖项。
Spring Boot 管理这两个依赖项,因此您可以在不指定版本的情况下切换到 Jedis。spring-boot-starter-data-redis
以下示例展示了如何在 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 提供了许多 starter 来支持消息传递。 本节回答了在 Spring Boot 中使用消息传递时出现的问题。
11.1. 禁用事务处理的 JMS 会话
如果您的 JMS 代理不支持事务处理会话,则必须完全禁用对事务的支持。
如果您创建自己的 ,则无需执行任何操作,因为默认情况下它无法进行交易。
如果要使用 the 来重用 Spring Boot 的默认值,则可以禁用事务处理会话,如下所示:JmsListenerContainerFactory
DefaultJmsListenerContainerFactoryConfigurer
@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. 指定批处理数据源
默认情况下,批处理应用程序需要 来存储作业详细信息。
Spring Batch 默认需要一个 single。
要使它使用应用程序的 main 以外的其他 ,请声明一个 bean,并用 .
如果您这样做并且需要两个数据源,请记住标记另一个 。
要获得更大的控制权,请添加到您的一个类中或扩展 。
有关更多详细信息,请参见 @EnableBatchProcessing
和 DefaultBatchConfiguration
的 Javadoc。DataSource
DataSource
DataSource
DataSource
DataSource
@Bean
@BatchDataSource
@Primary
@EnableBatchProcessing
@Configuration
DefaultBatchConfiguration
有关 Spring Batch 的更多信息,请参阅 Spring Batch 项目页面。
12.2. 在启动时运行 Spring Batch 作业
通过添加到应用程序的 Classpath 来启用 Spring Batch 自动配置。spring-boot-starter-batch
如果在应用程序上下文中找到单个,则在启动时执行该操作(有关详细信息,请参见JobLauncherApplicationRunner
)。
如果找到多个 bean,则必须使用 指定应执行的作业。Job
Job
spring.batch.job.name
要禁用在应用程序上下文中运行 found,请将 设置为 .Job
spring.batch.job.enabled
false
有关更多详细信息,请参阅 BatchAutoConfiguration 。
12.3. 从命令行运行
Spring Boot 将任何以 开头的命令行参数转换为要添加到 、 参见访问命令行属性的属性。
这不应用于将参数传递给批处理作业。
要在命令行上指定批处理参数,请使用常规格式(即 without ),如以下示例所示:--
Environment
--
$ java -jar myapp.jar someParameter=someValue anotherParameter=anotherValue
如果您在命令行上指定 the 的属性,则作业将忽略该属性。
请考虑以下命令:Environment
$ java -jar myapp.jar --server.port=7070 someParameter=someValue
这仅向批处理作业提供一个参数:.someParameter=someValue
12.4. 重启已停止或失败的作业
要重新启动 failed ,必须在命令行上重新指定所有参数(标识和非标识)。
非标识参数不会从上一次执行中复制。
这允许修改或删除它们。Job
当您使用 custom 时,必须收集由增量程序管理的所有参数才能重新启动失败的执行。JobParametersIncrementer |
12.5. 存储 Job 仓库
Spring Batch 需要存储库的数据存储。
如果使用 Spring Boot,则必须使用实际的数据库。
请注意,它可以是内存数据库,请参阅配置 Job Repository。Job
13. 执行器
Spring Boot 包括 Spring Boot Actuator。 本节回答了使用它时经常出现的问题。
13.1. 更改 Actuator 端点的 HTTP 端口或地址
在独立应用程序中,Actuator HTTP 端口默认与主 HTTP 端口相同。
要使应用程序侦听其他端口,请设置 external 属性: 。
要侦听完全不同的网络地址(例如,当您有一个用于管理的内部网络和一个用于用户应用程序的外部网络时),您还可以设置为服务器能够绑定到的有效 IP 地址。management.server.port
management.server.address
有关更多详细信息,请参阅 ManagementServerProperties
源代码和“生产就绪功能”部分中的“actuator.html”。
13.2. 自定义 'whitelabel' 错误页面
Spring Boot 会安装一个“whitelabel”错误页面,如果您遇到服务器错误,您会在浏览器客户端中看到该页面(使用 JSON 和其他媒体类型的机器客户端应该看到带有正确错误代码的合理响应)。
设置为关闭默认错误页面。
这样做将恢复您正在使用的 Servlet 容器的默认值。
请注意, Spring Boot 仍然尝试解决错误视图,因此您可能应该添加自己的错误页面,而不是完全禁用它。server.error.whitelabel.enabled=false |
用您自己的页面覆盖错误页面取决于您使用的模板技术。
例如,如果使用 Thymeleaf,则可以添加模板。
如果您使用 FreeMarker,则可以添加模板。
通常,您需要使用 name 解析的 a 或处理路径的 a。
除非你替换了一些默认配置,否则你应该在你的 中找到 a,所以 a named 将是实现此目的的一种方式。
有关更多选项,请参阅 ErrorMvcAutoConfiguration
。error.html
error.ftlh
View
error
@Controller
/error
BeanNameViewResolver
ApplicationContext
@Bean
error
有关如何在 Servlet 容器中注册处理程序的详细信息,另请参阅“错误处理”部分。
13.3. 自定义 Sanitization
要控制清理,请定义一个 bean。
调用函数时使用的 提供对键和值以及它们的来源的访问。
例如,这允许您清理来自特定属性源的每个值。
每个 Cookie 都会按顺序调用,直到函数更改可清理数据的值。SanitizingFunction
SanitizableData
PropertySource
SanitizingFunction
13.4. 将健康指标映射到 Micrometer 指标
Spring Boot 运行状况指示器返回一个类型来指示整体系统运行状况。
如果要监控特定应用程序的运行状况级别或发出警报,可以使用 Micrometer 将这些状态导出为指标。
默认情况下,Spring Boot 使用状态代码 “UP”、“DOWN”、“OUT_OF_SERVICE” 和 “UNKNOWN”。
要导出这些值,您需要将这些状态转换为一组数字,以便它们可以与 Micrometer 一起使用。Status
Gauge
以下示例显示了编写此类 exporter 的一种方法:
@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 安全配置
如果在应用程序中定义 with bean,则会关闭 Spring Boot 中的默认 webapp 安全设置。@Configuration
SecurityFilterChain
14.2. 更改 UserDetailsService 并添加用户帐户
如果您提供 类型 、 、 或 ,则默认值为 not created。
这意味着您拥有可用的 Spring Security 的完整功能集(例如各种身份验证选项)。@Bean
AuthenticationManager
AuthenticationProvider
UserDetailsService
@Bean
InMemoryUserDetailsManager
添加用户帐户的最简单方法是提供您自己的 bean。UserDetailsService
14.3. 在 Proxy Server 后面运行时启用 HTTPS
确保所有主要终端节点仅通过 HTTPS 可用,对于任何应用程序来说都是一项重要的苦差事。
如果你使用 Tomcat 作为 servlet 容器,那么 Spring Boot 如果检测到某些环境设置,它会自动添加 Tomcat 自己的容器,你应该能够依靠 来报告它是否安全(甚至在处理实际 SSL 终止的代理服务器的下游)。
标准行为由某些请求标头 ( 和 )的存在与否决定,这些请求标头的名称是约定俗成的,因此它应该适用于大多数前端代理。
您可以通过向 中添加一些条目来打开阀门,如以下示例所示:RemoteIpValve
HttpServletRequest
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"
(这些属性中的任何一个的存在都会打开阀门。
或者,您可以通过自定义 using a bean.)RemoteIpValve
TomcatServletWebServerFactory
WebServerFactoryCustomizer
要将 Spring Security 配置为要求所有(或部分)请求都使用安全通道,请考虑添加您自己的 Bean,该 bean 添加以下配置:SecurityFilterChain
HttpSecurity
@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 { requests -> requests.anyRequest().requiresSecure() }
return http.build()
}
}
15. 热插拔
Spring Boot 支持热插拔。 本节回答了有关其工作原理的问题。
15.1. 重新加载静态内容
热重载有多种选择。
推荐的方法是使用spring-boot-devtools
,因为它提供了额外的开发时功能,例如支持快速应用程序重启和 LiveReload 以及合理的开发时配置(例如模板缓存)。
Devtools 通过监视 Classpath 的更改来工作。
这意味着必须 “构建” 静态资源更改才能使更改生效。
默认情况下,在 Eclipse 中,当您保存更改时,这会自动发生。
在 IntelliJ IDEA 中,Make Project 命令会触发必要的构建。
由于默认的重启排除项,对静态资源的更改不会触发应用程序的重启。
但是,它们确实会触发实时重新加载。
或者,在 IDE 中运行(尤其是在调试时)是进行开发的好方法(所有现代 IDE 都允许重新加载静态资源,通常还允许热交换 Java 类更改)。
最后,可以配置 Maven 和 Gradle 插件(参见属性)以支持从命令行运行,并直接从源重新加载静态文件。
如果您正在使用更高级别的工具编写该代码,则可以将其与外部 css/js 编译器进程一起使用。addResources
15.2. 在不重启容器的情况下重新加载模板
Spring Boot 支持的大多数模板技术都包含一个用于禁用缓存的配置选项(本文档稍后将介绍)。
如果您使用该模块,则会在开发时自动为您配置这些属性。spring-boot-devtools
15.2.1. Thymeleaf 模板
如果使用 Thymeleaf,请设置为 。
有关其他 Thymeleaf 自定义选项,请参见ThymeleafAutoConfiguration
。spring.thymeleaf.cache
false
15.2.2. FreeMarker 模板
如果使用 FreeMarker,请设置为 .
有关其他 FreeMarker 自定义选项,请参阅 FreeMarkerAutoConfiguration
。spring.freemarker.cache
false
15.2.3. Groovy 模板
如果使用 Groovy 模板,请设置为 。
有关其他 Groovy 自定义选项,请参见GroovyTemplateAutoConfiguration
。spring.groovy.template.cache
false
15.3. 应用程序快速重启
该模块包括对应用程序自动重启的支持。
虽然不如 JRebel 等技术快,但它通常比“冷启动”快得多。
在研究本文档后面讨论的一些更复杂的重新加载选项之前,您可能应该先尝试一下。spring-boot-devtools
有关更多详细信息,请参阅 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 的全面集成,这也可以在使用 slice 和 .@WebMvcTest
MockMvc
有关 Spring Security 的测试支持的更多详细信息,请参阅 Spring Security 的参考文档。
16.2. 用于包含在 slice 测试中的结构类@Configuration
切片测试的工作原理是将 Spring Framework 的组件扫描限制为基于其类型的一组有限的组件。
对于不是通过组件扫描创建的任何 bean,例如,使用 Comments 创建的 bean,切片测试将无法在应用程序上下文中包含/排除它们。
请考虑以下示例:@Bean
@Configuration(proxyBeanMethods = false)
public class MyConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());
return http.build();
}
@Bean
@ConfigurationProperties("app.datasource.second")
public BasicDataSource secondDataSource() {
return DataSourceBuilder.create().type(BasicDataSource.class).build();
}
}
对于具有上述类的应用程序,您可能希望在应用程序上下文中具有 Bean,以便您可以测试控制器端点是否得到正确保护。
但是,@WebMvcTest 的组件扫描筛选条件不会选取它,因为它与筛选条件指定的任何类型都不匹配。
您可以通过使用 .
这将加载所有 bean,包括 bean 中,这在测试 web 层时不是必需的。
将 configuration 类拆分为两个将允许仅导入 security configuration。@WebMvcTest
@Configuration
SecurityFilterChain
MyConfiguration
@Import(MyConfiguration.class)
MyConfiguration
BasicDataSource
@Configuration(proxyBeanMethods = false)
public class MySecurityConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((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 包含在 slice 测试中时,拥有单个配置类可能效率低下。 相反,将应用程序的配置构建为具有特定域的 bean 的多个细粒度类可以允许仅针对特定切片测试导入它们。
17. 构建
Spring Boot 包括适用于 Maven 和 Gradle 的构建插件。 本节回答了有关这些插件的常见问题。
17.1. 生成构建信息
Maven 插件和 Gradle 插件都允许生成包含项目坐标、名称和版本的构建信息。
还可以将插件配置为通过配置添加其他属性。
当存在这样的文件时, Spring Boot 会自动配置一个 bean。BuildProperties
要使用 Maven 生成构建信息,请为目标添加执行,如以下示例所示:build-info
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.1.12</version>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
有关更多详细信息,请参阅 Spring Boot Maven Plugin 文档。 |
以下示例对 Gradle 执行相同的操作:
springBoot {
buildInfo()
}
有关更多详细信息,请参阅 Spring Boot Gradle Plugin 文档。 |
17.2. 生成 Git 信息
Maven 和 Gradle 都允许生成一个文件,其中包含有关构建项目时源代码存储库状态的信息。git.properties
git
对于 Maven 用户,POM 包括一个预配置的插件,用于生成文件。
要使用它,请将 Git 提交 ID 插件
的以下声明添加到您的 POM 中:spring-boot-starter-parent
git.properties
<build>
<plugins>
<plugin>
<groupId>io.github.git-commit-id</groupId>
<artifactId>git-commit-id-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Gradle 用户可以使用 gradle-git-properties
插件获得相同的结果,如下例所示:
plugins {
id "com.gorylenko.gradle-git-properties" version "2.4.1"
}
Maven 和 Gradle 插件都允许配置 其中包含的属性。git.properties
提交的时间应与以下格式匹配:.
这是上面列出的两个插件的默认格式。
使用此格式可以将时间解析为 a,其格式在序列化为 JSON 时由 Jackson 的日期序列化配置设置控制。git.properties yyyy-MM-dd’T’HH:mm:ssZ Date |
17.3. 自定义依赖项版本
POM 管理常见依赖项的版本。
适用于 Maven 和 Gradle 的 Spring Boot 插件允许使用 build 属性自定义这些托管依赖项版本。spring-boot-dependencies
每个 Spring Boot 版本都是针对这组特定的第三方依赖项进行设计和测试的。 覆盖版本可能会导致兼容性问题。 |
要使用 Maven 覆盖依赖项版本,请参阅 Maven 插件文档的此部分。
如需覆盖 Gradle 中的依赖项版本,请参阅 Gradle 插件文档的此部分。
17.4. 使用 Maven 创建可执行 JAR
这可用于创建可执行的 “fat” JAR。
如果你使用 POM,你可以声明插件,并且你的 jar 被重新打包,如下所示:spring-boot-maven-plugin
spring-boot-starter-parent
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
如果您不使用父 POM,您仍然可以使用该插件。
但是,您必须额外添加一个部分,如下所示:<executions>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.1.12</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 格式将应用程序类打包在 .
这意味着当可执行 jar 用作依赖项时,无法找到它们。BOOT-INF/classes
要生成两个工件,一个可用作依赖项,另一个可用作可执行文件,必须指定分类器。 此分类器应用于可执行存档的名称,将默认存档用作依赖项。
要在 Maven 中配置 的分类器,您可以使用以下配置:exec
<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 支持,它假定 the 始终可以直接作为文件使用。jruby-complete.jar
要处理任何有问题的库,您可以标记特定的嵌套 jar 应在可执行 jar 首次运行时自动解压缩。
此类嵌套 jar 将写入由 system 属性标识的临时目录下。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. 创建带有 Exclusions 的不可执行 JAR
通常,如果您将可执行文件和不可执行 jar 作为两个单独的构建产品,则可执行版本具有库 jar 中不需要的其他配置文件。
例如,配置文件可能从不可执行的 JAR 中排除。application.yaml
在 Maven 中,可执行 jar 必须是主对象,您可以为库添加分类 jar,如下所示:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>lib</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>lib</classifier>
<excludes>
<exclude>application.yaml</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
17.8. 远程调试使用 Maven 启动的 Spring Boot 应用程序
要将远程调试器附加到使用 Maven 启动的 Spring Boot 应用程序,可以使用 maven 插件的属性。jvmArguments
有关更多详细信息,请参阅此示例。
17.9. 从 Ant 构建可执行档案,而不使用 spring-boot-antlib
要使用 Ant 进行构建,您需要获取依赖项、编译,然后创建 jar 或 war 存档。
要使其可执行,您可以使用该模块,也可以按照以下说明进行操作:spring-boot-antlib
-
如果要构建 jar,请将应用程序的类和资源打包到嵌套目录中。 如果要构建 war,请像往常一样将应用程序的类打包到嵌套目录中。
BOOT-INF/classes
WEB-INF/classes
-
在 jar 或 war 的嵌套目录中添加运行时依赖项。 切记不要压缩存档中的条目。
BOOT-INF/lib
WEB-INF/lib
-
在 jar 或 war 的嵌套目录中添加(嵌入式容器)依赖项。 切记不要压缩存档中的条目。
provided
BOOT-INF/lib
WEB-INF/lib-provided
-
在存档的根目录中添加类(以便 可用)。
spring-boot-loader
Main-Class
-
使用适当的Starters(例如用于 jar 文件)作为清单中的属性,并指定它需要作为清单条目的其他属性 — 主要是通过设置属性。
JarLauncher
Main-Class
Start-Class
以下示例演示如何使用 Ant 构建可执行存档:
<target name="build" depends="compile">
<jar destfile="target/${ant.project.name}-${spring-boot.version}.jar" compress="false">
<mappedresources>
<fileset dir="target/classes" />
<globmapper from="*" to="BOOT-INF/classes/*"/>
</mappedresources>
<mappedresources>
<fileset dir="src/main/resources" erroronmissingdir="false"/>
<globmapper from="*" to="BOOT-INF/classes/*"/>
</mappedresources>
<mappedresources>
<fileset dir="${lib.dir}/runtime" />
<globmapper from="*" to="BOOT-INF/lib/*"/>
</mappedresources>
<zipfileset src="${lib.dir}/loader/spring-boot-loader-jar-${spring-boot.version}.jar" />
<manifest>
<attribute name="Main-Class" value="org.springframework.boot.loader.JarLauncher" />
<attribute name="Start-Class" value="${start-class}" />
</manifest>
</jar>
</target>
18. 提前处理
当人们使用 Spring Boot 应用程序的预先处理时,经常会出现许多问题。 本节将解决这些问题。
18.1. 条件
如果希望 bean 是基于预先优化的应用程序中的条件创建的,则必须在构建应用程序时设置环境。 在构建时提前处理时创建的 bean 始终在运行应用程序时创建,并且无法关闭。 为此,您可以设置构建应用程序时应使用的配置文件。
对于 Maven,这通过设置执行的配置来实现:profiles
spring-boot-maven-plugin:process-aot
<profile>
<id>native</id>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>process-aot</id>
<configuration>
<profiles>profile-a,profile-b</profiles>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
对于 Gradle,您需要配置任务:ProcessAot
tasks.withType(org.springframework.boot.gradle.tasks.aot.ProcessAot).configureEach {
args('--spring.profiles.active=profile-a,profile-b')
}
在运行预先优化的应用程序时,仅支持更改不影响条件的配置属性的配置文件,而不受限制。
19. 传统部署
Spring Boot 支持传统部署以及更现代的部署形式。 本节解答了有关传统部署的常见问题。
19.1. 创建一个可部署的 war 文件
因为 Spring WebFlux 并不严格依赖于 servlet API,而且应用程序默认部署在嵌入式 Reactor Netty 服务器上,所以 WebFlux 应用程序不支持 War 部署。 |
生成可部署的 war 文件的第一步是提供一个子类并覆盖其方法。
这样做利用了 Spring Framework 的 servlet 3.0 支持,并允许您在 servlet 容器启动应用程序时对其进行配置。
通常,您应该更新应用程序的 main 类以扩展 ,如以下示例所示:SpringBootServletInitializer
configure
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 和(为你配置 Maven 的 war 插件),你需要做的就是修改以将打包更改为 war,如下所示:spring-boot-starter-parent
pom.xml
<packaging>war</packaging>
如果使用 Gradle,则需要修改才能将 war 插件应用到项目中,如下所示:build.gradle
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 的配置。
除其他限制外,依赖项不在测试 Classpath 上,因此任何基于 Web 的集成测试都会失败。compileOnly compileOnly |
如果使用 Spring Boot 构建工具,则将嵌入式 servlet 容器依赖项标记为已提供将生成一个可执行的 war 文件,其中提供的依赖项打包在一个目录中。
这意味着,除了可部署到 servlet 容器之外,您还可以在命令行上使用 来运行应用程序。lib-provided
java -jar
19.2. 将现有应用程序转换为 Spring Boot
要将现有的非 Web Spring 应用程序转换为 Spring Boot 应用程序,请替换创建 your 的代码,并将其替换为对 或 的调用。
Spring MVC Web 应用程序通常适合先创建一个可部署的 war 应用程序,然后再将其迁移到可执行的 war 或 jar 中。
请参阅有关将 jar 转换为 war 的入门指南。ApplicationContext
SpringApplication
SpringApplicationBuilder
要通过扩展(例如,在名为 的类中)并添加 Spring Boot 注释来创建可部署的 war,请使用类似于以下示例中所示的代码:SpringBootServletInitializer
Application
@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
}
}
请记住,无论你放入什么 都只是一个 弹簧 .
通常,任何已经有效的内容都应该在这里工作。
可能有一些 bean 你可以稍后删除,并让 Spring Boot 为它们提供自己的默认值,但是在你需要这样做之前,应该可以让一些东西工作。sources
ApplicationContext
静态资源可以移动到 Classpath 根目录中(或 or 或 )。
这同样适用于(Spring Boot 在 Classpath 的根目录中自动检测到)。/public
/static
/resources
/META-INF/resources
messages.properties
Spring 和 Spring Security 的原版用法应该不需要进一步的更改。
如果您的应用程序中还有其他功能(例如,使用其他 servlet 或过滤器),则可能需要通过替换 中的这些元素来向上下文添加一些配置,如下所示:DispatcherServlet
Application
web.xml
-
A 类型的 or 将该 Bean 安装在容器中,就像它是 a 和 一样。
@Bean
Servlet
ServletRegistrationBean
<servlet/>
<servlet-mapping/>
web.xml
-
类型 或 行为相似的 A (如 a 和 )。
@Bean
Filter
FilterRegistrationBean
<filter/>
<filter-mapping/>
-
可以通过 中的 . 或者,可以在几行中重新创建已大量使用 Comments 配置的情况作为定义。
ApplicationContext
@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
|
应用程序可以分为多个类别:
-
没有 .
web.xml
-
带有 .
web.xml
-
具有上下文层次结构的应用程序。
-
没有上下文层次结构的应用程序。
所有这些都应该适合翻译,但每个可能需要略有不同的技术。
如果 Servlet 3.0+ 应用程序已经使用 Spring Servlet 3.0+ 初始化器支持类,那么它们可能很容易进行翻译。
通常,现有代码中的所有代码都可以移动到 .
如果您现有的应用程序有多个(例如,如果它使用 ),则您或许能够将所有上下文源合并到一个 .
您可能会遇到的主要复杂情况是,如果合并不起作用,并且您需要维护上下文层次结构。
有关示例,请参阅 building a hierarchy 上的条目。
通常需要分解包含 Web 特定功能的现有父上下文,以便所有组件都位于子上下文中。WebApplicationInitializer
SpringBootServletInitializer
ApplicationContext
AbstractDispatcherServletInitializer
SpringApplication
ServletContextAware
尚不是 Spring 应用程序的应用程序可能可转换为 Spring Boot 应用程序,前面提到的指南可能会有所帮助。
但是,您可能还会遇到问题。
在这种情况下,我们建议在 Stack Overflow 上使用 spring-boot
标签提问。
19.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>
20. Docker 撰写
本节包括与 Spring Boot 中的 Docker Compose 支持相关的主题。
20.1. 自定义 JDBC URL
与 Docker Compose 一起使用时,JDBC URL 的参数
可以通过将标签应用于
服务。例如:JdbcConnectionDetails
org.springframework.boot.jdbc.parameters
services:
postgres:
image: 'postgres:15.3'
environment:
- 'POSTGRES_USER=myuser'
- 'POSTGRES_PASSWORD=secret'
- 'POSTGRES_DB=mydb'
ports:
- '5432:5432'
labels:
org.springframework.boot.jdbc.parameters: 'ssl=true&sslmode=require'
有了这个 Docker Compose 文件,使用的 JDBC URL 是 .jdbc:postgresql://127.0.0.1:5432/mydb?ssl=true&sslmode=require
20.2. 在多个应用程序之间共享服务
如果要在多个应用程序之间共享服务,请在其中一个应用程序中创建文件,然后在其他应用程序中使用 configuration 属性来引用该文件。
您还应将其设置为 ,因为它默认为 ,并且停止一个应用程序也会关闭其他仍在运行的应用程序的共享服务。
将其设置为 不会在应用程序停止时停止共享服务,但需要注意的是,如果您关闭所有应用程序,服务将保持运行。
您可以通过在包含该文件的目录中的命令行上运行来手动停止服务。compose.yaml
spring.docker.compose.file
compose.yaml
spring.docker.compose.lifecycle-management
start-only
start-and-stop
start-only
docker compose stop
compose.yaml