返回

Spring Boot“操作方法”指南

发布时间:2023-11-30 09:14:23 230

本节提供了使用 Spring Boot 时经常出现的一些常见“我该怎么做……”问题的答案。它的覆盖范围并不详尽,但确实涵盖了很多。

如果您有我们未在此处介绍的特定问题,您可能需要检查stackoverflow.com以查看是否有人已经提供了答案。这也是提出新问题的好地方(请使用​​spring-boot​​标签)。

我们也非常乐意扩展本节。如果您想添加“操作方法”,请向我们发送拉取请求。

Spring Boot“操作方法”指南_配置文件

1. Spring Boot 应用程序

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

1.1创建您的故障分析器

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

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

​FailureAnalyzer​​实现必须在​​META-INF/spring.factories​​. 以下示例寄存器​​ProjectConstraintViolationFailureAnalyzer​​:

org.springframework.boot.diagnostics.FailureAnalyzer=\
com.example.ProjectConstraintViolationFailureAnalyzer

1.2. 自动配置故障排除

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

​ConditionEvaluationReport​​在任何 Spring Boot 中都有一个非常有用的可用​​ApplicationContext​​。如果启用​​DEBUG​​日志输出,您可以看到它。如果您使用​​spring-boot-actuator​​(请参阅执行器章节),还有一个​​conditions​​以 JSON 格式呈现报告的端点。使用该端点来调试应用程序,并查看 Spring Boot 在运行时添加了哪些功能(哪些还没有添加)。

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

  • 查找调用的类*AutoConfiguration并阅读它们的来源。请特别注意@Conditional*注释以了解它们启用了哪些功能以及何时启用。添加--debug到命令行或系统属性-Ddebug以在控制台上获取在您的应用程序中做出的所有自动配置决策的日志。在启用了执行器的正在运行的应用程序中,查看conditions端点(/actuator/conditions或 JMX 等效项)以获取相同的信息。
  • 查找类@ConfigurationProperties(例如ServerProperties)并从那里读取可用的外部配置选项。@ConfigurationProperties注释有一个name作为外部属性前缀的属性。因此,ServerPropertieshasprefix="server"及其配置属性是server.portserver.address和其他。在启用执行器的运行应用程序中,查看configprops端点。
  • 寻找该bind方法的用途,以轻松的方式Binder显式地将配置值拉出。Environment它通常与前缀一起使用。
  • 查找@Value直接绑定到Environment.
  • 查找@ConditionalOnExpression响应 SpEL 表达式打开和关闭功能的注释,通常使用从Environment.

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

A ​​SpringApplication​​has ​​ApplicationListeners​​and ​​ApplicationContextInitializers​​that 用于将自定义应用到上下文或环境。Spring Boot 从​​META-INF/spring.factories​​. 注册附加自定义的方法不止一种:

  • 以编程方式,每个应用程序,通过在运行之前调用addListenersaddInitializers方法。SpringApplication
  • 声明式地,每个应用程序,通过设置context.initializer.classesorcontext.listener.classes属性。
  • 声明式地,对于所有应用程序,通过添加META-INF/spring.factories并打包应用程序都用作库的 jar 文件。

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

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

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

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

public class MyEnvironmentPostProcessor implements EnvironmentPostProcessor {

private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();

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

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

}

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

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

1.5创建非 Web 应用程序

并非所有 Spring 应用程序都必须是 Web 应用程序(或 Web 服务)。如果你想在一个​​main​​方法中执行一些代码,同时还要引导一个 Spring 应用程序来设置要使用的基础设施,你可以使用​​SpringApplication​​Spring Boot 的特性。A​​SpringApplication​​改变它的​​ApplicationContext​​类,这取决于它是否认为它需要一个 Web 应用程序。您可以做的第一件事就是将与服务器相关的依赖项(例如 servlet API)从类路径中移除。如果您不能这样做(例如,您从同一代码库运行两个应用程序),那么您可以显式调用​​setWebApplicationType(WebApplicationType.NONE)​​您的​​SpringApplication​​实例或设置​​applicationContextClass​​属性(通过 Java API 或使用外部属性)。您希望作为业务逻辑运行的应用程序代码可以实现为​​CommandLineRunner​​​​@Bean​​并作为定义放入上下文中。

2. 属性和配置

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

2.1在构建时自动展开属性

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

2.1.1使用 Maven 自动扩展属性

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

特性

app.encoding=@project.build.sourceEncoding@
app.java.version=@java.version@

如果您不使用起始父级,则需要在​​​您的元素中包含以下元素​​pom.xml​​:



src/main/resources
true

您还需要在其中包含以下元素​​:


org.apache.maven.plugins
maven-resources-plugin
2.7


@

false

2.1.2. 使用 Gradle 自动扩展属性

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

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

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

特性

app.name=${name}
app.description=${description}

2.2. 外化 SpringApplication 的配置

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

特性

spring.main.web-application-type=none
spring.main.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);
}

}

或者到​​sources(…)​​a 的方法​​SpringApplicationBuilder​​:

public class MyApplication {

public static void main(String[] args) {
new SpringApplicationBuilder()
.bannerMode(Banner.Mode.OFF)
.sources(MyApplication.class)
.run(args);
}

}

给定上面的例子,如果我们有以下配置:

特性

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

实际的应用程序将显示横幅(被配置覆盖)并使用三个来源作为​​ApplicationContext​​. 应用程序来源是:

  1. ​MyApplication​​(来自代码)
  2. ​MyDatabaseConfig​​(来自外部配置)
  3. ​MyJmsConfig​​(来自外部配置)

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

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

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

  • ​spring.config.name​​( SPRING_CONFIG_NAME):默认application为文件名的根。
  • ​spring.config.location​​( SPRING_CONFIG_LOCATION):要加载的文件(例如类路径资源或 URL)。为该文档设置了一个单独的Environment属性源,它可以被系统属性、环境变量或命令行覆盖。

无论您在环境中设置什么,Spring Boot 总是​​application.properties​​按上述方式加载。默认情况下,如果使用 YAML,则扩展名为 '.yml' 的文件也会添加到列表中。

2.4. 使用“短”命令行参数

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

特性

server.port=${port:8080}

2.5. 将 YAML 用于外部属性

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

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

创建一个名为的文件​​application.yml​​并将其放在类路径的根目录中。然后添加​​snakeyaml​​到您的依赖项(Maven 坐标​​org.yaml:snakeyaml​​,如果您使用,则已包含​​spring-boot-starter​​)。YAML 文件被解析为 Java ​​Map​(如 JSON 对象),Spring Boot 将映射展平,使其具有一层深度并具有以句点分隔的键,正如许多人习惯于使用​​Properties​​Java 中的文件一样。

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

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

有关 YAML 的更多信息,请参阅“ Spring Boot 功能”部分中的“ features.html ”。

2.6. 设置活动弹簧配置文件

Spring​​Environment​​对此有一个 API,但您通常会设置系统属性 ( ​​spring.profiles.active​​) 或操作系统环境变量 ( ​​SPRING_PROFILES_ACTIVE​​)。此外,您可以使用参数启动应用程序​​-D​​(请记住将其放在主类或 jar 存档之前),如下所示:

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

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

特性

