0%

SpringBoot官方文档翻译-使用方法指南

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

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

我们也很乐意扩展此部分。如果您想添加“操作方法”,请给我们发送pull request

SpringBoot应用程序

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

创建自己的FailureAnalyzer

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

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

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

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

Note

如果您需要访问BeanFactoryEnvironment,则您的FailureAnalyzer可以分别简单地实现BeanFactoryAwareEnvironmentAware

自动配置故障排除

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

Spring Boot ApplicationContext中有一个非常有用的ConditionEvaluationReport。如果启用DEBUG日志记录输出,则可以看到它。如果您使用spring-boot-actuator(请参见Actuator 章节,则还有一个conditions端点以 JSON 渲染报告。使用该端点来调试应用程序,并在运行时查看 Spring Boot 添加了哪些功能(哪些尚未添加)。

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

  • 查找名为*AutoConfiguration的类,并阅读其源代码。请特别注意@Conditional*注解,以了解它们启用了哪些功能以及何时启用。将--debug添加到命令行或系统属性-Ddebug,以在控制台上获取在您的应用中做出的所有自动配置决策的日志。在正在运行的 Actuator 应用程序中,查看conditions端点(/actuator/conditions或等效的 JMX)以获取相同的信息。
  • 查找@ConfigurationProperties的类(例如ServerProperties),然后从中读取可用的外部配置选项。 @ConfigurationProperties注解具有name属性,该属性充当外部属性的前缀。因此,ServerProperties具有prefix="server",并且其配置属性是server.portserver.address等。在正在运行的 Actuator 应用程序中,查看configprops端点。
  • 寻找在Binder上使用bind方法以轻松地将配置值从Environment中拉出的用法。它通常与前缀一起使用。
  • 查找直接绑定到Environment@ValueComments。
  • 寻找@ConditionalOnExpressionComments,这些 Comments 可根据 SpEL 表达式打开和关闭功能,这些 Comments 通常使用从Environment解析的占位符进行评估。

在启动环境或ApplicationContext之前对其进行自定义

SpringApplication具有ApplicationListenersApplicationContextInitializers,用于将自定义项应用于上下文或环境。 Spring Boot 从META-INF/spring.factories内部加载了许多此类自定义内容供内部使用。注册其他自定义项的方法有多种:

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

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

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

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

该实现可以加载任意文件并将其添加到Environment。例如,以下示例从 Classpath 加载 YAML 配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class EnvironmentPostProcessorExample implements EnvironmentPostProcessor {

private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();

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

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

}

Tip

Environment已经准备好了 Spring Boot 默认加载的所有常用属性源。因此,可以从环境中获取文件的位置。前面的示例将custom-resource属性源添加到列表的末尾,以便在其他任何常见位置定义的键都具有优先权。定制实现可以定义另一个 Sequences。

Warning

虽然在@SpringBootApplication上使用@PropertySource似乎是在Environment中加载自定义资源的便捷方法,但我们不建议您这样做,因为 Spring Boot 在刷新ApplicationContext之前会准备Environment。用@PropertySource定义的任何键加载得太晚,以至于对自动配置没有任何影响。

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

您可以使用ApplicationBuilder类创建父/子ApplicationContext层次结构。有关更多信息,请参见“ Spring Boot 功能”部分中的“ 第 23.4 节“ Fluent Builder API””。

创建非Web应用程序

并非所有的 Spring 应用程序都必须是 Web 应用程序(或 Web 服务)。如果要用main方法执行一些代码,又要引导 Spring 应用程序来设置要使用的基础架构,则可以使用 Spring Boot 的SpringApplication功能。 SpringApplication更改其ApplicationContext类,具体取决于它是否认为需要 Web 应用程序。您可以做的第一件事是将与服务器相关的依存关系(例如 Servlet API)从 Classpath 中移开。如果您不能执行此操作(例如,从同一代码库运行两个应用程序),则可以在SpringApplication实例上显式调用setWebApplicationType(WebApplicationType.NONE)或设置applicationContextClass属性(通过 Java API 或带有外部属性)。您可以将要作为业务逻辑运行的应用程序代码实现为CommandLineRunner,并可以将其作为@Bean定义放到上下文中。

属性和配置

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

在构建时自动扩展属性

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

使用Maven自动扩展属性

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

1
2
app.encoding[emailprotected]@
app.java.version[emailprotected]@

Note

这样只会过滤生产配置(换句话说,不会对src/test/resources进行过滤)。

Tip

如果启用addResources标志,则spring-boot:run目标可以将src/main/resources直接添加到 Classpath 中(用于热重载)。这样做避免了资源过滤和此功能。相反,您可以使用exec:java目标或自定义插件的配置。有关更多详细信息,请参见插件使用情况页面

如果您不使用 Starter Parent,则需要在pom.xml<build/>元素内包括以下元素:

1
2
3
4
5
6
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>

您还需要在<plugins/>内包括以下元素:

1
2
3
4
5
6
7
8
9
10
11
<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>

Note

如果您在配置中使用标准的 Spring 占位符(例如${placeholder}),则useDefaultDelimiters属性非常重要。如果该属性未设置为false,则可以通过构建扩展它们。

使用Gradle自动扩展属性

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

1
2
3
processResources {
expand(project.properties)
}

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

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

Note

Gradle 的expand方法使用 Groovy 的SimpleTemplateEngine,它可以转换${..}令牌。 ${..}样式与 Spring 自己的属性占位符机制冲突。要将 Spring 属性占位符与自动扩展一起使用,请按以下方式对 Spring 属性占位符进行转义:\${..}

外部化SpringApplication的配置

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

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

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

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

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

现在考虑以下配置:

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

实际的应用程序 now 显示标语(被配置覆盖)并为ApplicationContext使用三个源(按以下 Sequences):demo.MyAppcom.acme.Configcom.acme.ExtraConfig

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

默认情况下,来自不同来源的属性将以定义的 Sequences 添加到 Spring Environment(有关确切 Sequences,请参见“ Spring Boot 功能”部分的“ 第 24 章,外部化配置

增强和修改此 Sequences 的一种好方法是向应用程序源添加@PropertySource注解。检查传递给SpringApplication静态便捷方法的类和使用setSources()添加的类,以查看它们是否具有@PropertySources。如果确实如此,则将这些属性尽早添加到Environment以便在ApplicationContext生命周期的所有阶段中使用。以这种方式添加的属性的优先级低于使用默认位置(例如application.properties),系统属性,环境变量或命令行添加的属性。

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

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

无论您在环境中设置什么,Spring Boot 总是如上所述加载application.properties。默认情况下,如果使用 YAML,则 extensions 为’.yml’的文件也将添加到列表中。

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

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

使用“简短”命令行参数

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

1
server.port=${port:8080}

Tip

如果您从spring-boot-starter-parent POM 继承,则maven-resources-plugins的默认过滤器令牌已从${*}更改为@(即@[email protected]而不是${maven.token}),以防止与 Spring 样式的占位符冲突。如果直接为application.properties启用了 Maven 过滤,则可能还需要更改默认过滤器令牌以使用other delimiters

Note

在这种特定情况下,端口绑定可在 PaaS 环境(例如 Heroku 或 Cloud Foundry)中工作。在这两个平台中,PORT环境变量是自动设置的,并且 Spring 可以绑定到Environment属性的大写同义词。

对外部属性使用YAML

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

1
2
3
4
5
6
7
8
spring:
application:
name: cruncher
datasource:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost/test
server:
port: 9000

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

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

1
2
3
4
spring.application.name=cruncher
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost/test
server.port=9000

有关 YAML 的更多信息,请参见“ Spring Boot 功能”部分中的“ 第 24.7 节“使用 YAML 代替属性””。

设置ActiveSpring轮廓

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

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

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

1
spring.profiles.active=production

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

有关更多信息,请参见“ Spring Boot 功能”部分中的“ 第 25 章,Profile”。

根据环境更改配置

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
server:
port: 9000
---

spring:
profiles: development
server:
port: 9001

---

spring:
profiles: production
server:
port: 0

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

Note

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

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

发现外部属性的内置选项

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

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

附录包括一个application.properties示例,其中列出了 Spring Boot 支持的最常见属性。Authority 列表来自于在源代码中搜索@ConfigurationProperties@Value注解以及偶尔使用Binder。有关加载属性的确切 Sequences 的更多信息,请参见“ 第 24 章,外部化配置”。

嵌入式Web服务器

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

使用其他Web服务器

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

  • 对于 Servlet 堆栈应用程序,spring-boot-starter-web通过包含spring-boot-starter-tomcat来包含 Tomcat,但是您可以使用spring-boot-starter-jettyspring-boot-starter-undertow来代替。
  • 对于反应堆应用程序,spring-boot-starter-webflux通过包含spring-boot-starter-reactor-netty来包含 Reactor Netty,但是您可以改用spring-boot-starter-tomcatspring-boot-starter-jettyspring-boot-starter-undertow

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<properties>
<servlet-api.version>3.1.0</servlet-api.version>
</properties>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!-- Exclude the Tomcat dependency -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Use Jetty instead -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

Note

Servlet API 的版本已被覆盖,因为与 Tomcat 9 和 Undertow 2.0 不同,Jetty 9.4 不支持 Servlet 4.0.

以下 Gradle 示例显示了如何排除 Netty 并为 Spring WebFlux 包括 Undertow:

1
2
3
4
5
6
7
8
9
10
11
configurations {
// exclude Reactor Netty
compile.exclude module: 'spring-boot-starter-reactor-netty'
}

dependencies {
compile 'org.springframework.boot:spring-boot-starter-webflux'
// Use Undertow instead
compile 'org.springframework.boot:spring-boot-starter-undertow'
// ...
}

Note

必须使用spring-boot-starter-reactor-netty才能使用WebClient类,因此即使需要包含其他 HTTP 服务器,也可能需要保持对 Netty 的依赖。

禁用Web服务器

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

1
spring.main.web-application-type=none

更改HTTP端口

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

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

有关更多详细信息,请参阅“ Spring Boot 功能”部分中的“ 第 28.4.4 节“自定义嵌入式 Servlet 容器””或ServerProperties源代码。

使用随机未分配的HTTP端口

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

在运行时发现HTTP端口

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
public class MyWebIntegrationTests {

@Autowired
ServletWebServerApplicationContext server;

@LocalServerPort
int port;

// ...

}

Note

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

启用HTTP响应压缩

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

1
server.compression.enabled=true

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

默认情况下,仅当响应的 Content Type 为以下之一时,它们才被压缩:

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

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

配置SSL

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

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

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

使用前面示例中的配置意味着应用程序不再在端口 8080 上支持纯 HTTP 连接器。SpringBoot 不支持通过application.properties配置 HTTP 连接器和 HTTPS 连接器。如果要同时拥有两者,则需要以编程方式配置它们之一。我们建议使用application.properties来配置 HTTPS,因为 HTTP 连接器在两者中以编程方式进行配置比较容易。有关示例,请参见spring-boot-sample-tomcat-multi-connectors示例项目。

配置HTTP/2

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

Note

Spring Boot 不支持h2c,即 HTTP/2 协议的明文版本。因此,您必须首先配置 SSL

具有Undertow的HTTP/2

从 Undertow 1.4.0 开始,在 JDK8 上无需任何其他要求即可支持 HTTP/2.

使用Jetty的HTTP/2

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

带有Tomcat的HTTP/2

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

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

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

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

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

具有ReactorNetty的HTTP/2

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

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

配置Web服务器

通常,您应该首先考虑使用许多可用的配置密钥之一,并通过在application.properties(或application.yml或环境等,请参见“ 第 77.8 节“发现外部属性的内置选项””)中添加新条目来自定义 Web 服务器。 server.*命名空间在这里非常有用,它包括server.tomcat.*server.jetty.*等名称空间,用于特定于服务器的功能。请参阅附录 A,通用应用程序属性的列表。

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

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

1
2
3
4
5
6
7
8
9
@Component
public class MyTomcatWebServerCustomizer
implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {

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

此外,Spring Boot 还提供:

Server Servlet stack Reactive stack
Tomcat TomcatServletWebServerFactory TomcatReactiveWebServerFactory
Jetty JettyServletWebServerFactory JettyReactiveWebServerFactory
Undertow UndertowServletWebServerFactory UndertowReactiveWebServerFactory
Reactor N/A NettyReactiveWebServerFactory

获得WebServerFactory的访问权限后,通常可以向其添加定制程序以配置特定的部分,例如连接器,服务器资源或服务器本身-全部使用服务器特定的 API。

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

将Servlet,过滤器或侦听器添加到应用程序

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

使用SpringBean添加Servlet,过滤器或侦听器

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

对于FiltersServlets,您还可以通过添加FilterRegistrationBeanServletRegistrationBean来代替基础组件或在基础组件之外添加 Map 和 init 参数。

Note

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

像其他任何 Spring bean 一样,您可以定义 Servlet 过滤器 bean 的 Sequences。请确保选中“ 名为“将 Servlet,过滤器和侦听器注册为 Spring Bean”的部分”部分。

禁用Servlet或过滤器的注册

作为described earlier,任何ServletFilter bean 都会自动注册到 servlet 容器中。要禁用特定FilterServlet bean 的注册,请为其创建注册 bean 并将其标记为已禁用,如以下示例所示:

1
2
3
4
5
6
@Bean
public FilterRegistrationBean registration(MyFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.setEnabled(false);
return registration;
}

使用Classpath扫描添加Servlet,过滤器和侦听器

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

配置访问日志

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

例如,以下设置使用custom pattern记录对 Tomcat 的访问。

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

Note

日志的默认位置是相对于 Tomcat 基本目录的logs目录。默认情况下,logs目录是一个临时目录,因此您可能需要修复 Tomcat 的基本目录或对日志使用绝对路径。在前面的示例中,相对于应用程序的工作目录,日志位于my-tomcat/logs中。

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

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

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

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

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

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

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

您的应用程序可能需要发送302重定向或使用绝对链接将内容渲染回自身。当在代理后面运行时,调用者需要链接到代理,而不要链接到托管您的应用的计算机的物理地址。通常,此类情况是通过与代理之间的 Contract 来处理的,该代理添加了 Headers,以告诉后端如何构造与自身的链接。

如果代理添加了常规的X-Forwarded-ForX-Forwarded-ProtoHeaders(大多数代理服务器都这样做),则在application.properties中将server.use-forward-headers设置为true的情况下,应正确渲染绝对链接。

Note

如果您的应用程序在 Cloud Foundry 或 Heroku 中运行,则server.use-forward-headers属性默认为true。在所有其他情况下,它默认为false

自定义Tomcat的代理配置

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

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

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

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

Note

仅当使用属性文件进行配置时,才需要双反斜杠。如果使用 YAML,则单个反斜杠就足够了,并且与上一个示例中所示的值相等的值为192\.168\.\d{1,3}\.\d{1,3}

Note

您可以通过将internal-proxies设置为空来信任所有代理(但在生产环境中不要这样做)。

您可以完全关闭 Tomcat RemoteIpValve的配置,方法是关闭自动开关(为此,设置server.use-forward-headers=false)并在TomcatServletWebServerFactory bean 中添加新的 Valve 实例。

使用Tomcat启用多个连接器

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Bean
public ServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
tomcat.addAdditionalTomcatConnectors(createSslConnector());
return tomcat;
}

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

使用Tomcat的LegacyCookieProcessor

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

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

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

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

使用Undertow启用多个侦听器

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

1
2
3
4
5
6
7
8
9
10
11
12
13
@Bean
public UndertowServletWebServerFactory servletWebServerFactory() {
UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();
factory.addBuilderCustomizers(new UndertowBuilderCustomizer() {

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

});
return factory;
}

使用ServerEndpoint注解创建WebSocket端点

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

1
2
3
4
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}

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

SpringMVC

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

编写JSONREST服务

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

1
2
3
4
5
6
7
8
9
@RestController
public class MyController {

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

}

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

编写XMLREST服务

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

1
2
3
4
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>

如果无法使用 Jackson 的 XML extensions,则使用 JAXB(JDK 中默认提供),另外要求将MyThing标注为@XmlRootElement,如以下示例所示:

1
2
3
4
5
@XmlRootElement
public class MyThing {
private String name;
// .. getters and setters
}

要使服务器渲染 XML 而不是 JSON,您可能必须发送Accept: text/xmlHeaders(或使用浏览器)。

自定义JacksonObjectMapper

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

ObjectMapper(对于 Jackson XML 转换器,则为XmlMapper)实例(默认情况下创建)具有以下自定义属性:

  • MapperFeature.DEFAULT_VIEW_INCLUSION已禁用
  • DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES已禁用
  • SerializationFeature.WRITE_DATES_AS_TIMESTAMPS已禁用

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

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

Enum Property Values
com.fasterxml.jackson.databind.DeserializationFeature spring.jackson.deserialization.<feature_name> true , false
com.fasterxml.jackson.core.JsonGenerator.Feature spring.jackson.generator.<feature_name> true , false
com.fasterxml.jackson.databind.MapperFeature spring.jackson.mapper.<feature_name> true , false
com.fasterxml.jackson.core.JsonParser.Feature spring.jackson.parser.<feature_name> true , false
com.fasterxml.jackson.databind.SerializationFeature spring.jackson.serialization.<feature_name> true , false
com.fasterxml.jackson.annotation.JsonInclude.Include spring.jackson.default-property-inclusion always , non_null , non_absent , non_default , non_empty

例如,要启用漂亮打印,请设置spring.jackson.serialization.indent_output=true。注意,由于使用了relaxed bindingindent_output的情况不必与相应的枚举常量INDENT_OUTPUT的情况匹配。

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

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

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

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

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

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

自定义ResponseBody注解渲染

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

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

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

处理分段文件上传

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

当您想在 Spring MVC 控制器处理程序方法中接收 Multipart 编码的文件数据作为@RequestParamComments 类型MultipartFile的参数时,Multipart 支持会很有帮助。

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

Note

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

关闭SpringMVCDispatcherServlet

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

1
spring.mvc.servlet.path=/acme

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

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

关闭默认的MVC配置

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

自定义ViewResolvers

ViewResolver是 Spring MVC 的核心组件,将@Controller中的视图名称转换为实际的View实现。请注意,ViewResolvers主要用于 UI 应用程序,而不是 REST 风格的服务(View不用于渲染@ResponseBody)。 ViewResolver的实现有很多可供选择,而 Spring 本身并未就应该使用哪个实现提出意见。另一方面,Spring Boot 会根据您在 Classpath 和应用程序上下文中找到的内容为您安装一两个。 DispatcherServlet使用它在应用程序上下文中找到的所有解析器,依次尝试每个解析器直到得到结果,因此,如果添加自己的解析器,则必须知道解析器的 Sequences 和添加位置。

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

  • InternalResourceViewResolver名为“ defaultViewResolver”。此代码查找可以使用DefaultServlet渲染的物理资源(包括静态资源和 JSP 页面,如果使用的话)。它在视图名称上应用前缀和后缀,然后在 Servlet 上下文中查找具有该路径的物理资源(默认值均为空,但可通过spring.mvc.view.prefixspring.mvc.view.suffix进行外部配置访问)。您可以通过提供相同类型的 bean 覆盖它。
  • BeanNameViewResolver名为“ beanNameViewResolver”。这是视图解析器链的有用成员,可以拾取与要解析的View同名的所有 bean。不必重写或替换它。
  • 仅当实际存在View类型的 Bean 时,才添加名为ContentNegotiatingViewResolver的“ viewResolver”。这是一个“主”解析器,委派给所有其他解析器,并尝试查找与 Client 端发送的“ Accept” HTTP Headers 匹配的内容。您可能想学习有用的关于 ContentNegotiatingViewResolver 的博客以了解更多信息,也可以查看源代码以获取详细信息。您可以通过定义一个名为’viewResolver’的 bean 来关闭自动配置的ContentNegotiatingViewResolver
  • 如果您使用 Thymeleaf,则还有一个ThymeleafViewResolver,名为“ thymeleafViewResolver”。它通过在视图名称前后加上前缀和后缀来查找资源。前缀为spring.thymeleaf.prefix,后缀为spring.thymeleaf.suffix。前缀和后缀的值分别默认为“ classpath:/ templates /”和“ .html”。您可以通过提供同名的 bean 来覆盖ThymeleafViewResolver
  • 如果使用 FreeMarker,则还有一个FreeMarkerViewResolver名为“ freeMarkerViewResolver”。它通过在视图名称前加上前缀和后缀来在加载程序路径(外部化为spring.freemarker.templateLoaderPath且默认值为“ classpath:/ templates /”)中查找资源。前缀外部化为spring.freemarker.prefix,后缀外部化为spring.freemarker.suffix。前缀和后缀的默认值分别为空和’.ftl’。您可以通过提供同名的 bean 来覆盖FreeMarkerViewResolver
  • 如果您使用 Groovy 模板(实际上,如果groovy-templates在 Classpath 上),则您也有一个GroovyMarkupViewResolver,名为“ groovyMarkupViewResolver”。它通过在视图名称前加上前缀和后缀(扩展为spring.groovy.template.prefixspring.groovy.template.suffix)来在加载程序路径中查找资源。前缀和后缀分别具有默认值’classpath:/ templates /‘和’.tpl’。您可以通过提供同名的 bean 来覆盖GroovyMarkupViewResolver

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

使用SpringSecurity进行测试

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

1
2
3
4
5
6
7
@Test
@WithMockUser(roles="ADMIN")
public void requestProtectedUrlWithUser() throws Exception {
mvc
.perform(get("/"))
...
}

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

有关 Spring Security 的测试支持的更多详细信息,请参阅 Spring Security 的reference documentation

Jersey

使用SpringSecurity的安全Jersey端点

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

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

1
2
3
4
5
6
7
8
9
10
@Component
public class JerseyConfig extends ResourceConfig {

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

}

HTTPClient端

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

配置RestTemplate以使用代理

第 34.1 节“ RestTemplate 自定义”中所述,您可以将RestTemplateCustomizerRestTemplateBuilder结合使用来构建自定义的RestTemplate。建议使用此方法来创建配置为使用代理的RestTemplate

代理配置的确切详细信息取决于所使用的基础 Client 端请求工厂。以下示例将HttpComponentsClientRequestFactoryHttpClient配置为对192.168.0.5以外的所有主机使用代理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static class ProxyCustomizer implements RestTemplateCustomizer {

@Override
public void customize(RestTemplate restTemplate) {
HttpHost proxy = new HttpHost("proxy.example.com");
HttpClient httpClient = HttpClientBuilder.create()
.setRoutePlanner(new DefaultProxyRoutePlanner(proxy) {

@Override
public HttpHost determineProxy(HttpHost target,
HttpRequest request, HttpContext context)
throws HttpException {
if (target.getHostName().equals("192.168.0.5")) {
return null;
}
return super.determineProxy(target, request, context);
}

}).build();
restTemplate.setRequestFactory(
new HttpComponentsClientHttpRequestFactory(httpClient));
}

}

Logging

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

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

Spring Boot 具有LoggingSystem抽象,该抽象试图基于 Classpath 的内容配置日志记录。如果可以使用 Logback,则它是首选。

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

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

您还可以使用“ logging.file”设置日志的文件位置(控制台除外)。

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

配置日志记录的日志回传

如果将logback.xml放在 Classpath 的根目录中,则从那里(或从logback-spring.xml拾取它,以利用 Boot 提供的模板功能)。 Spring Boot 提供了一个默认的基本配置,如果您想设置级别,可以将其包括在内,如以下示例所示:

1
2
3
4
5
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<logger name="org.springframework.web" level="DEBUG"/>
</configuration>

如果您在 spring-boot jar 中查看base.xml,您会发现它使用了一些有用的 System 属性,而LoggingSystem会为您创建这些属性:

  • ${PID}:当前进程 ID。
  • ${LOG_FILE}:是否在 Boot 的外部配置中设置了logging.file
  • ${LOG_PATH}:是否在 Boot 的外部配置中设置了logging.path(表示要存放日志文件的目录)。
  • ${LOG_EXCEPTION_CONVERSION_WORD}:是否在 Boot 的外部配置中设置了logging.exception-conversion-word

通过使用自定义的 Logback 转换器,Spring Boot 还可以在控制台上提供一些不错的 ANSI 颜色终端输出(但不在日志文件中)。有关详细信息,请参见默认的base.xml配置。

如果 Groovy 在 Classpath 上,那么您也应该能够使用logback.groovy配置 Logback。如果存在,则优先考虑此设置。

为仅文件输出配置Logback

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

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>

您还需要将logging.file添加到application.properties,如以下示例所示:

1
logging.file=myapplication.log

配置Log4j进行日志记录

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<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 中设置启动器的一种方法:

1
2
3
4
5
6
7
8
9
10
dependencies {
compile 'org.springframework.boot:spring-boot-starter-web'
compile 'org.springframework.boot:spring-boot-starter-log4j2'
}

configurations {
all {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
}
}

Note

Log4j Starter 人员将依赖关系集中在一起,以满足常见的日志记录要求(例如让 Tomcat 使用java.util.logging,但使用 Log4j 2 配置输出)。有关详细信息,请参见Actuator Log4j 2示例,并查看实际效果。

Note

为了确保将使用java.util.logging执行的调试日志记录路由到 Log4j 2 中,可以通过将java.util.logging.manager系统属性设置为org.apache.logging.log4j.jul.LogManager来配置其JDK 记录适配器

使用YAML或JSON配置Log4j 2

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

Format Dependencies File names
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

数据访问

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

配置自定义数据源

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

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

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

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

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

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

Spring Boot 还提供了一个名为DataSourceBuilderUtil 生成器类,该类可用于创建标准数据源之一(如果它在 Classpath 中)。构建器可以根据 Classpath 上可用的内容来检测要使用的一个。它还基于 JDBC URL 自动检测驱动程序。

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

1
2
3
4
5
@Bean
@ConfigurationProperties("app.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}

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

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

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

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

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

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
@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转换,因此您可以按以下方式进行配置:

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

Tip

Spring Boot 会将针对 Hikari 的设置公开给spring.datasource.hikari。本示例使用更通用的configuration子命名空间,因为该示例不支持多个数据源实现。

Note

由于您的自定义配置选择使用 Hikari,因此app.datasource.type无效。实际上,将使用您可以在此处设置的任何值初始化构建器,然后通过对.type()的调用来覆盖构建器。

有关更多详细信息,请参见“ Spring Boot 功能”部分和DataSourceAutoConfiguration类中的“ 配置数据源”。

配置两个数据源

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Bean
@Primary
@ConfigurationProperties("app.datasource.first")
public DataSourceProperties firstDataSourceProperties() {
return new DataSourceProperties();
}

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

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

Tip

firstDataSourceProperties必须标记为@Primary,以便数据库初始化程序功能使用您的副本(如果使用初始化程序)。

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

1
2
3
4
5
6
7
8
9
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,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Bean
@Primary
@ConfigurationProperties("app.datasource.first")
public DataSourceProperties firstDataSourceProperties() {
return new DataSourceProperties();
}

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

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

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

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

使用Spring数据存储库

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

对于许多应用程序,您所需要做的就是将正确的 Spring Data 依赖项放在 Classpath 上(对于 JPA,有spring-boot-starter-data-jpa;对于 Mongodb 是spring-boot-starter-data-mongodb),并创建了一些存储库接口来处理@Entity对象。示例在JPA sampleMongodb sample中。

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

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

将Entity注解定义与Spring配置分开

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

1
2
3
4
5
6
7
8
@Configuration
@EnableAutoConfiguration
@EntityScan(basePackageClasses=City.class)
public class Application {

//...

}

配置JPA属性

Spring Data JPA 已经提供了一些独立于供应商的配置选项(例如用于 SQL 日志记录的那些),并且 Spring Boot 公开了这些选项,还为 Hibernate 提供了一些其他选项作为外部配置属性。其中一些会根据上下文自动检测到,因此您不必进行设置。

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

还会根据当前的DataSource自动检测要使用的方言,但是如果您要明确表示并绕过启动检查,则可以自己设置spring.jpa.database

Note

指定database将导致配置良好的 Hibernate 方言。多个数据库有多个Dialect,这可能不满足您的需求。在这种情况下,您可以将spring.jpa.database设置为default以便让 Hibernate 弄清楚,也可以通过设置spring.jpa.database-platform属性来设置方言。

以下示例显示了最常用的设置选项:

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

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

Tip

如果您需要对 Hibernate 属性应用高级自定义,请考虑在创建EntityManagerFactory之前注册将被调用的HibernatePropertiesCustomizer bean。这优先于自动配置应用的任何内容。

配置Hibernate命名策略

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

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

例如,一个TelephoneNumber实体被 Map 到telephone_number表。

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

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

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

1
2
3
4
@Bean
public PhysicalNamingStrategy physicalNamingStrategy() {
return new PhysicalNamingStrategyStandardImpl();
}

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

配置Hibernate二级缓存

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

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

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
public class HibernateSecondLevelCacheExample {

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

}

}

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

在Hibernate组件中使用依赖注入

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

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

使用自定义EntityManagerFactory

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

使用两个EntityManager

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// add two data sources configured as above

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

@Bean
public LocalContainerEntityManagerFactoryBean orderEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
return builder
.dataSource(orderDataSource())
.packages(Order.class)
.persistenceUnit("orders")
.build();
}

Note

当您自己为LocalContainerEntityManagerFactoryBean创建bean时,在自动配置的LocalContainerEntityManagerFactoryBean创建过程中应用的所有自定义设置都将丢失。 例如,对于Hibernate,spring.jpa.hibernate前缀下的任何属性都不会自动应用于您的LocalContainerEntityManagerManagerBean。 如果您依靠这些属性来配置诸如命名策略或DDL模式之类的东西,则在创建LocalContainerEntityManagerManagerBean bean时将需要显式配置。 另一方面,如果您使用自动配置的EntityManagerFactoryBuilder构建LocalContainerEntityManagerFactoryBean bean,则将自动应用通过spring.jpa.properties指定的应用于自动配置的EntityManagerFactoryBuilder的属性。

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration
@EnableJpaRepositories(basePackageClasses = Customer.class,
entityManagerFactoryRef = "customerEntityManagerFactory")
public class CustomerConfiguration {
...
}

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

使用传统的persistence.xml文件

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

默认设置请参见JpaBaseConfiguration

使用SpringDataJPA和Mongo存储库

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

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

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

自定义SpringData的Web 支持

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

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

如果已为应用程序启用 Spring MVC,Spring Data REST 可以为您将Repository实现作为 REST 端点公开。

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

Note

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

配置JPA使用的组件

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