spring.profiles.active=production

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

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

2.7. 设置默认配置文件名称

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

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

特性

spring.profiles.default=dev

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

2.8. 根据环境更改配置

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

如果文档包含​​spring.config.activate.on-profile​​键,则将配置文件值(以逗号分隔的配置文件列表或配置文件表达式)输入 Spring​​Environment.acceptsProfiles()​​方法。如果配置文件表达式匹配,则该文档将包含在最终合并中(否则不包含),如以下示例所示:

特性

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

在前面的示例中,默认端口为 9000。但是,如果名为“开发”的 Spring 配置文件处于活动状态,则端口为 9001。如果“生产”处于活动状态,则端口为 0。

2.9发现外部属性的内置选项

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

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

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

3. 嵌入式 Web 服务器

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

3.1使用另一个 Web 服务器

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

  • 对于 servlet 堆栈应用程序,通过spring-boot-starter-webinclude 包含 Tomcat spring-boot-starter-tomcat,但您可以使用spring-boot-starter-jettyspring-boot-starter-undertow代替。
  • 对于反应式堆栈应用程序,通过spring-boot-starter-webfluxinclude 包含 Reactor Netty spring-boot-starter-reactor-netty,但您可以使用spring-boot-starter-tomcat,spring-boot-starter-jettyspring-boot-starter-undertow代替。

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

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


3.1.0


org.springframework.boot
spring-boot-starter-web



org.springframework.boot
spring-boot-starter-tomcat





org.springframework.boot
spring-boot-starter-jetty

如果您希望使用支持 servlet 4.0 的 Jetty 10,您可以按照以下示例进行操作:


10.0.8


org.springframework.boot
spring-boot-starter-web



org.springframework.boot
spring-boot-starter-tomcat





org.springframework.boot
spring-boot-starter-jetty



org.eclipse.jetty.websocket
websocket-server


org.eclipse.jetty.websocket
javax-websocket-server-impl


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

以下 Gradle 示例配置了必要的依赖项和模块替换,以使用 Undertow 代替 Spring WebFlux 的 Reactor Netty:

dependencies {
implementation "org.springframework.boot:spring-boot-starter-undertow"
implementation "org.springframework.boot:spring-boot-starter-webflux"
modules {
module("org.springframework.boot:spring-boot-starter-reactor-netty") {
replacedBy("org.springframework.boot:spring-boot-starter-undertow", "Use Undertow instead of Reactor Netty")
}
}
}

3.2. 禁用 Web 服务器

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

特性

spring.main.web-application-type=none

3.3. 更改 HTTP 端口

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

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

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

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

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

3.5. 在运行时发现 HTTP 端口

您可以从日志输出或​​WebServerApplicationContext​​通过其​​WebServer​​. 获得它并确保它已被初始化的最佳方法是添加一个​​@Bean​​类型​​ApplicationListener​并在发布时将容器从事件中拉出。

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

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

@LocalServerPort
int port;

// ...

}

3.6. 启用 HTTP 响应压缩

Jetty、Tomcat、Reactor Netty 和 Undertow 支持 HTTP 响应压缩。可以在 中启用​​application.properties​​,如下:

特性

server.compression.enabled=true

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

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

  • ​text/html​
  • ​text/xml​
  • ​text/plain​
  • ​text/css​
  • ​text/javascript​
  • ​application/javascript​
  • ​application/json​
  • ​application/xml​

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

3.7. 配置 SSL

SSL 可以通过设置各种​​server.ssl.*​​属性以声明方式配置,通常在​​application.properties​​或中​​application.yml​​。以下示例显示了使用 Java KeyStore 文件设置 SSL 属性:

特性

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

以下示例显示了使用 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

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

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

3.8. 配置 HTTP/2

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

3.8.1. HTTP/2 与 Tomcat

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

库目录必须对 JVM 库路径可用(如果还没有的话)。您可以使用 JVM 参数来执行此操作,例如​​-Djava.library.path=/usr/local/opt/tomcat-native/lib​​. 更多信息请参阅Tomcat 官方文档。

在启用了 HTTP/2 和 SSL 但没有本机支持的情况下在 JDK 8 上启动 Tomcat 9.0.x 会记录以下错误:

错误 8787 --- [main] oacoyote.http11.Http11NioProtocol : [h2] 的升级处理程序 [org.apache.coyote.http2.Http2Protocol] 仅支持通过 ALPN 升级,但已为 ["https-jsse-nio -8443"] 不支持 ALPN 的连接器。

这个错误不是致命的,应用程序仍然以 HTTP/1.1 SSL 支持启动。

3.8.2. HTTP/2 与码头

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

  • ​org.eclipse.jetty:jetty-alpn-java-server​​适用于在 JDK9+ 上运行的应用程序
  • ​org.eclipse.jetty:jetty-alpn-openjdk8-server​​适用于在 JDK8u252+ 上运行的应用程序
  • ​org.eclipse.jetty:jetty-alpn-conscrypt-server​​和没有 JDK 要求的Conscrypt 库

3.8.3. 使用 Reactor Netty 的 HTTP/2

默认情况下​​spring-boot-webflux-starter​​使用 Reactor Netty 作为服务器。Reactor Netty 支持​​h2c​​使用 JDK 8 或更高版本,无需额外依赖。Reactor Netty 支持​​h2​​在 JDK 9 或更高版本中使用 JDK 支持。对于 JDK 8 环境,或为了获得最佳运行时性能,该服务器还支持​​h2​​原生库。要启用它,您的应用程序需要有一个额外的依赖项。

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

3.8.4. HTTP/2 与 Undertow

从 Undertow 1.4.0+ 开始, JDK 8 支持​​h2​​和​​h2c​​,没有任何额外的依赖项。

3.9. 配置 Web 服务器

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

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

以下示例适用于带有​​spring-boot-starter-web​​(servlet 堆栈)的 Tomcat:

@Component
public class MyTomcatWebServerCustomizer implements WebServerFactoryCustomizer {

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

}

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

此外,Spring Boot 还提供:

服务器

Servlet 堆栈

反应堆

雄猫

​TomcatServletWebServerFactory​

​TomcatReactiveWebServerFactory​

码头

​JettyServletWebServerFactory​

​JettyReactiveWebServerFactory​

暗流

​UndertowServletWebServerFactory​

​UndertowReactiveWebServerFactory​

反应堆

不适用

​NettyReactiveWebServerFactory​

作为最后的手段,您还可以声明的​​WebServerFactory​​bean,它将覆盖 Spring Boot 提供的 bean。当您这样做时,自动配置的定制器仍会应用于您的自定义工厂,因此请谨慎使用该选项。

3.10向应用程序添加 Servlet、过滤器或侦听器

在 servlet 堆栈应用程序中,即使用​​spring-boot-starter-web​​,有两种方法可以将​​Servlet​​、​​Filter​​、​​ServletContextListener​​和 Servlet API 支持的其他侦听器添加到您的应用程序:

  • 使用 Spring Bean 添加 Servlet、过滤器或侦听器
  • 使用类路径扫描添加 Servlet、过滤器和侦听器

3.10.1使用 Spring Bean 添加 Servlet、过滤器或侦听器

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