如果您自己配置组件,则可以使用EntityManagerFactoryDependsOnPostProcessor子类作为构建必要依赖关系的便捷方法。例如,如果您将 Hibernate Search 和 Elasticsearch 用作其索引 Management 器,则必须将任何EntityManagerFactory bean 配置为依赖elasticsearchClient bean,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* {@link EntityManagerFactoryDependsOnPostProcessor} that ensures that
* {@link EntityManagerFactory} beans depend on the {@code elasticsearchClient} bean.
*/
@Configuration
static class ElasticsearchJpaDependencyConfiguration
extends EntityManagerFactoryDependsOnPostProcessor {

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

}

使用两个数据源配置jOOQ

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

Tip

特别是,JooqExceptionTranslatorSpringTransactionProvider可以重复使用,以提供与自动配置使用单个DataSource相似的功能。

初始化数据库

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

使用JPA初始化数据库

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

  • spring.jpa.generate-ddl(布尔值)打开和关闭该功能,并且与供应商无关。
  • spring.jpa.hibernate.ddl-auto(枚举)是一种 Hibernate 功能,可以更精细地控制行为。此功能将在本指南的后面部分详细介绍。

使用Hibernate初始化数据库

您可以显式设置spring.jpa.hibernate.ddl-auto,并且标准的 Hibernate 属性值为nonevalidateupdatecreatecreate-drop。 Spring Boot 根据是否认为您的数据库已嵌入为您选择默认值。如果未检测到任何模式管理器,则默认为create-drop,否则为none。通过查看Connection类型,可以检测到嵌入式数据库。嵌入了hsqldbh2derby,其他未嵌入。从内存数据库转换为“实际”数据库时,请不要对新平台中表和数据的存在做出假设。您必须显式设置ddl-auto或使用其他机制之一来初始化数据库。

Note

您可以通过启用org.hibernate.SQLLogger 来输出架构创建。如果启用debug mode,则会自动为您完成此操作。

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

初始化数据库

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

Note

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

1
spring.datasource.initialization-mode=always

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

Note

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

初始化SpringBatch数据库

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

1
spring.batch.initialize-schema=always

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

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

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

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

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

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

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

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

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

前面的配置没有使用db/migration,而是根据数据库的类型(例如db/migration/mysql表示 MySQL)来设置要使用的文件夹。 DatabaseDriver中提供了受支持的数据库列表。

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

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

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

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

有一个Flyway sample,以便您可以了解如何进行设置。

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

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

使用该设置,只有在dev配置文件处于 Active 状态时,才能在dev/db/migration中进行迁移。

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

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

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

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

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

有一个Liquibase sample,以便您可以了解如何进行设置。

Messaging

Spring Boot 提供了许多 Starter,包括消息传递。本部分回答了将消息与 Spring Boot 一起使用所引起的问题。

禁用事务JMS会话

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

1
2
3
4
5
6
7
8
9
10
11
@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(
ConnectionFactory connectionFactory,
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory listenerFactory =
new DefaultJmsListenerContainerFactory();
configurer.configure(listenerFactory, connectionFactory);
listenerFactory.setTransactionManager(null);
listenerFactory.setSessionTransacted(false);
return listenerFactory;
}

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