在过滤器和 servlet 的情况下,您还可以添加映射和初始化参数,方法是添加 a​​FilterRegistrationBean​​或 a​​ServletRegistrationBean​​来代替或添加到底层组件。

像任何其他 Spring bean 一样,您可以定义 servlet 过滤器 bean 的顺序;请务必检查“ web.html ”部分。

禁用 Servlet 或过滤器的注册

如前所述​​,​​任何​​Servlet​​或​​Filter​​bean 都会自动注册到 servlet 容器中。要禁用特定​​Filter​​或​​Servlet​​bean 的注册,请为其创建一个注册 bean 并将其标记为禁用,如以下示例所示:

@Configuration(proxyBeanMethods = false)
public class MyFilterConfiguration {

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

}

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

​@WebServlet​​, ​​@WebFilter​​, 和带注释的类可以通过使用注释类并指定包含要注册的组件的包​​@WebListener​​来自动注册到嵌入式 servlet 容器。默认情况下,从注释类的包中扫描。​​@Configuration​​​​@ServletComponentScan​​​​@ServletComponentScan​

3.11配置访问日志

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

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

特性

server.tomcat.basedir=my-tomcat
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%t %a %r %s (%D ms)

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

特性

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

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

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

特性

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

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

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

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

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

如果代理添加了常用的​​X-Forwarded-For​​和​​X-Forwarded-Proto​​头,设置​​server.forward-headers-strategy​​为​​NATIVE​​足以支持这些。有了这个选项,Web 服务器本身就支持这个特性;您可以查看他们的特定文档以了解特定行为。

如果这还不够,Spring Framework 提供了一个ForwardedHeaderFilter。​​server.forward-headers-strategy​​您可以通过将其设置为 将其注册为应用程序中的 servlet 过滤器​​FRAMEWORK​​。

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

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

特性

server.tomcat.remoteip.internal-proxies=192\\.168\\.\\d{1,3}\\.\\d{1,3}

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

3.13使用 Tomcat 启用多个连接器

您可以在 中添加一个​​org.apache.catalina.connector.Connector​​,​​TomcatServletWebServerFactory​​它可以允许多个连接器,包括 HTTP 和 HTTPS 连接器,如下例所示:

@Configuration(proxyBeanMethods = false)
public class MyTomcatConfiguration {

@Bean
public WebServerFactoryCustomizer sslConnectorCustomizer() {
return (tomcat) -> tomcat.addAdditionalTomcatConnectors(createSslConnector());
}

private Connector createSslConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
try {
URL keystore = ResourceUtils.getURL("keystore");
URL truststore = ResourceUtils.getURL("truststore");
connector.setScheme("https");
connector.setSecure(true);
connector.setPort(8443);
protocol.setSSLEnabled(true);
protocol.setKeystoreFile(keystore.toString());
protocol.setKeystorePass("changeit");
protocol.setTruststoreFile(truststore.toString());
protocol.setTruststorePass("changeit");
protocol.setKeyAlias("apitester");
return connector;
}
catch (IOException ex) {
throw new IllegalStateException("Fail to create ssl connector", ex);
}
}

}

3.14使用 Tomcat 的 LegacyCookieProcessor

默认情况下,Spring Boot 使用的嵌入式 Tomcat 不支持 Cookie 格式的“Version 0”,所以你可能会看到如下错误:

java.lang.IllegalArgumentException:Cookie 值中存在无效字符 [32]

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

@Configuration(proxyBeanMethods = false)
public class MyLegacyCookieProcessorConfiguration {

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

}

3.15启用 Tomcat 的 MBean 注册表

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

特性

server.tomcat.mbeanregistry.enabled=true

3.16使用 Undertow 启用多个侦听器

向 中添加一个​​UndertowBuilderCustomizer​​,向 中​​UndertowServletWebServerFactory​​添加一个侦听器​​Builder​​,如下例所示:

@Configuration(proxyBeanMethods = false)
public class MyUndertowConfiguration {

@Bean
public WebServerFactoryCustomizer undertowListenerCustomizer() {
return (factory) -> factory.addBuilderCustomizers(this::addHttpListener);
}

private Builder addHttpListener(Builder builder) {
return builder.addHttpListener(8080, "0.0.0.0");
}

}

3.17使用 @ServerEndpoint 创建 WebSocket 端点

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

@Configuration(proxyBeanMethods = false)
public class MyWebSocketConfiguration {

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

}

前面示例中显示的 bean 将任何​​@ServerEndpoint​​带注释的 bean 注册到底层 WebSocket 容器。当部署到独立的 servlet 容器时,此角色由 servlet 容器初始化程序执行,并且​​ServerEndpointExporter​​不需要 bean。

4. 春天MVC

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

4.1编写 JSON REST 服务

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

@RestController
public class MyController {

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

}

只要​​MyThing​​可以由 Jackson2 序列化(对于普通 POJO 或 Groovy 对象为 true),则​​localhost:8080/thing​​默认提供它的 JSON 表示。请注意,在浏览器中,您有时可能会看到 XML 响应,因为浏览器倾向于发送更喜欢 XML 的接受标头。

4.2. 编写 XML REST 服务

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


com.fasterxml.jackson.dataformat
jackson-dataformat-xml

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

@XmlRootElement
public class MyThing {

private String name;

// getters/setters ...

}

JAXB 仅适用于 Java 8。如果您使用较新的 Java 代,请将以下依赖项添加到您的项目中:


org.glassfish.jaxb
jaxb-runtime

4.3. 自定义 Jackson ObjectMapper

Spring MVC(客户端和服务器端)用于​​HttpMessageConverters​​协商 HTTP 交换中的内容转换。如果 Jackson 在类路径上,您已经获得了由 提供的默认转换器​​Jackson2ObjectMapperBuilder​​,它的一个实例是为您自动配置的。

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

  • ​MapperFeature.DEFAULT_VIEW_INCLUSION​​被禁用
  • ​DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES​​被禁用
  • ​SerializationFeature.WRITE_DATES_AS_TIMESTAMPS​​被禁用

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

您可以使用环境配置​​ObjectMapper​​和​​XmlMapper​​实例。Jackson 提供了一套广泛的开/关功能,可用于配置其处理的各个方面。这些特性在六个枚举(在 Jackson 中)中描述,它们映射到环境中的属性:

枚举

财产

价值观

​com.fasterxml.jackson.databind.DeserializationFeature​

​spring.jackson.deserialization.

​true​​​,​​false​

​com.fasterxml.jackson.core.JsonGenerator.Feature​

​spring.jackson.generator.

​true​​​,​​false​

​com.fasterxml.jackson.databind.MapperFeature​

​spring.jackson.mapper.

​true​​​,​​false​

​com.fasterxml.jackson.core.JsonParser.Feature​

​spring.jackson.parser.

​true​​​,​​false​

​com.fasterxml.jackson.databind.SerializationFeature​

​spring.jackson.serialization.

​true​​​,​​false​

​com.fasterxml.jackson.annotation.JsonInclude.Include​

​spring.jackson.default-property-inclusion​

​always​​​, ​​non_null​​​, ​​non_absent​​​, ​​non_default​​​,​​non_empty​

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

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