批处理应用程序

本部分回答了将 Spring Batch 与 Spring Boot 结合使用所引起的问题。

Note

默认情况下,批处理应用程序需要DataSource来存储作业详细信息。如果要偏离此范围,则需要实现BatchConfigurer。有关更多详细信息,请参见@EnableBatchProcessing 的 Javadoc

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

在启动时执行SpringBatch作业

通过在上下文中的某个位置添加@EnableBatchProcessing(来自 Spring Batch)来启用 Spring Batch 自动配置。

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

Tip

与命令行选项参数在环境中设置属性(即以--开头,例如--my-property=value)不同,作业参数必须在命令行上指定,而不用破折号(例如jobParam=value)。

如果应用程序上下文包括JobRegistry,则在注册表中查找spring.batch.job.names中的作业,而不是从上下文中自动装配。这是更复杂的系统的常见模式,其中多个作业在子上下文中定义并集中注册。

有关更多详细信息,请参见BatchAutoConfiguration@EnableBatchProcessing

Actuator

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

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

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

有关更多详细信息,请参见“生产就绪功能”部分中的ManagementServerProperties源代码和“ 第 54.2 节“自定义 Management 服务器端口””。

自定义“ whitelabel”错误页面

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

Note

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

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

另请参见“ Error Handling”部分,以获取有关如何在 servlet 容器中注册处理程序的详细信息。