上下文​​Jackson2ObjectMapperBuilder​​可以由一个或多个​​Jackson2ObjectMapperBuilderCustomizer​​bean 定制。可以订购此类定制器 bean(Boot 的定制器的顺序为 0),允许在 Boot 定制之前和之后应用额外的定制。

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

如果您想​​ObjectMapper​​完全替换默认值,请定义​​@Bean​​该类型的 a 并将其标记为,​​@Primary​​或者,如果您更喜欢基于构建器的方法,请定义 a ​​Jackson2ObjectMapperBuilder​​ ​​@Bean​​。请注意,在任何一种情况下,这样做都会禁用​​ObjectMapper​​.

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

4.4. 自定义 @ResponseBody 渲染

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

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

4.5. 处理多部分文件上传

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

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

4.6. 关闭 Spring MVC DispatcherServlet

默认情况下,所有内容都从应用程序的根目录 ( ​​/​​) 提供。如果您希望映射到不同的路径,您可以配置如下:

特性

yaml

spring.mvc.servlet.path=/mypath

如果你有额外的 servlet,你可以声明一个​​@Bean​​类型​​Servlet​​或​​ServletRegistrationBean​​为每个类型,Spring Boot 会将它们透明地注册到容器中。因为 servlet 是以这种方式注册的,所以它们可以映射到 的子上下文​​DispatcherServlet​​而不调用它。

配置​​DispatcherServlet​​是不寻常的,但如果你真的需要这样做,还必须提供一个​​@Bean​​类型来提供你的自定义路径。​​DispatcherServletPath​​​​DispatcherServlet​

4.7. 关闭默认 MVC 配置

完全控制 MVC 配置的最简单方法是提供您​​@Configuration​​的​​@EnableWebMvc​​注解。这样做会将所有 MVC 配置留在您的手中。

4.8. 自定义 ViewResolver

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

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

  • 一个InternalResourceViewResolver名为“defaultViewResolver”。这个定位可以通过使用来呈现的物理资源DefaultServlet(包括静态资源和 JSP 页面,如果您使用它们)。它将前缀和后缀应用于视图名称,然后在 servlet 上下文中查找具有该路径的物理资源(默认均为空,但可通过spring.mvc.view.prefix和进行外部配置访问spring.mvc.view.suffix)。您可以通过提供相同类型的 bean 来覆盖它。
  • 一个BeanNameViewResolver名为“beanNameViewResolver”。这是视图解析器链中一个有用的成员,它会拾取任何与View正在解析的名称相同的 bean。没有必要覆盖或替换它。
  • 仅当实际存在类型的 bean 时ContentNegotiatingViewResolver才会添加命名的“viewResolver” 。这是一个复合解析器,委托给所有其他解析器并尝试找到与客户端发送的“接受”HTTP 标头的匹配项。有一个有用的博客,您可能想学习以了解更多信息,您还可以查看源代码以获取详细信息。您可以通过定义一个名为“viewResolver”的 bean来关闭自动配置。ViewContentNegotiatingViewResolverContentNegotiatingViewResolver
  • 如果你使用 Thymeleaf,你还有一个ThymeleafViewResolver名为 'thymeleafViewResolver' 的名字。它通过用前缀和后缀包围视图名称来查找资源。前缀是spring.thymeleaf.prefix,后缀是spring.thymeleaf.suffix。前缀和后缀的值分别默认为 'classpath:/templates/' 和 '.html'。ThymeleafViewResolver您可以通过提供同名的 bean来覆盖。
  • 如果您使用 FreeMarker,您还有一个FreeMarkerViewResolver名为“freeMarkerViewResolver”的工具。spring.freemarker.templateLoaderPath它通过用前缀和后缀包围视图名称来在加载器路径(外部化并具有默认值'classpath:/templates/')中查找资源。前缀外spring.freemarker.prefix化为 ,后缀外化为spring.freemarker.suffix。前缀和后缀的默认值分别为空和“.ftlh”。FreeMarkerViewResolver您可以通过提供同名的 bean来覆盖。
  • 如果您使用 Groovy 模板(实际上,如果groovy-templates在您的类路径中),您还有一个GroovyMarkupViewResolver名为“groovyMarkupViewResolver”的模板。spring.groovy.template.prefix它通过用前缀和后缀(外部化为and )包围视图名称来在加载器路径中查找资源spring.groovy.template.suffix。前缀和后缀的默认值分别为“classpath:/templates/”和“.tpl”。GroovyMarkupViewResolver您可以通过提供同名的 bean来覆盖。
  • 如果您使用 Mustache,您还有一个MustacheViewResolver名为“mustacheViewResolver”。它通过用前缀和后缀包围视图名称来查找资源。前缀是spring.mustache.prefix,后缀是spring.mustache.suffix。前缀和后缀的值分别默认为“classpath:/templates/”和“.mustache”。MustacheViewResolver您可以通过提供同名的 bean来覆盖。

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

  • WebMvcAutoConfiguration
  • ThymeleafAutoConfiguration
  • FreeMarkerAutoConfiguration
  • GroovyTemplateAutoConfiguration

5. 泽西岛

5.1使用 Spring Security 保护 Jersey 端点

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

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

@Component
public class JerseySetStatusOverSendErrorConfig extends ResourceConfig {

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

}

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

要将 Jersey 与另一个 Web 框架(例如 Spring MVC)一起使用,应将其配置为允许另一个框架处理它无法处理的请求。首先,将 Jersey 配置为使用过滤器而不是 servlet,方法是将​​spring.jersey.type​​应用程序属性配置为​​filter​​. 其次,配置您​​ResourceConfig​​以转发可能导致 404 的请求,如以下示例所示。

@Component
public class JerseyConfig extends ResourceConfig {

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

}

6. HTTP 客户端

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

6.1配置 RestTemplate 以使用代理

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

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

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

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

@Configuration(proxyBeanMethods = false)
public class MyReactorNettyClientConfiguration {

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

}

7. 记录

Spring Boot 没有强制的日志记录依赖,除了 Commons Logging API,它通常由 Spring Framework 的​​spring-jcl​​模块提供。要使用Logback,您需要将它包含​​spring-jcl​​在类路径中。推荐的方法是通过所有依赖于​​spring-boot-starter-logging​​. 对于 Web 应用程序,您只需要​​spring-boot-starter-web​​,因为它可传递地依赖于日志记录启动器。如果您使用 Maven,以下依赖项会为您添加日志记录:


org.springframework.boot
spring-boot-starter-web

Spring Boot 有一个​​LoggingSystem​​抽象,它尝试根据类路径的内容配置日志记录。如果 Logback 可用,它是首选。

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

特性

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

您还可以使用​​logging.file.name​​.

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

7.1为日志配置 Logback

如果您需要对 logback 应用超出使用 可以实现的自定义​​application.properties​​项,您将需要添加一个标准的 logback 配置文件。您可以将​​logback.xml​​文件添加到类路径的根目录以供 logback 查找。​​logback-spring.xml​​如果你想使用Spring Boot Logback 扩展,你也可以使用。

Spring Boot 提供了许多​​included​​来自您的配置的 logback 配置。这些包括旨在允许重新应用某些常见的 Spring Boot 约定。

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

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

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

典型的自定义​​logback.xml​​文件如下所示:









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

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