清理合理的值

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

Spring Boot 对此类密钥使用合理的默认值:例如,对任何以单词“ password”,“ secret”,“ key”或“ token”结尾的密钥进行清理。也可以改用正则表达式,例如*credentials.*来清除将单词credentials作为关键字一部分的任何关键字。

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

Security

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

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

关闭SpringBoot安全性配置

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

更改UserDetailsService并添加用户帐户

如果提供类型AuthenticationManagerAuthenticationProviderUserDetailsService@Bean,则不会创建InMemoryUserDetailsManager的默认@Bean,因此您可以使用完整的 Spring Security 功能集(例如各种身份验证选项)。

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

在代理服务器上运行时启用HTTPS

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

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

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

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

1
2
3
4
5
6
7
8
9
10
@Configuration
public class SslWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

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

}

Hot Swapping

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

重新加载静态内容

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

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

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

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

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

Thymeleaf模板

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

FreeMarker模板

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

Groovy模板

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

快速启动应用程序

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

有关更多详细信息,请参见第 20 章,开发人员工具部分。

无需重新启动容器即可重新加载Java类

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

Build

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

生成内部版本信息

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.1.RELEASE</version>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

Tip

有关更多详细信息,请参见Spring Boot Maven 插件文档

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

1
2
3
springBoot {
buildInfo()
}