Spring Boot 还通过使用自定义 Logback 转换器在控制台(但不在日志文件中)提供了一些不错的 ANSI 颜色终端输出。请参阅配置​​CONSOLE_LOG_PATTERN​​中​​defaults.xml​​的示例。

如果 Groovy 在类路径上,您应该也可以配置 Logback ​​logback.groovy​​。如果存在,则优先考虑此设置。

7.1.1. 为仅文件输出配置 Logback

如果要禁用控制台日志记录并仅将输出写入文件,则需要一个​​logback-spring.xml​​可以导入​​file-appender.xml​​但不可以的自定义​​console-appender.xml​​,如以下示例所示:









您还需要添加​​logging.file.name​​到您的​​application.properties​​or​​application.yaml​​中,如以下示例所示:

特性

logging.file.name=myapplication.log

7.2. 为日志配置 Log4j

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

推荐的路径是通过启动器,即使它需要一些摇晃。以下示例显示了如何在 Maven 中设置启动器:


org.springframework.boot
spring-boot-starter-web


org.springframework.boot
spring-boot-starter


org.springframework.boot
spring-boot-starter-logging




org.springframework.boot
spring-boot-starter-log4j2

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

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

7.2.1. 使用 YAML 或 JSON 配置 Log4j 2

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

格式

依赖项

文件名

YAML



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





​log4j2.yaml​​​+​​log4j2.yml​



JSON



​com.fasterxml.jackson.core:jackson-databind​





​log4j2.json​​​+​​log4j2.jsn​



7.2.2. 使用复合配置来配置 Log4j 2

Log4j 2 支持将多个配置文件组合成一个复合配置。要在 Spring Boot 中使用此支持,​​logging.log4j2.config.override​​请使用一个或多个辅助配置文件的位置进行配置。辅助配置文件将与主配置合并,无论主配置的源是 Spring Boot 的默认值、标准位置(例如​​log4j.xml​​)还是属性配置的位置​​logging.config​​。

8. 数据访问

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

8.1配置自定义数据源

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

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

@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {

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

}

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

特性

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

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

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

以下示例显示了如何使用 a 创建数据源​​DataSourceBuilder​​:

@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {

@Bean
@ConfigurationProperties("app.datasource")
public 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

但是,有一个问题。由于未公开连接池的实际类型,因此不会在元数据中为您的自定义生成任何键,​​DataSource​​并且您的 IDE 中没有可用的完成(因为​​DataSource​​接口未公开任何属性)。此外,如果您碰巧在类路径中有 Hikari,则此基本设置不起作用,因为 Hikari 没有​​url​​属性(但确实有​​jdbcUrl​​属性)。在这种情况下,您必须按如下方式重写您的配置:

特性

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

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

以下示例显示了如何创建​​HikariDataSource​​with ​​DataSourceBuilder​​:

@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {

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

}

您甚至可以通过利用对您有用的功能走得更远​​DataSourceProperties​​——也就是说,如果没有提供 URL,则通过提供具有合理用户名和密码的默认嵌入式数据库。您可以轻松地​​DataSourceBuilder​​从任何​​DataSourceProperties​​对象的状态初始化 a,因此您还可以注入 Spring Boot 自动创建的 DataSource。但是,这会将您的配置拆分为两个命名空间:​​url​​、​​username​​、​​password​​、​​type​​和​​driver​​on ​​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();
}

}

此设置使您与默认情况下 Spring Boot 为您所做的同步​app.datasource.configuration​​,除了选择专用连接池(在代码中)并且其设置在子命名空间中公开。因为​​DataSourceProperties​​是为你处理​​url​​/​​jdbcUrl​​翻译,所以你可以配置如下:

特性

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

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

8.2. 配置两个数据源

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

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

@Configuration(proxyBeanMethods = false)
public class MyDataSourcesConfiguration {

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

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

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

}

这两个数据源也都需要进行高级定制。例如,您可以按如下方式配置它们:

特性

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

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

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

@Configuration(proxyBeanMethods = false)
public class MyCompleteDataSourcesConfiguration {

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

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

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

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

}

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

8.3. 使用 Spring 数据存储库

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

对于许多应用程序,您只需将正确的 Spring Data 依赖项放在您的类路径中。有一个​​spring-boot-starter-data-jpa​​用于 JPA、​​spring-boot-starter-data-mongodb​​Mongodb 和各种其他支持技术的启动器。首先,创建一些存储库接口来处理您的​​@Entity​​对象。

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

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

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

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

// ...

}

8.5配置 JPA 属性

Spring Data JPA 已经提供了一些与供应商无关的配置选项(例如那些用于 SQL 日志记录的配置选项),并且 Spring Boot 公开了这些选项以及 Hibernate 的更多选项作为外部配置属性。其中一些是根据上下文自动检测的,因此您不必设置它们。

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

JPA 提供程序检测到要使用的方言。如果您更喜欢设置方言,请设置​​spring.jpa.database-platform​​属性。

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

特性

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

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

8.6. 配置休眠命名策略

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

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

@Configuration(proxyBeanMethods = false)
public class MyHibernateConfiguration {

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

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

};
}

}

如果您更喜欢使用 Hibernate 5 的默认值,请设置以下属性:

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

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

@Configuration(proxyBeanMethods = false)
class MyHibernateConfiguration {

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

}

请参阅HibernateJpaAutoConfiguration和JpaBaseConfiguration了解更多详情。

8.7. 配置 Hibernate 二级缓存

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

要使用 JCache 执行此操作,首先要确保它​​org.hibernate:hibernate-jcache​​在类路径中可用。然后,添加一个​​HibernatePropertiesCustomizer​​bean,如下例所示:

@Configuration(proxyBeanMethods = false)
public class MyHibernateSecondLevelCacheConfiguration {

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

}

这个定制器会将 Hibernate 配置​​CacheManager​​​为与应用程序使用的相同。也可以使用单独的​​CacheManager​​实例。

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

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

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

8.9使用自定义 EntityManagerFactory

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

8.10使用多个 EntityManagerFactories

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

@Configuration(proxyBeanMethods = false)
public class MyEntityManagerFactoryConfiguration {

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

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

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

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

}

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


当您为创建 bean 时​​LocalContainerEntityManagerFactoryBean​​​,在创建自动配置期间应用的任何自定义都将​​LocalContainerEntityManagerFactoryBean​​​丢失。例如,在 Hibernate 的情况下,​​spring.jpa.hibernate​​​前缀下的任何属性都不会自动应用于您的​​LocalContainerEntityManagerFactoryBean​​​. 如果您依赖这些属性来配置命名策略或 DDL 模式等内容,则需要在创建​​LocalContainerEntityManagerFactoryBean​​bean 时显式配置它们。

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

如果使用 Spring Data,则需要进行​​@EnableJpaRepositories​​相应的配置,如下例所示:

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

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

}

8.11使用传统的 persistence.xml 文件

Spring Boot 默认不会搜索或使用 a ​​META-INF/persistence.xml​​。如果您更喜欢使用传统的​​persistence.xml​​,则需要定义​​@Bean​​的类型​​LocalEntityManagerFactoryBean​​(ID 为“entityManagerFactory”)并在那里设置持久性单元名称。

8.12使用 Spring Data JPA 和 Mongo 存储库

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

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

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

8.13自定义 Spring Data 的 Web 支持

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

8.14将 Spring 数据存储库公开为 REST 端点

Spring Data REST 可以​​Repository​​为您将实现公开为 REST 端点,前提是已为应用程序启用了 Spring MVC。

Spring Boot 公开了一组有用的属性(来自​​spring.data.rest​​命名空间),用于自定义RepositoryRestConfiguration. 如果您需要提供额外的定制,您应该使用RepositoryRestConfigurerbean。

8.15配置 JPA 使用的组件

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

如果您配置组件,则可以使用​​EntityManagerFactoryDependsOnPostProcessor​​子类作为设置必要依赖项的便捷方式。例如,如果您使用带有 Elasticsearch 作为其索引管理器的 Hibernate Search,则​​EntityManagerFactory​​必须将任何 bean 配置为依赖于​​elasticsearchClient​​bean,如下例所示:

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

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

}

8.16使用两个数据源配置 jOOQ

​DSLContext​​如果您需要将 jOOQ 与多个数据源一起使用,您应该为每个数据源创建的。

9. 数据库初始化

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

9.1使用 JPA 初始化数据库

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

  • ​spring.jpa.generate-ddl​​(布尔值)打开和关闭功能,并且与供应商无关。
  • ​spring.jpa.hibernate.ddl-auto​​(enum) 是一个 Hibernate 特性,它以更细粒度的方式控制行为。本指南稍后将更详细地介绍此功能。

9.2. 使用 Hibernate 初始化数据库

您可以​​spring.jpa.hibernate.ddl-auto​​显式设置,标准的 Hibernate 属性值为​​none​​、​​validate​​、​​update​​、​​create​​和​​create-drop​​。Spring Boot 会根据它是否认为你的数据库是嵌入的来为你选择一个默认值。​​create-drop​​如果没有检测到模式管理器或​​none​​在所有其他情况下,它默认为。通过查看​​Connection​​类型和 JDBC url 来检测嵌入式数据库。 ​​hsqldb​​, ​​h2​​, 和​​derby​​是候选人,而其他人不是。从内存中切换到“真实”数据库时要小心,不要假设新平台中是否存在表和数据。您要么必须​​ddl-auto​​显式设置,要么使用其他机制之一来初始化数据库。

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

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

Spring Boot 可以自动创建 JDBC​​DataSource​​或 R2DBC的模式(DDL 脚本)​​ConnectionFactory​​并对其进行初始化(DML 脚本)。它分别从标准根类路径位置加载 SQL:​​schema.sql​​和​​data.sql​​。此外,Spring Boot 处理​​schema-${platform}.sql​​和​​data-${platform}.sql​​文件(如果存在),​​platform​​其中​​spring.sql.init.platform​​. 这允许您在必要时切换到特定于数据库的脚本。例如,您可以选择将其设置为数据库的供应商名称(​​hsqldb​​、​​h2​​、​​oracle​​、​​mysql​​、​​postgresql​​等)。默认情况下,SQL 数据库初始化仅在使用嵌入式内存数据库时执行。要始终初始化 SQL 数据库,无论其类型如何,设置​​spring.sql.init.mode​​为​​always​​. 同样,要禁用初始化,请设置​​spring.sql.init.mode​​为​​never​​。默认情况下,Spring Boot 启用其基于脚本的数据库初始化程序的快速失败特性。这意味着,如果脚本导致异常,应用程序将无法启动。您可以通过设置来调整该行为​​spring.sql.init.continue-on-error​​。

​DataSource​​默认情况下,在​​EntityManagerFactory​​创建任何 JPA bean 之前执行基于脚本的初始化。​​schema.sql​​可用于为 JPA 管理的实体创建模式,​​data.sql​​并可用于填充它。虽然我们不建议使用多数据源初始化技术,但如果您希望基于脚本的​​DataSource​​初始化能够建立在 Hibernate 执行的模式创建之上,请设置​​spring.jpa.defer-datasource-initialization​​为​​true​​. 这将推迟数据源初始化,直到​​EntityManagerFactory​​创建和初始化任何 bean 之后。 ​​schema.sql​​然后可用于对 Hibernate 执行的任何模式创建进行添加,​​data.sql​​并可用于填充它。

如果您使用的是高级数据库迁移工具,例如 Flyway 或 Liquibase,则应单独使用它们来创建和初始化架构。不建议将基本​​schema.sql​​和​​data.sql​​脚本与 Flyway 或 Liquibase 一起使用,并且将在未来的版本中删除支持。

9.4初始化 Spring Batch 数据库

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

特性

spring.batch.jdbc.initialize-schema=always

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

9.5使用更高级别的数据库迁移工具

Spring Boot 支持两个更高级别的迁移工具:Flyway和Liquibase。

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

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

通常,迁移是表单中的脚本​​V__.sql​​(带有​​下划线分隔的版本,例如“1”或“2_1”)。默认情况下,它们位于名为 的目录中​​classpath:db/migration​​,但您可以通过设置来修改该位置​​spring.flyway.locations​​。这是一个或多个位置的逗号分隔​​classpath:​​列表​​filesystem:​​。例如,以下配置将在默认类路径位置和​​/opt/migration​​目录中搜索脚本:

特性

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

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

特性

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

前面的配置不是 using ​​db/migration​​,而是根据数据库的类型(例如​​db/migration/mysql​​MySQL)设置要使用的目录。支持的数据库列表在DatabaseDriver.

迁移也可以用 Java 编写。Flyway 将使用任何实现​​JavaMigration​​.

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

Spring Boot 调用​​Flyway.migrate()​​以执行数据库迁移。如果您想要更多控制权,请提供一个​​@Bean​​that implements FlywayMigrationStrategy。

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

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

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

特性

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

使用该设置,迁移​​dev/db/migration​​仅在​​dev​​配置文件处于活动状态时运行。

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

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

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

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

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

9.6。依赖于一个初始化的数据库

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

9.6.1。检测数据库初始化器

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

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

如果您使用第三方启动器进行数据库初始化库,它可能会提供一个检测器,这样其他类型的 bean 也会被自动检测到。要检测其他 bean,请注册​​DatabaseInitializerDetector​​in的实现​​META-INF/spring.factories​​。

9.6.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​​in的实现​​META-INF/spring.factories​​。或者,使用 注释 bean 的类或其​​@Bean​​方法​​@DependsOnDatabaseInitialization​​。

10. 消息传递

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

10.1禁用事务处理的 JMS 会话

如果您的 JMS 代理不支持事务会话,则必须完全禁用对事务的支持。如果您创建的​​JmsListenerContainerFactory​​,则无需执行任何操作,因为默认情况下无法进行交易。如果要使用​​DefaultJmsListenerContainerFactoryConfigurer​​来重用 Spring Boot 的默认值,可以禁用事务处理会话,如下所示:

@Configuration(proxyBeanMethods = false)
public class MyJmsConfiguration {

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

}

前面的示例覆盖了默认工厂,它应该应用于您的应用程序定义的任何其他工厂(如果有)。

11. 批量申请

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

11.1指定批处理数据源