Tip

有关更多详细信息,请参见Spring Boot Gradle 插件文档

生成Git信息

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

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

1
2
3
4
5
6
7
8
<build>
<plugins>
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
</plugin>
</plugins>
</build>

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

1
2
3
plugins {
id "com.gorylenko.gradle-git-properties" version "1.5.1"
}

Tip

git.properties中的提交时间应与以下格式匹配:yyyy-MM-dd'T'HH:mm:ssZ。这是上面列出的两个插件的默认格式。使用此格式,可以将时间解析为Date,并将其序列化为 JSON 时的格式由 Jackson 的日期序列化配置设置控制。

自定义依赖关系版本

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

1
2
3
<properties>
<slf4j.version>1.7.5<slf4j.version>
</properties>

Note

仅当您的 Maven 项目(直接或间接)继承spring-boot-dependencies时,此方法才有效。如果您在自己的dependencyManagement部分中使用<scope>import</scope>添加了spring-boot-dependencies,则必须自己重新定义工件,而不是覆盖该属性。

Warning

每个 Spring Boot 版本都是针对这组特定的第三方依赖关系进行设计和测试的。覆盖版本可能会导致兼容性问题。

要覆盖 Gradle 中的依赖版本,请参阅 Gradle 插件文档中的this section

使用Maven创建可执行 JAR

spring-boot-maven-plugin可用于创建可执行的“胖” JAR。如果使用spring-boot-starter-parent POM,则可以声明插件,然后将 jar 重新打包,如下所示:

1
2
3
4
5
6
7
8
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.1.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

有关完整用法的详细信息,请参见plugin documentation

使用SpringBoot应用程序作为依赖项

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

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

为了产生两个工件,一个可以用作依赖项,另一个可以执行,必须指定分类器。该分类器应用于可执行 Files 的名称,保留默认 Files 作为依赖项。

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

1
2
3
4
5
6
7
8
9
10
11
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
</plugins>
</build>

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

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

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

Warning

应注意确保已配置 os,以便在应用程序仍在运行时不会删除已解压缩到临时目录中的 jar。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<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>

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>lib</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>lib</classifier>
<excludes>
<exclude>application.yml</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

远程调试以Maven开头的SpringBoot应用程序

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

有关更多详细信息,请参见this example

无需使用spring-boot-antlib就可以从Ant构建可执行存档

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

  • 如果要构建 jar,请将应用程序的类和资源打包在嵌套的BOOT-INF/classes目录中。如果要发动 War,请照常将应用程序的类打包在嵌套的WEB-INF/classes目录中。
  • 在 jar 的嵌套BOOT-INF/lib目录中或在 war 的WEB-INF/lib中添加运行时依赖项。记住不要压缩压缩 Files 中的条目。
  • 在 jar 的嵌套BOOT-INF/lib目录中添加provided(嵌入式容器)依赖项,对于 War 则在WEB-INF/lib-provided中添加。记住不要压缩压缩 Files 中的条目。
  • 在 Files 的根目录中添加spring-boot-loader类(以便Main-Class可用)。
  • 使用适当的启动器(例如 jar 文件的JarLauncher)作为 Lists 中的Main-Class属性,并通过设置Start-Class属性来指定它作为 Lists 条目所需的其他属性。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<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>

Ant Sample包含一个build.xml文件,该文件具有manual任务,如果使用以下命令运行该文件,该任务应该可以工作:

1
$ ant -lib <folder containing ivy-2.2.jar> clean manual

然后,您可以使用以下命令运行该应用程序:

1
$ java -jar target/*.jar

传统部署

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

创建可部署的War文件

Warning

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
@SpringBootApplication
public class Application extends SpringBootServletInitializer {

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

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

}

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

1
<packaging>war</packaging>

如果使用 Gradle,则需要修改build.gradle,以将 war 插件应用于项目,如下所示:

1
apply plugin: 'war'

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

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

1
2
3
4
5
6
7
8
9
<dependencies>
<!-- … -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- … -->
</dependencies>

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

1
2
3
4
5
dependencies {
// …
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
// …
}

Tip

providedRuntime比 Gradle 的compileOnly配置更可取。除其他限制外,compileOnly依赖项不在测试 Classpath 上,因此任何基于 Web 的集成测试都将失败。

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

Tip

查看 Spring Boot 的示例应用程序中先前配置的Maven-based example

将现有应用程序转换为SpringBoot

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

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

1
2
3
4
5
6
7
8
9
10
11
12
@SpringBootApplication
public class Application extends SpringBootServletInitializer {

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

}

请记住,无论您 Importingsources只是一个 Spring ApplicationContext。通常,任何已经起作用的东西都应该在这里工作。可能有些 bean 可以稍后删除,然后让 Spring Boot 为它们提供自己的默认值,但是应该可以使某些东西工作,然后再执行此操作。

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

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

  • 类型为ServletServletRegistrationBean@Bean将该 bean 安装在容器中,就好像它是web.xml中的<servlet/><servlet-mapping/>一样。
  • FilterFilterRegistrationBean类型的@Bean的行为类似(如<filter/><filter-mapping/>)。
  • 可以通过Application中的@ImportResource添加 XML 文件中的ApplicationContext。或者,可以在几行中将@Bean定义重新创建已经大量使用 Comments 配置的简单情况。

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

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

Note

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@SpringBootApplication
public class Application extends SpringBootServletInitializer {

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

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

private static SpringApplicationBuilder configureApplication(SpringApplicationBuilder builder) {
return builder.sources(Application.class).bannerMode(Banner.Mode.OFF);
}

}

应用程序可以分为多个类别:

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

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

如果 Servlet 3.0 应用程序已经使用了 Spring Servlet 3.0 初始化程序支持类,则它们可能很容易转换。通常,现有WebApplicationInitializer中的所有代码都可以移到SpringBootServletInitializer中。如果您现有的应用程序有多个ApplicationContext(例如,如果使用AbstractDispatcherServletInitializer),则您可以将所有上下文源组合为一个SpringApplication。您可能遇到的主要并发症是,如果合并不起作用,并且您需要维护上下文层次结构。有关示例,请参见构建层次结构的 Starter)。通常需要分解包含特定于 Web 的功能的现有父上下文,以便所有ServletContextAware组件都位于子上下文中。

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

将WAR部署到WebLogic

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

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

1
2
3
4
5
6
7
8
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.web.WebApplicationInitializer;

@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer implements WebApplicationInitializer {

}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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
http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd
http://xmlns.oracle.com/weblogic/weblogic-web-app
http://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>

使用Jedis代替Lettuce

默认情况下,Spring Boot 启动器(spring-boot-starter-data-redis)使用Lettuce。您需要排除该依赖性,而改为包含Jedis个。 Spring Boot Management 这些依赖关系,以帮助简化此过程。

以下示例显示了如何在 Maven 中执行此操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<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 中执行此操作:

1
2
3
4
5
6
7
8
configurations {
compile.exclude module: "lettuce"
}

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