默认情况下,批处理应用程序需要​​DataSource​​存储作业详细信息。Spring Batch 默认需要一个​​DataSource​​。要让它使用​​DataSource​​不是应用程序的 main ​​DataSource​​,声明一个​​DataSource​​bean,​​@Bean​​用​​@BatchDataSource​​. 如果您这样做并且想要两个数据源,请记住标记另一个​​@Primary​​。要获得更大的控制权,请实施​​BatchConfigurer​​. 有关更多详细信息,请参阅Javadoc@EnableBatchProcessing。

11.2. 在启动时运行 Spring Batch 作业

​@EnableBatchProcessing​​通过添加到您的一个类来启用 Spring Batch 自动配置​​@Configuration​​。

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

11.3. 从命令行运行

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

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

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

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

这仅为批处理作业提供了一个参数:​​someParameter=someValue​​.

11.4. 存储作业存储库

Spring Batch 需要存储库的数据存储​​Job​​。如果使用 Spring Boot,则必须使用实际的数据库。

12. 执行器

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

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

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

12.2. 自定义“whitelabel”错误页面

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

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

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

12.3. 清理敏感值

​env​​和端点返回的信息​​configprops​​可能有些敏感,因此默认情况下会清理匹配某些模式的键(即它们的值被替换为​​******​​)。Spring Boot 对这些键使用合理的默认值:任何以单词“password”、“secret”、“key”、“token”、“vcap_services”、“sun.java.command”结尾的键都会被完全清除。此外,任何包含单词​​credentials​​(配置为正则表达式,即​​.*credentials.*​​)作为键的一部分的键也被完全清理。

此外,Spring Boot 对具有以下结尾之一的键的类似 URI 的值的敏感部分进行清理:

  • ​address​
  • ​addresses​
  • ​uri​
  • ​uris​
  • ​url​
  • ​urls​

URI 的敏感部分使用格式标识​://:@:/​​。例如,对于属性​​myclient.uri=http://user1:password1@localhost:8081​​,经过清理的结果值为 ​​http://user1:******@localhost:8081​​。

12.3.1. 自定义清理

消毒可以通过两种不同的方式进行定制。

​env​​和端点使用的默认模式​​configprops​​可以分别使用​​management.endpoint.env.keys-to-sanitize​​和替换​​management.endpoint.configprops.keys-to-sanitize​​。或者,可以使用​​management.endpoint.env.additional-keys-to-sanitize​​和配置其他模式​​management.endpoint.configprops.additional-keys-to-sanitize​​。

要对清理进行更多控制,请定义一个​​SanitizingFunction​​bean。调用该​​SanitizableData​​函数的 提供了对键和值以及​​PropertySource​​它们的来源的访问。例如,这允许您清理来自特定属性源的每个值。每个​​SanitizingFunction​​都按顺序调用,直到函数更改可清理数据的值。如果没有函数更改其值,则执行内置的基于键的清理。

12.4. 将健康指标映射到千分尺指标

Spring Boot 健康指标返回一个​​Status​​类型来指示整个系统的健康状况。如果您想监控或提醒特定应用程序的健康水平,您可以使用 Micrometer 将这些状态导出为指标。默认情况下,Spring Boot 使用状态码“UP”、“DOWN”、“OUT_OF_SERVICE”和“UNKNOWN”。要导出这些,您需要将这些状态转换为一组数字,以便它们可以与 Micrometer 一起使用​​Gauge​​。

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

@Configuration(proxyBeanMethods = false)
public class MyHealthMetricsExportConfiguration {

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

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

}

13. 安全

本节解决使用 Spring Boot 时有关安全性的问题,包括将 Spring Security 与 Spring Boot 一起使用时出现的问题。

13.1. 关闭 Spring Boot 安全配置

如果您在应用程序中​​@Configuration​​使用 a​​WebSecurityConfigurerAdapter​​或​​SecurityFilterChain​​bean 定义 a,它会关闭 Spring Boot 中的默认 webapp 安全设置。

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

如果您提供​​@Bean​​类型为​​AuthenticationManager​​、​​AuthenticationProvider​​或的 a,则不会创建​​UserDetailsService​​默认值​​@Bean​​for 。​​InMemoryUserDetailsManager​​这意味着您可以使用 Spring Security 的完整功能集(例如各种身份验证选项)。

添加用户帐户的最简单方法是提供您的​​UserDetailsService​​bean。

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

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

特性

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

(其中任何一个属性的存在都会打开阀门。或者,您可以通过使用bean​​RemoteIpValve​​自定义来添加。)​​TomcatServletWebServerFactory​​​​WebServerFactoryCustomizer​

要将 Spring Security 配置为要求所有(或部分)请求的安全通道,请考虑添加您的​​SecurityFilterChain​​bean,该 bean 添加以下​​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();
}

}

14. 热插拔

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

14.1. 重新加载静态内容

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

或者,在 IDE 中运行(尤其是在调试时)是一种很好的开发方式(所有现代 IDE 都允许重新加载静态资源,并且通常还允许热交换 Java 类更改)。

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

14.2. 在不重启容器的情况下重新加载模板

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

14.2.1. 百里香模板

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

14.2.2. FreeMarker 模板

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

14.2.3. Groovy 模板

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

14.3. 快速应用程序重启

该​​spring-boot-devtools​​模块包括对自动应用程序重新启动的支持。虽然不如JRebel等技术快,但它通常比“冷启动”快得多。在研究本文档后面讨论的一些更复杂的重新加载选项之前,您可能应该尝试一下。

14.4. 在不重新启动容器的情况下重新加载 Java 类

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

15. 测试

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

15.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("/"));
}

}

Spring Security 提供了与 Spring MVC Test 的全面集成,这也可以在使用​​@WebMvcTest​​slice 和​​MockMvc​​.

15.2. 使用测试容器进行集成测试

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

@SpringBootTest
@Testcontainers
class MyIntegrationTests {

@Container
static Neo4jContainer neo4j = new Neo4jContainer<>("neo4j:4.2");

@Test
void myTest() {
// ...
}

}

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

这可以通过​​@DynamicPropertySource​​允许将动态属性值添加到 Spring 环境的静态方法来完成。

@SpringBootTest
@Testcontainers
class MyIntegrationTests {

@Container
static Neo4jContainer neo4j = new Neo4jContainer<>("neo4j:4.2");

@Test
void myTest() {
// ...
}

@DynamicPropertySource
static void neo4jProperties(DynamicPropertyRegistry registry) {
registry.add("spring.neo4j.uri", neo4j::getBoltUrl);
}

}

上述配置允许应用程序中与 Neo4j 相关的 bean 与在 Testcontainers 管理的 Docker 容器内运行的 Neo4j 通信。

15.3. 包含在切片测试中的结构​​@Configuration​​类

切片测试通过将 Spring Framework 的组件扫描限制为基于其类型的一组有限组件来工作。对于不是通过组件扫描创建的任何 bean,例如,使用​​@Bean​​注释创建的 bean,切片测试将无法在应用程序上下文中包含/排除它们。考虑这个例子:

@Configuration(proxyBeanMethods = false)
public class MyConfiguration {

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

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

}

对于​​@WebMvcTest​​具有上述​​@Configuration​​类的应用程序,您可能希望将​​SecurityFilterChain​​bean 放在应用程序上下文中,以便您可以测试您的控制器端点是否得到正确保护。但是,​​MyConfiguration​​@WebMvcTest 的组件扫描过滤器不会选择它,因为它与过滤器指定的任何类型都不匹配。您可以通过使用​​@Import(MyConfiguration.class)​​. 这将加载所有 bean,​​MyConfiguration​​包括​​BasicDataSource​​测试 Web 层时不需要的 bean。将配置类拆分为两个将启用仅导入安全配置。

@Configuration(proxyBeanMethods = false)
public class MySecurityConfiguration {

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

}
@Configuration(proxyBeanMethods = false)
public class MyDatasourceConfiguration {

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

}

当某个域的 bean 需要包含在切片测试中时,拥有单个配置类可能效率低下。相反,将应用程序的配置构建为具有特定域的 bean 的多个粒度类可以启用仅针对特定切片测试导入它们。

16. 建造

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

16.1. 生成构建信息

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

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




org.springframework.boot
spring-boot-maven-plugin
2.7.5



build-info





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

springBoot {
buildInfo()
}

16.2. 生成 Git 信息

Maven 和 Gradle 都允许在构建项目时生成​​git.properties​​包含有关​​git​​源代码存储库状态信息的文件。

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




pl.project13.maven
git-commit-id-plugin


Gradle 用户使用该gradle-git-properties插件也可以达到同样的效果,如下例所示:

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

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

16.3. 自定义依赖版本

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

16.4. 使用 Maven 创建可执行 JAR

可​​spring-boot-maven-plugin​​用于创建可执行的“胖”JAR。如果你使用​​spring-boot-starter-parent​​POM,你可以声明插件并且你的 jars 被重新打包如下:




org.springframework.boot
spring-boot-maven-plugin


如果您不使用父 POM,您仍然可以使用该插件。但是,您必须另外添加一个​​部分,如下所示:




org.springframework.boot
spring-boot-maven-plugin
{spring-boot-version}



repackage





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

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

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

要生成两个工件,一个可以用作依赖项,另一个是可执行的,必须指定一个分类器。此分类器应用于可执行存档的名称,将默认存档用作依赖项。

要在 Maven 中配置分类器​​exec​​,可以使用以下配置:




org.springframework.boot
spring-boot-maven-plugin

exec



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

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

要处理任何有问题的库,您可以标记特定的嵌套 jar 在可执行 jar 首次运行时应自动解包。这样的嵌套 jar 被写入​​java.io.tmpdir​​系统属性标识的临时目录下。

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




org.springframework.boot
spring-boot-maven-plugin



org.jruby
jruby-complete





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

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

在 Maven 中,可执行 jar 必须是主要工件,您可以为库添加分类 jar,如下所示:




org.springframework.boot
spring-boot-maven-plugin


maven-jar-plugin


lib
package

jar


lib

application.yml






16.8. 远程调试使用 Maven 启动的 Spring Boot 应用程序

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

16.9不使用 spring-boot-antlib 从 Ant 构建可执行存档

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

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

以下示例显示了如何使用 Ant 构建可执行存档:





















17. 传统部署

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

17.1. 创建可部署的战争文件

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

爪哇

科特林

@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {

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

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

}

下一步是更新您的构建配置,以便您的项目生成一个 war 文件而不是 jar 文件。如果你使用 Maven 和​​spring-boot-starter-parent​​(它为你配置了 Maven 的 war 插件),你需要做的就是修改​​pom.xml​​将打包改为 war,如下:

war

如果你使用Gradle,则需要修改​​build.gradle​​将war插件应用到项目中,如下:

apply plugin: 'war'

该过程的最后一步是确保嵌入式 servlet 容器不会干扰部署 war 文件的 servlet 容器。为此,您需要将嵌入式 servlet 容器依赖项标记为已提供。

如果您使用 Maven,以下示例将 servlet 容器(在本例中为 Tomcat)标记为已提供:




org.springframework.boot
spring-boot-starter-tomcat
provided


如果您使用 Gradle,以下示例将 servlet 容器(在本例中为 Tomcat)标记为已提供:

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

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

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

要将现有的非 Web Spring 应用程序转换为 Spring Boot 应用程序,请替换创建您的代码​​ApplicationContext​​并将其替换为对​​SpringApplication​​或的调用​​SpringApplicationBuilder​​。Spring MVC Web 应用程序通常可以先创建一个可部署的 war 应用程序,然后再将其迁移到可执行的 war 或 jar 中。请参阅关于将 jar 转换为战争的入门指南。

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

@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {

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


}

请记住,您放入的任何内容​​sources​​都只是一个 Spring ​​ApplicationContext​​。通常,任何已经工作的东西都应该在这里工作。可能有一些 bean 您可以稍后删除并让 Spring Boot 为它们提供的默认值,但在您需要这样做之前应该可以让某些东西工作。

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

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

  • A@Bean类型ServletorServletRegistrationBean将该 bean 安装在容器中,就好像它是 ain一样web.xml
  • ​@Bean​​类型Filteror的 AFilterRegistrationBean行为类似(作为 a)。
  • XML 文件中的ApplicationContext可以通过@ImportResourceApplication或者,已经大量使用注释配置的情况可以在几行中重新创建为@Bean定义。

一旦 war 文件开始工作,您可以通过向​​main​​您​​Application​​的 .

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

应用程序可以分为不止一类:

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

所有这些都应该可以翻译,但每个都可能需要稍微不同的技术。

如果 Servlet 3.0+ 应用程序已经使用 Spring Servlet 3.0+ 初始化器支持类,它们可能会很容易转换。通常,现有的所有代码​​WebApplicationInitializer​​都可以移动到​​SpringBootServletInitializer​​. 如果您现有的应用程序有多个​​ApplicationContext​​(例如,如果它使用​​AbstractDispatcherServletInitializer​​),那么您可能能够将所有上下文源组合成一个​​SpringApplication​​. 您可能遇到的主要复杂情况是如果组合不起作用并且您需要维护上下文层次结构。有关示例,请参阅有关构建层次结构的条目。包含特定于 Web 的功能的现有父上下文通常需要分解,以便所有​​ServletContextAware​​组件都在子上下文中。

尚未成为 Spring 应用程序的应用程序可以转换为 Spring Boot 应用程序,前面提到的指南可能会有所帮助。但是,您可能还会遇到问题。在这种情况下,我们建议在 Stack Overflow 上使用标签提问spring-boot。

17.3. 将 WAR 部署到 WebLogic

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

WebLogic 的典型初始化程序应类似于以下示例:

@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer implements WebApplicationInitializer {

}

如果使用 Logback,还需要告诉 WebLogic 更喜欢打包的版本,而不是服务器预装的版本。您可以通过添加​​WEB-INF/weblogic.xml​​具有以下内容的文件来做到这一点:


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


org.slf4j


特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报
评论区(0)
按点赞数排序
用户头像
精选文章
thumb 中国研究员首次曝光美国国安局顶级后门—“方程式组织”
thumb 俄乌线上战争,网络攻击弥漫着数字硝烟
thumb 从网络安全角度了解俄罗斯入侵乌克兰的相关事件时间线
下一篇
分布式系统发展史一览,内附全图 2023-11-30 06:01:48