Spring Boot 2 官方指导手册译文

入门

介绍 Spring Boot

Spring Boot 使您可以轻松地创建独立的、生产级的基于 Spring 的应用程序,您可以运行这些应用程序。我们对 Spring 平台和第三方库采取了固执己见的观点,这样您就可以轻松地开始,不被琐事所困扰。大多数 Spring Boot 应用程序都需要很少的 Spring 配置。

您可以使用 Spring Boot 来创建 Java 应用程序,这些应用程序可以通过使用 java -jar 或更传统的 war 部署来启动。我们还提供了一个运行“spring 脚本”的命令行工具。

我们的主要目标是:

  • 为所有 Spring 开发提供一种快速而广泛的入门体验。
  • 要固执己见地拆箱即用,但当需求开始偏离默认值时,迅速退出。
  • 提供一系列非功能特性,这些特性在大型项目中是常见的(例如嵌入式服务器、安全、指标、健康检查和外部化配置)。
  • 绝对没有代码生成,也不需要 XML 配置。

系统要求

Spring Boot 2.0.2.RELEASE 需要 Java 8(或 9)和 Spring Framework 5.0.6.RELEASE(或更高)。为 Maven 3.2+ 和 Gradle 4 提供了显式构建支持。

Servlet 容器

Spring Boot 支持以下嵌入式 servlet 容器:

名称 Servlet 版本
Tomcat 8.5 3.1
Jetty 9.4 3.1
Undertow 1.4 3.1

您还可以将 Spring Boot 应用程序部署到任何 Servlet 3.1+ 兼容的容器中。

安装 Spring Boot

Maven 安装

Spring Boot 与 Apache Maven 3.2 或以上兼容。如果您没有安装 Maven,则可以按照 maven.apache.org 的指示操作。

Spring Boot 依赖关系使用 org.springframework.boot groupId。 通常,你的 Maven POM 文件继承自 spring-boot-starter-parent 项目,并向一个或多个启动器声明依赖关系。Spring Boot 还提供了一个可选的 Maven 插件来创建可执行的 jar

下面的清单显示了一个典型的 pom.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>myproject</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <!-- Inherit defaults from Spring Boot -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.2.RELEASE</version>
    </parent>

    <!-- Add typical dependencies for a web application -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <!-- Package as an executable jar -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

spring-boot-starter-parent 是使用 Spring Boot 的一个很好的方式,但它可能并不总是合适的。有时,你需要继承自一个不同的父 POM,或者你可能不喜欢我们的默认设置。在那些情况下,查看 第 13.2.2 节:“使用不包含父 POM 的 Spring Boot” 了解使用 import scope 的替代解决方案。

Gradle 安装

Spring Boot 与 Gradle 4 兼容。如果您还没有安装 Gradle,您可以按照 gradle.org 上的说明进行操作。

Spring Boot 依赖关系可以使用 org.springframework.boot group 声明。通常,你的项目向一个或多个启动器声明依赖关系。Spring Boot 提供了一个有用的 Gradle 插件,它可以用来简化依赖项声明并创建可执行的 jar

Gradle Wrapper

当您需要构建一个项目时,Gradle Wrapper 提供了一种“获取”Gradle 的好方法。它是一个小脚本和库,您可以在代码旁边提交,以引导构建过程。有关详细信息,请参阅 docs.gradle.org/4.2.1/userguide/gradle_wrapper.html

下面的示例显示一个典型的 build.gradle 文件:

plugins {
    id 'org.springframework.boot' version '2.0.2.RELEASE'
    id 'java'
}


jar {
    baseName = 'myproject'
    version =  '0.0.1-SNAPSHOT'
}

repositories {
    jcenter()
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    testCompile("org.springframework.boot:spring-boot-starter-test")
}

从 Spring Boot 的一个早期的版本升级

如果您正在从早期的 Spring Boot 版本升级,请检查提供详细的升级说明的“迁移指南”。还要检查发行说明,以获得每个版本的“新的和值得注意的”特性。

开发你的第一个 Spring Boot 应用程序

本节描述如何开发一个简单的“Hello World!”web 应用程序突出了 Spring Boot 的一些关键特性。我们使用 Maven 来构建这个项目,因为大多数 IDE 都支持它。

spring.io 网站包含许多使用 Spring Boot 的“入门”指南。如果你需要解决一个具体的问题,先检查一下。
要简化下面的步骤,你可以去 start.spring.io 并从依赖关系搜索器中选择“Web”启动器。这样做会生成一个新的项目结构,这样您就可以立即开始编写代码。查看 Spring Initializr 文档了解更多细节。

在开始之前,打开一个终端并运行以下命令,以确保安装了有效的 Java 和 Maven 版本:

$ java -version
java version "1.8.0_102"
Java(TM) SE Runtime Environment (build 1.8.0_102-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.102-b14, mixed mode)
$ mvn -v
Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-10T16:41:47+00:00)
Maven home: /usr/local/Cellar/maven/3.3.9/libexec
Java version: 1.8.0_102, vendor: Oracle Corporation

此示例需要在其自己的文件夹中创建。随后的指令假设您已经创建了一个合适的文件夹,并且它是您当前的目录。

创建 POM

我们需要从创建一个 Maven pom.xml 文件开始。pom.xml 是用于构建你的项目的“食谱”。打开你喜欢的文本编辑器并添加如下内容:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>myproject</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.2.RELEASE</version>
    </parent>

    <!-- Additional lines to be added here... -->

</project>

前面的清单应该给您一个生效的构建。您可以通过运行 mvn package 来测试它(现在,您可以忽略“jar will be empty - no content was marked for inclusion!”警告)。

此时,您可以将项目导入到 IDE 中(大多数现代 Java IDE 都包含对 Maven 的内置支持)。为了简单起见,我们继续使用这个示例的纯文本编辑器。

添加类路径依赖项

Spring Boot 提供了一些“启动器”让你可以添加 jar 到你的类路径。我们的示例应用程序已经在 POM 的 parent 部分使用了 spring-boot-starter-parentspring-boot-starter-parent 是一个特殊的启动器,它提供了有用的 Maven 默认值。它还提供了一个 dependency-management 部分,以便对于“有福的”依赖项你可以省略版本标记。

其它“启动器”提供在开发特定类型的应用程序时可能需要的依赖项。由于我们正在开发一个 web 应用程序,所以我们添加了一个 spring-boot-starter-web 依赖项。在此之前,我们可以通过运行以下命令查看当前所拥有的内容:

$ mvn dependency:tree

[INFO] com.example:myproject:jar:0.0.1-SNAPSHOT

mvn dependency:tree 命令打印你的项目依赖项的树型表示。您可以看到 spring-boot-starter-parent 本身不提供依赖项。要添加必要的依赖项,请编辑 pom.xml 并将 spring-boot-starter-web 依赖项立即添加到 parent 部分下方:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

如果你再次运行 mvn dependency:tree,您可以看到现在有许多额外的依赖项,包括 Tomcat web 服务器和 Spring Boot 本身。

编写你的代码

要完成我们的应用程序,我们需要创建一个 Java 文件。默认情况下,Maven 从 src/main/java 编译源代码,因此您需要创建该文件夹结构,然后添加一个名为 src/main/java/Example.java 的文件,包含以下代码:

import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.web.bind.annotation.*;

@RestController
@EnableAutoConfiguration
public class Example {

    @RequestMapping("/")
    String home() {
        return "Hello World!";
    }

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

}

虽然这里没有多少代码,但仍有很多工作要做。我们将在接下来的几节中讨论重要的部分。

  1. @RestController 和 @RequestMapping 注解

    在我们的示例类上的第一个注解是 @RestController。这被称为构造型注解。它为阅读代码的人们提供了一些提示,并且为 Spring 提供了一个特定的角色。在本例中,我们的类是一个web @Controller,所以 Spring 在处理传入 web 请求时考虑它。

    @RequestMapping 注解提供了“路由”信息。它告诉 Spring,任何带有 / 路径的 HTTP 请求都应该映射到 home 方法。@RestController 注解告诉 Spring 将生成的字符串直接呈现给调用者。

    @RestController@RequestMapping 注解是 Spring MVC 注解。(它们不是特定于 Spring Boot 的。)有关更多详细信息,请参见 Spring 参考文档中的 MVC 部分

  2. @EnableAutoConfiguration 注解

    第二个类级别注解是 @EnableAutoConfiguration。这个注解告诉 Spring Boot 去“猜测”您想如何配置 Spring,这基于您添加的 jar 依赖项。因为 spring-boot-starter-web 添加了 Tomcat 和 Spring MVC,所以自动配置假设您正在开发一个 web 应用程序,并相应地设置 Spring。

    启动器和自动配置

    自动配置被设计成与“启动器”很好地工作,但是这两个概念并没有直接关联。您可以自由地选择除启动器之外的 jar 依赖项。Spring Boot 仍然尽力地自动配置您的应用程序。

  3. main 方法

    我们的应用程序的最后一部分是 main 方法。这只是遵循应用程序入口点的 Java 约定的标准方法。通过调用 run,我们的 main 方法委托给 Spring Boot 的 SpringApplication 类。SpringApplication 引导我们的应用程序启动 Spring,而 Spring 又启动了自动配置的 Tomcat web 服务器。我们需要传递 Example.class 作为 run 方法的参数,以告诉 SpringApplication 它是主要的 Spring 组件。args 数组也被传递,以暴露任何命令行参数。

运行这个示例

此时,您的应用程序应该可以工作了。因为您使用了 spring-boot-starter-parent POM,所以您有一个有用的 run 目标,您可以使用它来启动应用程序。 在根项目目录键入 mvn spring-boot:run 以启动应用程序。您应该会看到类似如下的输出:

$ mvn spring-boot:run

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::  (v2.0.2.RELEASE)
....... . . .
....... . . . (log output here)
....... . . .
........ Started Example in 2.222 seconds (JVM running for 6.514)

如果你打开一个浏览器,访问 http://localhost:8080/,你应该会看见如下输出:

Hello World!

要优雅地退出应用程序,按 ctrl-c

创建一个可执行的 jar

我们通过创建一个可以在生产中运行的完全自包含的可执行 jar 文件来完成我们的示例。可执行 jar(有时称为“fat jars”)是包含您的编译类的存档文件,以及您的代码需要运行所需的所有 jar 依赖项。

可执行的 jar 和 Java

Java 没有提供加载嵌套 jar 文件的标准方法(jar 文件本身包含在一个 jar 中)。如果您希望分发一个自包含的应用程序,这可能会有问题。

为了解决这个问题,许多开发人员使用“uber”jar。一个 uber jar 将所有应用程序依赖项的所有类打包成一个归档文件。这种方法的问题在于,很难看到应用程序中有哪些库。如果在多个 jar 中使用相同的文件名(但使用不同的内容),也会有问题。

Spring Boot 采用了一种不同的方法,让您可以直接嵌套 jar

要创建一个可执行 jar,我们需要将 spring-boot-maven-plugin 添加到我们的 pom.xml 中。要做到这一点,请在 dependencies 部分下面插入以下几行:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

spring-boot-starter-parent POM 包含 <executions> 配置以绑定 repackage 目标。如果您不使用父 POM,您需要自己声明这个配置。有关详细信息,请参见插件文档

保存你的 pom.xml 并在命令行运行 mvn package,如下所示:

$ mvn package

[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building myproject 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] .... ..
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ myproject ---
[INFO] Building jar: /Users/developer/example/spring-boot-example/target/myproject-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- spring-boot-maven-plugin:2.0.2.RELEASE:repackage (default) @ myproject ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

如果你查看 target 目录内部,你应该会看到 myproject-0.0.1-SNAPSHOT.jar,这个文件应该差不多 10MB 大小。如果你想偷看里面的内容,你可以使用 jar tvf,如下所示:

$ jar tvf target/myproject-0.0.1-SNAPSHOT.jar

你应该也会看见一个更小的名为 myproject-0.0.1-SNAPSHOT.jar.original 的文件在 target 目录下。这是在 Spring Boot 重新打包之前,Maven 创建的初始 jar 文件 。

要运行该应用程序,使用 java -jar 命令,如下所示:

$ java -jar target/myproject-0.0.1-SNAPSHOT.jar

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::  (v2.0.2.RELEASE)
....... . . .
....... . . . (log output here)
....... . . .
........ Started Example in 2.536 seconds (JVM running for 2.864)

像前面一样,要退出该应用程序,按 ctrl-c

下一步该读什么

希望这一节提供了一些 Spring Boot 基础知识,并帮助您编写自己的应用程序。如果您是面向任务的开发人员,您可能想跳到 spring.io 并查看一些入门指南来解决具体的“我如何用 Spring 实现它?”问题。我们还有 Spring Boot 特有的“如何做”参考文档。

Spring Boot 存储库也有一些您可以运行的示例。这些示例与代码的其余部分无关(也就是说,您不需要构建其余的代码来运行或使用示例)。

否则,下一个逻辑步骤是阅读 第三部分:“使用 Spring Boot”。如果你真的很不耐烦,你也可以跳过,读一下 Spring Boot 特性

使用 Spring Boot

本节将详细讨论如何使用 Spring Boot。它涵盖了诸如构建系统、自动配置以及如何运行应用程序等主题。我们还介绍了一些 Spring Boot 最佳实践。尽管 Spring Boot 没有什么特别之处(它只是您可以使用的另一个库),但是有一些建议,在接下来的时候,使您的开发过程更容易一些。

如果您开始使用 Spring Boot,那么您应该在深入这一节之前阅读入门指南。

构建系统

强烈建议您选择一个支持依赖管理的构建系统,并且可以使用发布到“Maven Central”存储库的工件。我们建议您选择 Maven 或 Gradle。可以让 Spring Boot 与其他构建系统(例如 Ant)一起工作,但是它们并不是特别受支持。

依赖管理

Spring Boot 的每一个版本都提供了它所支持的一个被整理的依赖项列表。实际上,在构建配置中,您不需要为这些依赖项提供一个版本,因为 Spring Boot 为您管理这些依赖项。当您升级 Spring Boot 本身时,这些依赖项也会以一致的方式升级。

如果需要,您仍然可以指定一个版本并覆盖 Spring Boot 的建议。

策划列表包含了 Spring Boot 可以使用的所有 spring 模块以及第三方库的改进列表。这个列表可以作为一个标准的材料清单spring-boot-dependencies),可以适用于 MavenGradle

Spring Boot 的每个版本都与 Spring 框架的一个基本版本相关联。我们强烈建议您不要指定它的版本。

Maven

Maven 用户可以从 spring-boot-starter-parent 项目继承来获得合理的默认值。父项目提供了以下特性:

  • Java 1.8 作为默认编译等级
  • UTF-8 源码编码
  • 一个依赖管理部分,继承自 spring-boot-dependencies pom,管理通用依赖项的版本。这个依赖管理允许你在自己的 pom 中使用这些依赖项时省略 <version> 标签
  • 明智的资源过滤
  • 明智的插件配置(exec pluginGit commit IDshade
  • 明智的用于 application.propertiesapplication.yml 的包含特定 profile 文件的资源过滤(比如:application-dev.propertiesapplication-dev.yml

注意,由于 application.propertiesapplication.yml 文件接受 Spring 风格的占位符 ${…​},Maven 过滤被更改为使用 @..@ 占位符。(你可以通过设置一个名为 resource.delimiter 的 Maven 属性来覆盖它。)

  1. 继承父启动器

    要配置你的项目继承自 spring-boot-starter-parent,设置 parent 如下所示:

    <!-- Inherit defaults from Spring Boot -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.2.RELEASE</version>
    </parent>
    

    您应该仅在此依赖项上指定 Spring Boot 版本号。如果您导入额外的启动器,您可以安全地省略版本号。

    通过这种设置,您还可以通过在自己的项目中覆盖一个属性来覆盖单个依赖项。例如,要升级到另一个 Spring Data release train,您需要将以下内容添加到您的 pom.xml

    <properties>
        <spring-data-releasetrain.version>Fowler-SR2</spring-data-releasetrain.version>
    </properties>
    

    检查 spring-boot-dependencies pom 获取支持的属性列表。

  2. 使用没有父 POM 的 Spring Boot

    不是每个人都喜欢继承自 spring-boot-starter-parent POM。您可能有您自己的企业标准父类,您需要使用它们,或者您可能倾向于显式地声明所有的 Maven 配置。

    如果你不想使用 spring-boot-starter-parent,您仍然可以使用 scope=import 依赖项来保持依赖管理(但不是插件管理)的好处:

    <dependencyManagement>
            <dependencies>
            <dependency>
                <!-- Import dependency management from Spring Boot -->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.0.2.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    

    前面的示例设置不允许您使用属性来覆盖单个依赖项,如上所述。要实现相同的结果,您需要在 spring-boot-dependencies 条目之前在您的项目的依赖项管理中添加一个条目。例如,要升级到另一个 Spring Data release train,您可以将以下元素添加到您的 pom.xml

    <dependencyManagement>
        <dependencies>
            <!-- Override Spring Data release train provided by Spring Boot -->
            <dependency>
                <groupId>org.springframework.data</groupId>
                <artifactId>spring-data-releasetrain</artifactId>
                <version>Fowler-SR2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.0.2.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    

    在前面的示例中,我们指定了一个 BOM,但是任何依赖类型都可以以相同的方式被覆盖。

  3. 使用 Spring Boot Maven 插件

    Spring Boot 包含了一个 Maven 插件可以将项目打包成一个可执行的 jar。如果你想使用它,添加该插件到你的 <plugins> 部分,如下示例所示:

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    

    如果你使用 Spring Boot 启动器父 pom,你只需要添加该插件。没有其它需要配置的东西,除非你想修改父 pom 中定义的设置。

Gradle

要了解搭配 Gradle 来使用 Spring Boot,请参考 Spring Boot 的 Gradle 插件文档:

启动器

启动器是一组方便的依赖关系描述符,您可以在应用程序中包括这些描述符。您可以获取为所有 Spring 和相关技术提供一站式服务,而无需通过示例代码和复制粘贴的依赖描述符来进行搜索。例如,如果您想要开始使用 Spring 和 JPA 进行数据库访问,请在项目中包含 spring-boot-starter-data-jpa 依赖项。

启动器包含大量的依赖项,您需要通过一个一致的、受支持的管理传递依赖集来快速地启动项目并运行。

名字里包含了什么

所有官方的启动器都遵循类似的命名模式:spring-boot-starter-*,其中 * 是一种特殊类型的应用程序。这种命名结构旨在帮助您找到启动器。许多 IDE 中的 Maven 集成让您可以通过名称搜索依赖项。例如,如果安装了适当的 Eclipse 或 STS 插件,您可以在 POM 编辑器中按下 ctrl-space,并在一个完整的列表中键入“spring-boot-starter”。

正如在“创建你自己的启动器”部分中所解释的,第三方启动器不应该从 spring-boot 开始,因为它是为官方 Spring Boot 工件预留的。相反,第三方启动器通常以项目的名称开始。例如,一个名为 thirdpartyproject 的第三方启动项目通常会被命名为 thirdpartyproject-spring-boot-starter

下面列举的应用程序启动器,由 Spring Boot 提供,位于 org.springframework.boot group 下:

名称 描述 Pom
spring-boot-starter 核心启动器,保留自动配置支持、日志和 YAML Pom
spring-boot-starter-activemq 用于使用 Apache ActiveMQ 进行 JMS 消息传递 Pom
spring-boot-starter-amqp 用于使用 Spring AMQP 和 Rabbit MQ Pom
spring-boot-starter-aop 用于使用 Spring AOP 和 AspectJ 进行面向切面编程 Pom
spring-boot-starter-artemis 用于使用 Apache Artemis 进行 JMS 消息传递 Pom
spring-boot-starter-batch 用于使用 Spring Batch Pom
spring-boot-starter-cache 用于使用 Spring Framework 的缓存支持 Pom
spring-boot-starter-cloud-connectors 用于使用 Spring Cloud Connectors,它简化了与云平台里的服务的连接,如 Cloud Foundry 和 Heroku Pom
spring-boot-starter-data-cassandra 用于使用 Cassandra 分布式数据库和 Spring Data Cassandra Pom
spring-boot-starter-data-cassandra-reactive 用于使用 Cassandra 分布式数据库和 Spring Data Cassandra Reactive Pom
spring-boot-starter-data-couchbase 用于使用 Couchbase 面向文档型数据库和 Spring Data Couchbase Pom
spring-boot-starter-data-couchbase-reactive 用于使用 Couchbase 面向文档型数据库和 Spring Data Couchbase Reactive Pom
spring-boot-starter-data-elasticsearch 用于使用 Elasticsearch 搜索分析引擎和 Spring Data Elasticsearch Pom
spring-boot-starter-data-jpa 用于使用基于 Hibernate 的 Spring Data JPA Pom
spring-boot-starter-data-ldap 用于使用 Spring Data LDAP Pom
spring-boot-starter-data-mongodb 用于使用 MongoDB 面向文档型数据库和 Spring Data MongoDB Pom
spring-boot-starter-data-mongodb-reactive 用于使用 MongoDB 面向文档型数据库和 Spring Data MongoDB Reactive Pom
spring-boot-starter-data-neo4j 用于使用 Neo4j 图形数据库和 Spring Data Neo4j Pom
spring-boot-starter-data-redis 用于使用 Redis 键值对数据存储,以及 Spring Data Redis 和 Lettuce 客户端 Pom
spring-boot-starter-data-redis-reactive 用于使用 Redis 键值对数据存储,以及 Spring Data Redis reactive 和 Lettuce 客户端 Pom
spring-boot-starter-data-rest 用于使用 Spring Data Rest 通过 REST 暴露 Spring Data 仓库 Pom
spring-boot-starter-data-solr 用于使用 Apache Solr 搜索平台以及 Spring Data Solr Pom
spring-boot-starter-freemarker 用于使用 FreeMarker 视图构建 MVC web 应用程序 Pom
spring-boot-starter-groovy-templates 用于使用 Groovy Templates 视图构建 MVC web 应用程序 Pom
spring-boot-starter-hateoas 用于构建基于超媒体的 RESTful web 应用程序,使用 Spring MVC 和 Spring HATEOAS Pom
spring-boot-starter-integration 用于使用 Spring Integration Pom
spring-boot-starter-jdbc 用于使用 JDBC 以及 HikariCP 连接池 Pom
spring-boot-starter-jersey 用于构建 RESTful web 应用程序,使用 JAX-RS 和 Jersey。spring-boot-starter-web 的另一种选择。 Pom
spring-boot-starter-jooq 用于使用 jOOQ 访问 SQL 数据库。spring-boot-starter-data-jpaspring-boot-starter-jdbc 的另一种选择。 Pom
spring-boot-starter-json 用于读写 json Pom
spring-boot-starter-jta-atomikos 用于使用 Atomikos JTA 事务 Pom
spring-boot-starter-jta-bitronix 用于使用 Bitronix JTA 事务 Pom
spring-boot-starter-jta-narayana 用于使用 Narayana JTA 事务 Pom
spring-boot-starter-mail 用于使用 Java Mail 和 Spring Framework 的 email 发送支持 Pom
spring-boot-starter-mustache 用于使用 Mustache 视图构建 web 应用程序 Pom
spring-boot-starter-quartz 用于使用 Quartz 调度程序 Pom
spring-boot-starter-security 用于使用 Spring Security Pom
spring-boot-starter-test 用于测试 Spring Boot 应用程序,包括 JUnit、Hamcrest 和 Mockito 库 Pom
spring-boot-starter-thymeleaf 用于使用 Thymeleaf 视图构建 MVC web 应用程序 Pom
spring-boot-starter-validation 用于使用基于 Hibernate Validator 的 Java Bean 校验程序 Pom
spring-boot-starter-web 用于构建 web,包括 RESTful 和使用 Spring MVC 的应用程序。使用 Tomcat 作为默认内置容器 Pom
spring-boot-starter-web-services 用于使用 Spring Web Services Pom
spring-boot-starter-webflux 用于构建 WebFlux 应用程序,使用 Spring Framework 的 Reactive Web 支持 Pom
spring-boot-starter-websocket 用于构建 WebSocket 应用程序,使用 Spring Framework 的 WebSocket 支持 Pom

除了应用程序启动器之外,下面的启动器还可以用于添加生产就绪特性:

名称 描述 Pom
spring-boot-starter-actuator 用于使用 Spring Boot 的 Actuator 提供生产就绪特性,帮助您监视和管理应用程序 Pom

最后,Spring Boot 还包括以下启动器,如果您想要排除或交换特定的技术方面,可以使用:

名称 描述 Pom
spring-boot-starter-jetty 用于使用 Jetty 作为内置 servlet 容器。spring-boot-starter-tomcat 的另一种选择。 Pom
spring-boot-starter-log4j2 用于使用 Log4j2 记录日志。spring-boot-starter-logging 的另一种选择。 Pom
spring-boot-starter-logging 用于logging 使用 Logback. Default logging starter Pom
spring-boot-starter-reactor-netty 用于使用 Reactor Netty 作为内置响应式 HTTP 服务器。 Pom
spring-boot-starter-tomcat 用于使用 Tomcat 作为内置 servlet 容器。spring-boot-starter-web 使用的默认 servlet 容器启动器。 Pom
spring-boot-starter-undertow 用于使用 Undertow 作为内置 servlet 容器。spring-boot-starter-tomcat 的另一种选择。 Pom

有关附加社区贡献的启动器列表,请参阅 Github 上的 spring-boot-starters 模块中的自述文件

组织你的代码

Spring Boot 不需要任何特定的代码布局来工作。然而,有一些最佳实践可以提供帮助。

使用“default”包

当一个类不包含包声明时,它被认为是在“default 包”中。使用“default 包”通常是不鼓励的,应该避免使用。它可能会导致使用 @ComponentScan@EntityScan@SpringBootApplication 注解的 Spring Boot 应用程序的特定问题,因为每个 jar 的每个类都被读取。

我们建议您遵循 Java 推荐的包命名约定,并使用一个反向的域名(例如,com.example.project)。

定位主应用程序类

我们通常建议您在其他类之上的根包中定位主应用程序类。@SpringBootApplication 注解通常放在主类上,它隐式地为某些项定义了一个基本的“搜索包”。例如,如果您正在编写一个 JPA 应用程序,则使用 @SpringBootApplication 注解类的包来搜索 @Entity 项。使用根包也允许组件扫描只应用于您的项目。

如果您不想使用 @SpringBootApplication,那么 @EnableAutoConfiguration@ComponentScan 注解将定义该行为,因此您也可以使用它。

下面的清单展示了一个典型的布局:

com
 +- example
     +- myapplication
         +- Application.java
         |
         +- customer
         |   +- Customer.java
         |   +- CustomerController.java
         |   +- CustomerService.java
         |   +- CustomerRepository.java
         |
         +- order
             +- Order.java
             +- OrderController.java
             +- OrderService.java
             +- OrderRepository.java

Application.java 文件会声明 main 方法,以及基础的 @SpringBootApplication,如下所示:

package com.example.myapplication;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

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

}

配置类

Spring Boot 支持基于 Java 的配置。虽然可以使用 XML 源码的 SpringApplication,但是我们通常建议您的主源是一个 @Configuration 类。通常,定义主方法的类是一个很好的候选者,作为主要的 @Configuration

许多 Spring 配置示例已经在 Internet 上发布,它们使用 XML 配置。如果可能,始终尝试使用等效的基于 Java 的配置。搜索 Enable* 注解可能是一个很好的起点。

导入附加的配置类

你不需要把你所有的 @Configuration 放入单一的类中。@Import 注解可用来导入附加的配置类。替代地,你可以使用 @ComponentScan 自动拾取所有的 Spring 组件,包括 @Configuration 类。

导入 XML 配置

如果你必须使用基于 XML 的配置,我们推荐你仍然从 @Configuration 类开始。你可以使用 @ImportResource 注解加载 XML 配置文件。

自动配置

Spring Boot 自动配置尝试根据您添加的 jar 依赖项自动配置 Spring 应用程序。例如,如果 HSQLDB 在您的类路径上,并且您没有手动配置任何数据库连接 bean,那么 Spring Boot 将自动配置内存数据库。

通过将 @EnableAutoConfiguration@SpringBootApplication 注解添加到您的一个 @Configuration 类中,您需要选择加入到自动配置(原文:You need to opt-in to auto-configuration)。

您应该只添加一个 @SpringBootApplication@EnableAutoConfiguration 注解。我们通常建议只在主 @Configuration 类中添加其中一个。

逐步取代自动配置

自动配置是非侵入性的。在任何时候,您都可以开始定义自己的配置来替换自动配置的特定部分。例如,如果您添加了自己的 DataSource bean,默认的嵌入式数据库支持就会被取代。

如果您需要了解当前正在应用的自动配置,以及为什么。使用 --debug 开关启动应用程序。这样做可以为一些核心日志记录器开始调试日志,并将条件报告记录到控制台。

禁用特定的自动配置类

如果你发现你不想应用的特定自动配置类,你可以使用 @EnableAutoConfigurationexclude 属性禁用它们,如下示例所示:

import org.springframework.boot.autoconfigure.*;
import org.springframework.boot.autoconfigure.jdbc.*;
import org.springframework.context.annotation.*;

@Configuration
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class MyConfiguration {
}

如果那个类不在类路径,你可以使用这个注解的 excludeName 属性,指定完整的全类名。最后,您还可以通过使用 spring.autoconfigure.exclude property 来控制需要排除的自动配置类的列表。

你可以同时使用注解级别和 property 定义排除项。

Spring Bean 和依赖注入

您可以自由使用任何标准 Spring 框架技术来定义 bean 及其注入的依赖项。为了简单起见,我们经常发现使用 @ComponentScan(找到您的 bean)和使用 @Autowired(进行构造函数注入)工作得很好。

如果按照上面建议的方式构造代码(在根包中定位应用程序类),可以不带任何参数添加 @ComponentScan。所有应用程序组件(@Component@Service@Repository@Controller 等)都自动注册为 Spring bean。

下面的示例显示了使用构造函数注入来获得所需的 RiskAssessor Bean 的 @Service Bean:

package com.example.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class DatabaseAccountService implements AccountService {

    private final RiskAssessor riskAssessor;

    @Autowired
    public DatabaseAccountService(RiskAssessor riskAssessor) {
        this.riskAssessor = riskAssessor;
    }

    // ...

}

如果一个 Bean 只有一个构造函数,你可以省略 @Autowired,如下示例所示:

@Service
public class DatabaseAccountService implements AccountService {

    private final RiskAssessor riskAssessor;

    public DatabaseAccountService(RiskAssessor riskAssessor) {
        this.riskAssessor = riskAssessor;
    }

    // ...

}

注意,使用构造函数注入时,可以将 riskAssessor 字段标记为 final,表示它不能在之后被修改。

使用 @SpringBootApplication 注解

许多 Spring Boot 开发者喜欢在他们的应用中使用自动配置、组件扫描,并且能够在他们的“application class”上定义额外配置。单个 @SpringBootApplication 注解即可以用来开启上述三个特性,即:

  • @EnableAutoConfiguration:开启 Spring Boot 的自动配置机制
  • @ComponentScan:在应用程序的包上开启 @Component 扫描(查看最佳实践
  • @Configuration:允许在上下文注册额外的 bean,或者导入额外的配置类

@SpringBootApplication 相当于使用默认属性的 @Configuration@EnableAutoConfiguration@ComponentScan,如下示例所示:

package com.example.myapplication;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication // same as @Configuration @EnableAutoConfiguration @ComponentScan
public class Application {

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

}

@SpringBootApplication 也提供了别名去定制 @EnableAutoConfiguration@ComponentScan 的属性。

这些特性都不是强制性的,您可以选择用它支持的任何特性来替换这个注解。例如,您可能不想在应用程序中使用组件扫描:

package com.example.myapplication;

import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@EnableAutoConfiguration
@Import({ MyConfig.class, MyAnotherConfig.class })
public class Application {

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

}

在本例中,应用程序和其他 Spring Boot 应用程序一样,只是没有自动检测到 @Component 注解的类,而用户定义的 bean 是显式导入的(参见 @Import)。

运行你的应用程序

将您的应用程序打包为 jar 并使用嵌入式 HTTP 服务器的最大优点之一是,您可以像对待其他应用程序一样运行应用程序。调试 Spring Boot 应用程序也很简单。您不需要任何特殊的 IDE 插件或扩展。

本节只讨论基于 jar 的打包。如果您选择将应用程序打包为 war 文件,则应该参考服务器和 IDE 文档。

从 IDE 运行

您可以从 IDE 运行 Spring Boot 应用程序,作为简单的 Java 应用程序。但是,您首先需要导入您的项目。导入步骤取决于您的 IDE 和构建系统。大多数 IDE 可以直接导入 Maven 项目。例如,Eclipse 用户可以选择 File 菜单的 Import…Existing Maven Projects

如果不能直接将项目导入到 IDE 中,那么可以使用构建插件生成 IDE 元数据。Maven 包含 EclipseIDEA 的插件。Gradle 提供各种 IDE 的插件。

如果您不小心运行了两次 web 应用程序,您会看到一个“Port already in use”错误。STS 用户可以使用 Relaunch 按钮而不是 Run 按钮来确保任何现有实例都已关闭。

作为打包应用程序运行

如果您使用 Spring Boot Maven 或 Gradle 插件来创建一个可执行 jar,您可以使用 java -jar 运行您的应用程序,如下面的例子所示:

$ java -jar target/myapplication-0.0.1-SNAPSHOT.jar

还可以运行具有远程调试支持的打包应用程序。这样做可以将调试器附加到您的打包应用程序中,如下面的示例所示:

$ java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n \
       -jar target/myapplication-0.0.1-SNAPSHOT.jar

使用 Maven 插件

Spring Boot Maven 插件包含一个 run 目标,可以用来快速编译和启动你的应用程序。应用程序以展开的方式运行,正如它们在你的 IDE 中所做的那样。下面的示例显示一个典型的 Maven 命令来运行 Spring Boot 应用程序:

$ mvn spring-boot:run

您可能还希望使用 MAVEN_OPTS 操作系统环境变量,如下例所示:

$ export MAVEN_OPTS=-Xmx1024m

使用 Gradle 插件

Spring Boot Gradle 插件还包括一个 bootRun 任务,它可以用来以一个展开的形式运行您的应用程序。当您应用 org.springframework.boot 和 java 插件时,将添加 bootRun 任务。如下例所示:

$ gradle bootRun

您可能还想使用 JAVA_OPTS 操作系统环境变量,如下例所示:

$ export JAVA_OPTS=-Xmx1024m

热交换

由于 Spring Boot 应用程序只是普通的 Java 应用程序,所以 JVM 热交换应该可以开箱即用。JVM 热交换在一定程度上限制了它可以替换的字节码。对于更完整的解决方案,可以使用 JRebel

spring-boot-devtools 模块还包括对快速应用程序重启的支持。查看本章后面的开发者工具部分和如何做热交换获取详细信息。

开发者工具

Spring Boot 包括一组额外的工具,这些工具可以使应用程序开发体验变得更加愉快。spring-boot-devtools 模块可以包含在任何项目中,以提供额外的开发时特性。要包含 devtools 支持,请将模块依赖项添加到您的构建中,如下所示的 Maven 和 Gradle 列表:

Maven

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

Gradle

dependencies {
    compile("org.springframework.boot:spring-boot-devtools")
}

在运行完全打包的应用程序时,开发者工具会自动被禁用。如果您的应用程序是从 java -jar 启动的,或者是从一个特殊的类加载器开始的,那么它就被认为是一个“生产应用程序”。在 Maven 中将依赖项标记为 optional 或 在 Gradle 使用 compileOnly 中是一种最佳实践,它可以防止 devtools 被传递到其他使用您的项目的模块中。

默认情况下,重新打包的存档不包含 devtools。如果您想要使用某个远程 devtools 特性,您需要禁用 excludeDevtools 构建属性来包含它。该属性同时支持 Maven 和 Gradle 插件。

属性默认值

Spring Boot 所支持的几个库都使用缓存来提高性能。例如,模板引擎缓存已编译的模板以避免重复解析模板文件。另外,Spring MVC 可以在服务静态资源时添加 HTTP 缓存头信息。

虽然缓存在生产中非常有益,但在开发过程中可能会产生相反的效果,使您无法看到您在应用程序中所做的更改。出于这个原因,spring-boot-devtools 在默认情况下禁用了缓存选项。

缓存选项通常在你的 application.properties 文件中配置。例如,Thymeleaf 提供了 spring.thymeleaf.cache 属性。spring-boot-devtools 模块不需要手动设置这些属性,而是自动应用合理的开发时配置。

有关 devtools 应用的属性的完整列表,请参见 DevToolsPropertyDefaultsPostProcessor

自动重启

使用 spring-boot-devtools 的应用程序在类路径更改时自动重新启动。当在 IDE 中工作时,这可能是一个有用的特性,因为它为代码更改提供了非常快速的反馈循环。默认情况下,指向一个文件夹的类路径上的任何条目都会被监控以进行更改。请注意,某些资源(如静态资产和视图模板)不需要重新启动应用程序

触发重启

当 DevTools 监视类路径资源时,触发重启的惟一方法是更新类路径。您导致要更新的类路径的方式取决于您使用的 IDE。在 Eclipse 中,保存修改后的文件会导致类路径被更新并触发重新启动。在 IntelliJ IDEA 中,构建项目(Build -> Build Project)具有相同的效果。

只要启用了 forking,您就可以使用支持的构建插件(Maven 和 Gradle)来启动应用程序,因为 DevTools 需要一个独立的应用程序类加载器才能正常运行。默认情况下,Gradle 和 Maven 在类路径上检测 DevTools 时是这样做的。

当与 LiveReload 一起使用时,自动重启非常有效。详情请参阅 LiveReload 一节。如果您使用 JRebel,自动重新启动将被禁用,以支持动态类重载。其他 devtools 特性(如 LiveReload 和 property overrides)仍然可以使用。

DevTools 依赖于应用程序上下文的关闭钩子在重新启动时关闭它。如果您已经禁用了关闭钩子(SpringApplication.setRegisterShutdownHook(false)),那么它将无法正常工作。

当决定是否在类路径上的条目发生更改时触发重新启动时,DevTools 会自动忽略名为 spring-bootspring-boot-devtoolsspring-boot-autoconfigurespring-boot-actuatorspring-boot-starter 的项目。

DevTools 需要自定义 ApplicationContext 所使用的 ResourceLoader。如果您的应用程序已经提供了一个,那么它将被打包。不支持在 ApplicationContext 上直接覆盖 getResource 方法。

重启和重新加载

Spring Boot 提供的重启技术使用两个类加载器。不改变的类(例如,来自第三方 jar 的类)被加载到一个基类加载器中。正在积极开发的类被加载到重启类加载器中。当应用程序重新启动时,重启类加载器将被丢弃,并创建一个新的类加载器。这种方法意味着应用程序重新启动通常要比“冷启动”快得多,因为基类加载器已经可用并填充了。

如果您发现重新启动对应用程序不够快,或者遇到了类加载问题,那么您可以考虑重新加载技术,例如从 ZeroTurnaround 转向 JRebel。这些工作通过重写类,使它们更适合重载。

  1. 记录状态评估的变化(Logging changes in condition evaluation)

    默认情况下,每次应用程序重新启动时,都会记录显示状态评估增量的报告。报告显示了在进行更改(如添加或删除 bean 和设置配置属性)时对应用程序的自动配置的更改。

    若要禁用报告的日志记录,请设置以下属性:

    spring.devtools.restart.log-condition-evaluation-delta=false
    
  2. 排除资源

    某些资源在更改时不一定需要触发重新启动。例如,Thymeleaf 模板可以就地编辑。默认情况下,/META-INF/maven/META-INF/resources/resources/static/public/templates 不会触发重新启动,而是触发 live reload。如果你想要自定义这些排除项,你可以使用 spring.devtools.restart.exclude 属性。例如,只排除 /static/public 可以这样设置:

    spring.devtools.restart.exclude=static/**,public/**
    

    如果你想要保留默认设置并添加额外的排除项,使用 spring.devtools.restart.additional-exclude 替代它。

  3. 观察附加路径

    你可能希望当你对不在类路径上的文件进行更改时,重新启动或加载你的应用程序。要这样,使用 spring.devtools.restart.additional-paths 属性配置要观察变化的附加路径。您可以使用上面提到的 spring.devtools.restart.exclude 属性来控制在附加路径下的更改是否会触发完全重启或 live reload

  4. 禁用重启

    如果您不想使用重启功能,您可以使用 spring.devtools.restart.enabled 属性禁用它。在大多数情况下,您可以在 application.properties 中设置此属性(这样做仍然初始化重启类加载器,但它不观察文件的更改)。

    如果您需要完全禁用重新启动支持(例如,因为它不能与特定的库一起工作),那么您需要设置 spring.devtools.restart.enabled 系统属性为 false,然后调用 SpringApplication.run(…),如下例所示:

    public static void main(String[] args) {
        System.setProperty("spring.devtools.restart.enabled", "false");
        SpringApplication.run(MyApp.class, args);
    }
    
  5. 使用一个触发文件

    如果您使用一个持续编译已更改文件的 IDE,您可能只需要在特定的时间触发重新启动。为此,您可以使用一个“触发文件”,它是一个特殊的文件,当您想要实际触发重新启动检查时,必须对其进行修改。更改文件只会触发检查,只有当 Devtools 检测到它必须做某事时才会重新启动。触发器文件可以手动更新,也可以使用 IDE 插件进行更新。

    要使用一个触发器文件,请将 spring.devtools.restart.trigger-file 属性设置为触发器文件的路径。

    您可能想要设置 spring.devtools.restart.trigger-file 作为全局设置,以便所有的项目都以相同的方式运行。

  6. 自定义重启类加载器

    如前所述,在“重启和重新加载”部分中,重新启动功能是通过使用两个类加载器实现的。对于大多数应用程序来说,这种方法运行良好。然而,它有时会导致类加载问题。

    默认情况下,IDE 中的任何开放项目都包含“重启”类加载器,任何常规的 .jar 文件都装载了“基础”类加载器。如果您在一个多模块项目中工作,而不是每个模块都导入到您的 IDE 中,您可能需要定制一些东西。为此,您可以创建一个 META-INF/spring-devtools.properties 文件。

    spring-devtools.properties 文件可以包含以 restart.excluderestart.include 为前缀的属性。include 元素是应该被拉到“重启”类加载器中的项,而 exclude 元素则是应该被推入“基础”类加载器的项。属性的值是应用于类路径的正则表达式模式,如下例所示:

    restart.exclude.companycommonlibs=/mycorp-common-[\\w-]+\.jar
    restart.include.projectcommon=/mycorp-myproj-[\\w-]+\.jar
    

    所有属性的键必须是唯一的。只有属性以 restart.include.restart.exclude. 开头,它才会被考虑。

    所有类路径的 META-INF/spring-devtools.properties 都会被加载。您可以在项目中或项目使用的库中打包文件。

  7. 已知局限性

    通过使用标准 ObjectInputStream 来反序列化的对象,重新启动功能不会很好地工作。如果需要反序列化数据,可能需要使用 Spring 的 ConfigurableObjectInputStreamThread.currentThread().getcontextclassloader()

    不幸的是,一些第三方库在不考虑上下文类加载器的情况下反序列化。如果您发现这样的问题,您需要向原始作者请求修复。

LiveReload

spring-boot-devtools 模块包含一个嵌入式的 LiveReload 服务器,当资源被更改时,它可以用来触发浏览器刷新。LiveReload 浏览器扩展可以从 livereload.com 免费提供给 Chrome、Firefox 和 Safari。

如果您不想在应用程序运行时启动 LiveReload 服务器,则可以设置 spring.devtools.livereload.enabled 属性为 false

您一次只能运行一个 LiveReload 服务器。在启动应用程序之前,确保没有其他的 LiveReload 服务器在运行。如果您在 IDE 中启动多个应用程序,那么只有第一个应用程序得到了 LiveReload 的支持。

全局设置

您可以通过添加名为 .spring-boot-devtools.properties 的文件到 $HOME 文件夹(注意文件名以“.”开头)来配置全局 devtools 设置。添加到该文件的任何属性都适用于使用 devtools 的机器上的所有 Spring Boot 应用程序。例如,要配置重新启动以始终使用触发器文件,您需要添加以下属性:

~/.spring-boot-devtools.properties.

spring.devtools.reload.trigger-file=.reloadtrigger

远程应用程序

Spring Boot 开发者工具并不局限于本地开发。在远程运行应用程序时,还可以使用几个特性。远程支持是可选的。要启用它,您需要确保将 devtools 包含在重新打包的归档文件中,如下面的清单所示:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <excludeDevtools>false</excludeDevtools>
            </configuration>
        </plugin>
    </plugins>
</build>

然后,你需要设置 spring.devtools.remote.secret 属性,如下示例所示:

spring.devtools.remote.secret=mysecret

在远程应用程序上启用 spring-boot-devtools 是一种安全风险。您不应该在生产部署上启用支持。

远程 devtools 支持分两部分提供:一个服务器端端点接受连接,一个客户端应用程序在 IDE 中运行。当 spring.devtools.remote.remote.secret 属性被设置时,服务器组件自动启用。客户端组件必须手动启动。

  1. 运行远程客户端应用程序

    远程客户端应用程序被设计为从 IDE 中运行。你需要运行 org.springframework.boot.devtools.RemoteSpringApplication,使用你链接的远程项目相同的类路径。应用程序的唯一必需参数是它连接的远程 URL。

    例如,如果您正在使用 Eclipse 或 STS,并且您有一个名为 my-app 的项目,您已经部署到 Cloud Foundry,那么您将执行以下操作:

    • 选择 Run 菜单的 Run Configurations…
    • 创建一个新的 Java Application “launch configuration”
    • 浏览 my-app 项目
    • 使用 org.springframework.boot.devtools.RemoteSpringApplication 作为主类
    • 添加 https://myapp.cfapps.ioProgram arguments(或者你的任何远程 URL)

    运行中的远程客户端可能类似于如下列表:

      .   ____          _                                              __ _ _
     /\\ / ___'_ __ _ _(_)_ __  __ _          ___               _      \ \ \ \
    ( ( )\___ | '_ | '_| | '_ \/ _` |        | _ \___ _ __  ___| |_ ___ \ \ \ \
     \\/  ___)| |_)| | | | | || (_| []::::::[]   / -_) '  \/ _ \  _/ -_) ) ) ) )
      '  |____| .__|_| |_|_| |_\__, |        |_|_\___|_|_|_\___/\__\___|/ / / /
     =========|_|==============|___/===================================/_/_/_/
     :: Spring Boot Remote :: 2.0.2.RELEASE
    
    2015-06-10 18:25:06.632  INFO 14938 --- [           main] o.s.b.devtools.RemoteSpringApplication   : Starting RemoteSpringApplication on pwmbp with PID 14938 (/Users/pwebb/projects/spring-boot/code/spring-boot-devtools/target/classes started by pwebb in /Users/pwebb/projects/spring-boot/code/spring-boot-samples/spring-boot-sample-devtools)
    2015-06-10 18:25:06.671  INFO 14938 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2a17b7b6: startup date [Wed Jun 10 18:25:06 PDT 2015]; root of context hierarchy
    2015-06-10 18:25:07.043  WARN 14938 --- [           main] o.s.b.d.r.c.RemoteClientConfiguration    : The connection to http://localhost:8080 is insecure. You should use a URL starting with 'https://'.
    2015-06-10 18:25:07.074  INFO 14938 --- [           main] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
    2015-06-10 18:25:07.130  INFO 14938 --- [           main] o.s.b.devtools.RemoteSpringApplication   : Started RemoteSpringApplication in 0.74 seconds (JVM running for 1.105)
    

    因为远程客户端使用与实际应用程序相同的类路径,它可以直接读取实际应用程序属性。这是 spring.devtools.remote.secret 属性被读取并传递给服务器进行身份验证的方法。

    使用 https:// 作为连接协议总是明智的,这样就可以加密传输并不能截获密码。

    如果需要使用代理访问远程应用程序,配置 spring.devtools.remote.proxy.hostspring.devtools.remote.proxy.port 属性。

  2. 远程更新

    远程客户端监控您的应用程序类路径,以与本地重启相同的方式进行更改。任何更新的资源都被推送到远程应用程序,并且(如果需要的话)触发重启。如果您在一个使用不本地化的云服务的特性上进行迭代,这将是很有帮助的。一般来说,远程更新和重新启动比完整的重建和部署周期要快得多。

    只在远程客户端运行时监视文件。如果在启动远程客户端之前更改一个文件,则不会将其推送到远程服务器。

打包用于生产环境的应用程序

可执行 jar 可以用于生产部署。由于它们是自包含的,所以它们也非常适合基于云的部署。

对于额外的“生产就绪”特性,如健康、审计和度量 REST 或 JMX 端点,考虑添加 spring-boot-actuator。查看 Spring Boot Actuator:生产就绪特性获取详细信息。

下一步该读什么

现在您应该了解如何使用 Spring Boot 和您应该遵循的一些最佳实践。现在,您可以深入了解特定的 Spring Boot 特性,或者您可以跳过,阅读 Spring Boot 的“生产就绪”方面的内容。

Spring Boot 特性

本节将深入介绍 Spring Boot 的详细信息。在这里,您可以了解您可能想要使用和定制的关键特性。如果您还没有这样做,您可能希望阅读“入门”和“使用 Spring Boot”部分,这样您就有了良好基础。

SpringApplication

SpringApplication 类提供了一种方便的方法来引导从 main() 方法开始的 Spring 应用程序。在许多情况下,您可以委托给静态 SpringApplication.run 方法,如下例所示:

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

当你的应用程序启动时,你应该看到类似于如下输出:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::   v2.0.2.RELEASE

2013-07-31 00:08:16.117  INFO 56603 --- [           main] o.s.b.s.app.SampleApplication            : Starting SampleApplication v0.1.0 on mycomputer with PID 56603 (/apps/myapp.jar started by pwebb)
2013-07-31 00:08:16.166  INFO 56603 --- [           main] ationConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6e5a8246: startup date [Wed Jul 31 00:08:16 PDT 2013]; root of context hierarchy
2014-03-04 13:09:54.912  INFO 41370 --- [           main] .t.TomcatServletWebServerFactory : Server initialized with port: 8080
2014-03-04 13:09:56.501  INFO 41370 --- [           main] o.s.b.s.app.SampleApplication            : Started SampleApplication in 2.992 seconds (JVM running for 3.658)

默认情况下,显示 INFO 日志消息,包括一些相关的启动细节,比如启动应用程序的用户。如果您需要一个除 INFO 之外的日志级别,您可以设置它,如日志级别

启动失败

如果您的应用程序启动失败,注册的 FailureAnalyzers 将有机会提供专用的错误消息和解决问题的具体操作。例如,如果您在端口 8080 上启动 web 应用程序,并且该端口已经在使用,您应该会看到类似于以下消息的内容:

***************************
APPLICATION FAILED TO START
***************************

Description:

Embedded servlet container failed to start. Port 8080 was already in use.

Action:

Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.

Spring Boot 提供了大量的 FailureAnalyzer 实现,您可以添加自己的

如果没有故障分析器能够处理异常,您仍然可以显示完整的情况报告,以便更好地理解错误。要做到这一点,您需要启用 debug 属性或为 org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener 启用 DEBUG 日志记录。

例如,如果您正在使用 java -jar 运行您的应用程序,您可以使调试属性如下:

$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug

定制横幅

可以通过向类路径中添加 banner.txt 文件或将 spring.banner.location 属性设置为此类文件的位置来更改在启动时打印的横幅。如果文件的编码不是 UTF-8,则可以设置 spring.banner.charset。除了文本文件之外,还可以向类路径中添加 banner.gifbanner.jpgbanner.png 图像文件,或者设置 spring.banner.image.location 属性。图像转换为 ASCII 艺术表示,并打印在任何文本横幅之上。

banner.txt 文件中, 您可以使用下列任何一个占位符:

变量 描述
${application.version} 你的应用程序版本号,如 MANIFEST.MF 中声明的。比如,Implementation-Version: 1.0 打印为 1.0
${application.formatted-version} 你的应用程序版本号,如 MANIFEST.MF 中声明的,格式化显示(被括号包裹,用 v 作前缀)。比如 (v1.0)
${spring-boot.version} 你使用的 Spring Boot 版本。比如 2.0.2.RELEASE
${spring-boot.formatted-version} 你使用的 Spring Boot 版本,格式化显示(被括号包裹,用 v 作前缀)。比如 (v2.0.2.RELEASE)
${Ansi.NAME}(或 ${AnsiColor.NAME}, ${AnsiBackground.NAME}, ${AnsiStyle.NAME} 其中 NAME 是 ANSI 转义代码的名称。查看 AnsiPropertySource 获取详细信息。
${application.title} 你的应用程序的标题,如 MANIFEST.MF 中声明的。比如 Implementation-Title: MyApp 打印为 MyApp

如果您想以编程的方式生成横幅,则可以使用 SpringApplication.setBanner(…) 方法。使用 org.springframework.boot.Banner 接口并实现您自己的 printBanner() 方法。
你也可以使用 spring.main.banner-mode 属性决定横幅是否打印在 System.outconsole) 上、发送到配置的日志记录器(log)、完全不产生(off)。

在以下名称中,打印的横幅被注册为一个单例 bean:springBootBanner

YAML 映射 offfalse,所以如果您想要禁用应用程序中的横幅,请确保添加引号,如下例所示:

spring:
  main:
      banner-mode: "off"

定制 SpringApplication

如果 SpringApplication 的默认值不符合您的喜好,您可以创建一个本地实例并自定义它。例如,要关闭横幅,你可以写:

public static void main(String[] args) {
    SpringApplication app = new SpringApplication(MySpringConfiguration.class);
    app.setBannerMode(Banner.Mode.OFF);
    app.run(args);
}

传递给 SpringApplication 的构造函数参数是 Spring bean 的配置源。在大多数情况下,这些都是对 @Configuration 类的引用,但是它们也可以是对 XML 配置的引用,或者对应该被扫描的包的引用。

也可以使用 application.properties 文件配置 SpringApplication。查看外部化配置以获取详细信息。

有关配置选项的完整列表,查看 SpringApplication Javadoc

Fluent 风格构建器 API

如果您需要构建 ApplicationContext 层次结构(包含父/子关系的多个上下文),或者您更喜欢使用“fluent”构建器 API,那么您可以使用 SpringApplicationBuilder

SpringApplicationBuilder 允许您将多个方法调用链接在一起,并包含让您创建层次结构的 parentchild 方法,如下例所示:

new SpringApplicationBuilder()
        .sources(Parent.class)
        .child(Application.class)
        .bannerMode(Banner.Mode.OFF)
        .run(args);

在创建 ApplicationContext 层次结构时,有一些限制。例如,Web 组件必须包含在子上下文内,并且在父和子上下文环境中都使用相同的 Environment。请参阅 SpringApplicationBuilder Javadoc 了解详细信息。

应用程序事件和监听器

除了通常的 Spring Framework 事件(比如 ContextRefreshedEvent)之外,SpringApplication 还会发送一些附加的应用程序事件。

在创建 ApplicationContext 之前,实际上触发了一些事件,因此不能将侦听器注册为 @Bean。您可以使用 SpringApplication.addListeners(…​) 方法或 SpringApplicationBuilder.listeners(…​) 方法注册它们。

如果您希望这些侦听器自动注册,不管应用程序是如何创建的,您都可以添加一个 META-INF/spring.factories 文件到您的项目,并通过使用 org.springframework.context.ApplicationListener 键来引用您的侦听器,如下例所示:

org.springframework.context.ApplicationListener = com.example.project.MyListener

应用程序事件按以下顺序发送:

  1. ApplicationStartingEvent,是在运行开始时发送的,但在任何处理之前,除了侦听器和初始化器的注册之外。
  2. ApplicationEnvironmentPreparedEvent,当 Environment 被使用时,在上下文被创建之前被发送。
  3. ApplicationPreparedEvent,在刷新之前发送,但是在加载 bean 定义之后。
  4. ApplicationStartedEvent,在调用上下文之后发送,但是在调用任何应用程序和命令行运行程序之前。
  5. ApplicationReadyEvent,在调用任何应用程序和命令行运行程序后发送。它表明应用程序已经准备好服务请求。
  6. ApplicationFailedEvent,如果启动时出现异常,则发送。

您通常不需要使用应用程序事件,但是知道它们的存在是很方便的。在内部,Spring Boot 使用事件来处理各种任务。

使用 Spring Framework 的事件发布机制发送应用程序事件。该机制的一部分确保在子环境中发布给侦听器的事件也会在任何祖先上下文中被发布给侦听器。因此,如果您的应用程序使用了 SpringApplication 实例的层次结构,那么侦听器可能会接收到相同类型的应用程序事件的多个实例。

为了让您的侦听器区分事件的上下文和派生上下文的事件,它应该请求将其应用程序上下文注入,然后将注入的上下文与事件上下文进行比较。可以通过实现 ApplicationContextAware 或,如果侦听器是 bean,通过使用 @Autowired 来注入上下文。

Web 环境

SpringApplication 试图为您创建合适的 ApplicationContext 类型。用于确定 WebEnvironmentType 的算法相当简单:

  • 如果 Spring MVC 存在,则使用 AnnotationConfigServletWebServerApplicationContext
  • 如果 Spring MVC 不存在,Spring WebFlux 是存在的,那么就使用一个 AnnotationConfigReactiveWebServerApplicationContext
  • 否则,使用 AnnotationConfigApplicationContext

这意味着如果您使用 Spring MVC 和来自 Spring WebFlux 的新 WebClient 在相同的应用程序中,Spring MVC 将在默认情况下使用。您可以通过调用 setWebApplicationType(WebApplicationType) 来轻松覆盖它。

还可以完全控制调用 setApplicationContextClass(…) 所使用的 ApplicationContext 类型。

在 JUnit 测试中使用 SpringApplication 时,通常需要调用 setWebApplicationType(WebApplicationType.NONE)

访问应用程序参数

如果您需要访问传递到 SpringApplication.run(…) 的应用程序参数,您可以注入一个 org.springframework.boot.ApplicationArguments bean。ApplicationArguments 接口提供了对原始 String[] 参数以及解析 optionnon-option 参数的访问,如下例所示:

import org.springframework.boot.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.stereotype.*;

@Component
public class MyBean {

    @Autowired
    public MyBean(ApplicationArguments args) {
        boolean debug = args.containsOption("debug");
        List<String> files = args.getNonOptionArgs();
        // if run with "--debug logfile.txt" debug=true, files=["logfile.txt"]
    }

}

Spring Boot 还会在 Spring Environment 中注册一个 CommandLinePropertySource。这允许您使用 @Value 注解注入单个应用程序参数。

使用 ApplicationRunner 或 CommandLineRunner

如果您需要在 SpringApplication 启动之后运行一些特定的代码,您可以实现 ApplicationRunnerCommandLineRunner 接口。两个接口都以相同的方式工作,并提供了一个单独的运行方法,在 SpringApplication.run(…) 完成之前调用。

CommandLineRunner 接口提供对应用程序参数的访问作为一个简单的字符串数组,而 ApplicationRunner 使用前面讨论的 ApplicationArguments 接口。下面的示例展示了一个使用 run 方法的 CommandLineRunner

import org.springframework.boot.*;
import org.springframework.stereotype.*;

@Component
public class MyBean implements CommandLineRunner {

    public void run(String... args) {
        // Do something...
    }

}

如果定义了多个 CommandLineRunnerApplicationRunner bean,必须以特定的顺序调用它们,那么您可以额外地实现 org.springframework.core.Ordered 接口或使用 org.springframework.core.annotation.Order 注解。

应用程序退出

每个 SpringApplication 都向 JVM 注册一个关闭钩子,以确保 ApplicationContext 在退出时优雅地关闭。可以使用所有标准的 Spring 生命周期回调函数(如 DisposableBean bean 接口或 @PreDestroy 注解)。

此外,bean 可以实现 org.springframework.boot.ExitCodeGenerator 接口,如果希望当 SpringApplication.exit() 被调用时,返回特定的退出代码。然后可以将此退出代码传递给 System.exit(),以将其作为状态代码返回,如下面的示例所示:

@SpringBootApplication
public class ExitCodeApplication {

    @Bean
    public ExitCodeGenerator exitCodeGenerator() {
        return () -> 42;
    }

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

}

此外,ExitCodeGenerator 接口也可以由异常来实现。当遇到这样的异常时,Spring Boot 返回由实现的 getExitCode() 方法提供的退出代码。

管理员特性

通过指定 spring.application.admin.enabled 属性,可以为应用程序启用与 admin 相关的特性。这将在平台 MBeanServer 上公开 SpringApplicationAdminMXBean。您可以使用该特性远程管理您的 Spring Boot 应用程序。这个特性还可以用于任何服务包装器实现。

如果您想知道应用程序正在运行哪个 HTTP 端口,请使用 local.server.port 的键获取该属性。

谨慎

在启用该特性时要注意,因为 MBean 公开了关闭应用程序的方法。

外部化配置(Externalized Configuration)

Spring Boot 允许您外部化您的配置,这样您就可以在不同的环境中使用相同的应用程序代码。您可以使用 properties 文件、YAML 文件、环境变量和命令行参数来外部化配置。属性值可以通过使用 @Value 注解直接注入到您的 bean 中,通过 Spring 的 Environment 抽象访问,或者通过 @ConfigurationProperties 绑定到结构化对象

Spring Boot 使用一种非常特殊的 PropertySource 命令,该命令旨在允许对值进行合理的覆盖。属性按以下顺序考虑:

  1. 主目录上的 Devtools 全局设置属性~/.spring-boot-devtools.properties,当 devtools 激活时)
  2. 测试上的 @TestPropertySource 注解
  3. 测试上的 @SpringBootTest#properties 注解
  4. 命令行参数
  5. 来自 SPRING_APPLICATION_JSON 的属性(嵌入在环境变量或系统属性中的内联 JSON)
  6. ServletConfig 初始化参数
  7. ServletContext 初始化参数
  8. 来自 java:comp/env 的 JNDI 属性
  9. Java 系统属性(System.getProperties()
  10. OS 环境变量
  11. RandomValuePropertySource,只在 random.* 中的属性
  12. 指定 Profile 的应用程序 properties,在打包好的 jar 之外(application-{profile}.properties 和 YAML variants)
  13. 指定 Profile 的应用程序 properties,打包在 jar 中(application-{profile}.properties 和 YAML variants)
  14. 应用程序属性,在打包好的 jar 之外(application.properties 和 YAML variants)
  15. 应用程序属性,打包在 jar 中(application.properties 和 YAML variants)
  16. @Configuration 类上的 @PropertySource 注解
  17. 默认属性(通过设置 SpringApplication.setDefaultProperties 明确规定)

为了提供一个具体的示例,假设您开发了一个使用 name 属性的 @Component,如下例所示:

import org.springframework.stereotype.*;
import org.springframework.beans.factory.annotation.*;

@Component
public class MyBean {

    @Value("${name}")
    private String name;

    // ...

}

在您的应用程序类路径(例如,在 jar 中)您可以有一个 application.properties 文件,为 name 提供一个合理的默认属性值。在新环境中运行时,可以在您的 jar 之外提供 application.properties 文件,以覆盖 name。对于一次性测试,您可以使用特定的命令行开关启动(例如,java -jar app.jar --name="Spring")。

SPRING_APPLICATION_JSON 属性可以在命令行上提供环境变量。例如:你可以在 UN*X shell 中使用如下行:

$ SPRING_APPLICATION_JSON='{"acme":{"name":"test"}}' java -jar myapp.jar

在前面的示例中,您在 Spring Environment 中最终得到了 acme.name=test。您也可以提供 JSON 如 spring.application.json 在系统属性中,如下例所示:

$ java -Dspring.application.json='{"name":"test"}' -jar myapp.jar

您还可以使用命令行参数来提供 JSON,如下面的示例所示:

$ java -jar myapp.jar --spring.application.json='{"name":"test"}'

您还可以将 JSON 作为 JNDI 变量提供,如下所示:java:comp/env/spring.application.json

配置随机值

RandomValuePropertySource 用于注入随机值(例如,在机密或测试用例中)。它可以生成 integer、long、uuid 或 string,如下面的示例所示:

my.secret=${random.value}
my.number=${random.int}
my.bignumber=${random.long}
my.uuid=${random.uuid}
my.number.less.than.ten=${random.int(10)}
my.number.in.range=${random.int[1024,65536]}

random.int* 语法是 OPEN value (,max) CLOSE,其中 OPEN,CLOSE 为任意字符、value,max 为 integer。如果 max 被提供,value 便是最小值、max 便是最大值(不包含)。

访问命令行属性

在默认情况下,SpringApplication 会转换任何命令行选项参数(也就是说,参数以 -- 开始,如 --server.port=9000)到一个属性,并将它们添加到 Spring Environment 中。如前所述,命令行属性总是优先于其他属性源。

如果您不希望将命令行属性添加到 Environment 中,您可以使用 SpringApplication.setAddCommandLineProperties(false) 禁用它们。

应用程序属性文件

SpringApplication 从以下位置的 application.properties 文件加载属性,并将它们添加到Spring Environment

  1. 当前目录的 /config 子目录
  2. 当前目录
  3. 类路径的 /config
  4. 类路径根

列表按优先顺序排序(在列表中较高的位置定义的属性覆盖在较低位置定义的属性)。

你也可以使用 YAML ('.yml') 文件代替“.properties”。

如果您不喜欢 application.properties 作为配置文件名,可以通过指定 spring.config.name 环境属性切换到另一个文件名。您还可以使用 spring.config.location 环境属性来引用一个显式的位置(它是一个以逗号分隔的目录位置或文件路径列表)。下面的示例演示如何指定不同的文件名:

$ java -jar myproject.jar --spring.config.name=myproject

下面的示例演示如何指定两个位置:

$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties

spring.config.namespring.config.location 很早就被用于确定哪些文件必须被加载,因此它们必须被定义为环境属性(通常是一个 OS 环境变量、一个系统属性或一个命令行参数)。

如果 spring.config.location 包含目录(相对于文件),它们应该以 / 结束(并且在运行时,被附加到 spring.config.name 生成的名称,包括特定于 profile 的文件名)。spring.config.location 中指定的文件是按原样使用的,不支持特定于 profile 的变体,并且被任何特定于 profile 的属性覆盖。

配置位置按相反顺序搜索。默认情况下,配置的位置是 classpath:/,classpath:/config/,file:./,file:./config/。由此产生的搜索顺序如下:

  1. file:./config/
  2. file:./
  3. classpath:/config/
  4. classpath:/

当自定义配置位置使用 spring.config.location 配置时,它们替换默认的位置。例如,如果 spring.config.location 配置为值:classpath:/custom-config/,file:./custom-config/,搜索顺序如下:

  1. file:./custom-config/
  2. classpath:custom-config/

或者,当自定义配置位置使用 spring.config.additional-location 配置时,除了默认位置外,还使用它们。在默认位置之前搜索额外的位置。例如,如果额外的位置配置为 classpath:/custom-config/,file:./custom-config/,搜索顺序如下:

  1. file:./custom-config/
  2. classpath:custom-config/
  3. file:./config/
  4. file:./
  5. classpath:/config/
  6. classpath:/

这个搜索排序允许您在一个配置文件中指定默认值,然后在另一个配置文件中选择性地覆盖这些值。您可以在位于默认位置之一的 application.properties 中为应用程序提供默认值(或您在 spring.config.name 中选择的其他 basename)。这些默认值可以在运行时被定制的位置中放置的一个不同的文件重写。

如果您使用环境变量而不是系统属性,大多数操作系统都不允许使用句号分隔的键名,但是您可以使用下划线(例如,SPRING_CONFIG_NAME 而不是 spring.config.name)。

如果应用程序在容器中运行,那么可以使用 JNDI 属性(在 java:comp/env 中)或 servlet 上下文初始化参数,而不是环境变量或系统属性。

特定于 Profile 属性

除了 application.properties 文件,特定于 profile 的属性也可以通过使用以下命名约定来定义:application-{profile}.propertiesEnvironment 中有一组默认 profile(默认情况下是 [default]),如果没有设置激活的 profile,则使用默认 profile。换句话说,如果没有显式地激活 profile,那么就会加载 application-default.properties

特定于 profile 的属性从相同的位置加载到标准 application.properties 中,特定于 profile的文件总是覆盖非特定的文件,无论特定于 profile 的文件是否在您的打包 jar 内或外部。

如果指定了多个 profile,则应用最后的策略。例如,spring.profiles.active 属性指定的 profile,在通过 SpringApplication API 配置后,被添加,因此优先。

如果您在 spring.config.location 中指定了任何文件,这些文件特定于 profile 的变体不会被考虑。如果您还想使用特定于 profile 的属性,使用在 spring.config.location 中的目录。

属性中的占位符

application.properties 中的值在使用时通过现有 Environment 进行过滤,因此您可以引用之前定义的值(例如,从系统属性)。

app.name=MyApp
app.description=${app.name} is a Spring Boot application

您还可以使用此技术创建存在于 Spring Boot 属性中的“短”变体。请参阅使用“短”命令行参数来获取详细信息。

使用 YAML 代替 Properties

YAML 是 JSON 的超集,因此,它是一种用于指定分层配置数据的方便格式。当您的类路径上有 SnakeYAML 库时,SpringApplication 类会自动支持 YAML 作为属性的替代品。

如果你使用“启动器”,SnakeYAML 是由 spring-boot-starter 自动提供的。

  1. 加载 YAML

    Spring 框架提供了两个方便的类,可以用来加载 YAML 文档。YamlPropertiesFactoryBean 将 YAML 加载为 Properties,而 YamlMapFactoryBean 将 YAML 加载为 Map

    例如,考虑以下 YAML 文档:

    environments:
        dev:
            url: http://dev.example.com
            name: Developer Setup
        prod:
            url: http://another.example.com
            name: My Cool App
    

    前面的示例将转换为以下属性:

    environments.dev.url=http://dev.example.com
    environments.dev.name=Developer Setup
    environments.prod.url=http://another.example.com
    environments.prod.name=My Cool App
    

    YAML 列表表示为 [index] 引用的属性键。例如,考虑以下 YAML:

    my:
    servers:
        - dev.example.com
        - another.example.com
    

    前面的示例将转换为这些属性:

    my.servers[0]=dev.example.com
    my.servers[1]=another.example.com
    

    要使用 Spring Boot 的 Binder 工具(这是 @ConfigurationProperties 所做的)来绑定到这样的属性,您需要在 java.util.List(或 Set)类型的目标 bean 中拥有一个属性,您要么需要提供一个 setter,要么用一个可变值初始化它。例如,下面的示例绑定到前面显示的属性:

    @ConfigurationProperties(prefix="my")
    public class Config {
    
        private List<String> servers = new ArrayList<String>();
    
        public List<String> getServers() {
            return this.servers;
        }
    }
    
  2. 在 Spring Environment 中暴露 YAML 作为 Properties

    YamlPropertySourceLoader 类可以用于在 Spring Environment 中将 YAML 作为 PropertySource 公开。这样做可以让您使用带有占位符语法的 @Value 注解来访问 YAML 属性。

  3. 多 profile 的 YAML 文档

    您可以使用 spring.profiles 键在单个文件中指定多个特定于 profile 的 YAML 文档,以指示文档何时应用,如以下示例所示:

    server:
        address: 192.168.1.100
    ---
    spring:
        profiles: development
    server:
        address: 127.0.0.1
    ---
    spring:
        profiles: production
    server:
        address: 192.168.1.120
    

    在前面的示例中,如果 development profile 是激活的,则 server.address 属性是 127.0.0.1。类似地,如果 production profile 是激活的,则 server.address 属性是 192.168.1.120。如果启用 developmentproduction profile,则该属性的值为 192.168.1.100

    如果在应用程序上下文启动时没有显式激活,则会激活默认 profile。因此,在接下来的 YAML 中,我们为 spring.security.user.password 设置了一个值,在 “default” profile 中可用:

    server:
      port: 8000
    ---
    spring:
      profiles: default
      security:
        user:
          password: weak
    

    然而,在下面的例子中,密码总是被设置,因为它没有附加到任何 profile,而且必须在必要时显式地重置所有其他 profile:

    server:
      port: 8000
    spring:
      security:
        user:
          password: weak
    

    使用 spring.profiles 元素指定的 Spring profile 可以选择性地使用 ! 字符否定。如果为单个文档指定了否定和非否定的 profile,那么至少有一个非否定的 profile 必须匹配,并且没有任何被否定的 profile 可能匹配。

  4. YAML 缺陷

    YAML 文件不能通过使用 @PropertySource 注解来加载。因此,在需要以这种方式加载值的情况下,需要使用 properties 文件。

类型安全的配置属性

使用 @Value("${property}") 注解注入配置属性有时会很麻烦,特别是如果您使用的是多个属性,或者您的数据在本质上是分层的。Spring Boot 提供了一种处理属性的替代方法,可以让强类型 bean 管理和验证应用程序的配置,如下面的示例所示:

package com.example;

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("acme")
public class AcmeProperties {

    private boolean enabled;

    private InetAddress remoteAddress;

    private final Security security = new Security();

    public boolean isEnabled() { ... }

    public void setEnabled(boolean enabled) { ... }

    public InetAddress getRemoteAddress() { ... }

    public void setRemoteAddress(InetAddress remoteAddress) { ... }

    public Security getSecurity() { ... }

    public static class Security {

        private String username;

        private String password;

        private List<String> roles = new ArrayList<>(Collections.singleton("USER"));

        public String getUsername() { ... }

        public void setUsername(String username) { ... }

        public String getPassword() { ... }

        public void setPassword(String password) { ... }

        public List<String> getRoles() { ... }

        public void setRoles(List<String> roles) { ... }

    }
}

前面的 POJO 定义了以下属性:

  • acme.enabled,默认值为 false
  • acme.remote-address,一个可以从 String 强转的类型
  • acme.security.username,使用嵌套的“security”对象,其名称由属性的名称决定。特别是,返回类型在那里没有使用,并且可能是 SecurityProperties
  • acme.security.password
  • acme.security.roles,String 集合

getter 和 setter 通常是强制的,因为绑定是通过标准的 Java bean 属性描述符,就像在 Spring MVC 中一样。在下列情况下,可以省略 setter:

  • Map,只要它们被初始化,就需要一个 getter,但不一定需要 setter,因为它们可以由绑定器进行更改。
  • 可以通过索引(通常是 YAML)或使用单个逗号分隔值(属性)来访问集合和数组。在后一种情况下,setter 是强制的。我们建议总是为这种类型添加一个 setter。如果您初始化一个集合,请确保它不是不可变的(就像前面的例子)。
  • 如果嵌套的 POJO 属性被初始化(比如前面示例中的 Security 字段),则不需要 setter。如果您希望绑定器使用它的默认构造函数来动态创建实例,那么您需要一个 setter。

有些人使用项目 Lombok 自动添加 getter 和 setter。确保 Lombok 不会为这种类型生成任何特定的构造函数,因为它是由容器自动使用来实例化对象的。
最后,只考虑标准的 Java Bean 属性,不支持对静态属性的绑定。

也可参考 @Value@ConfigurationProperties 的区别

您还需要列出在 @EnableConfigurationProperties 注解中注册的属性类,如下例所示:

@Configuration
@EnableConfigurationProperties(AcmeProperties.class)
public class MyConfiguration {
}

@ConfigurationProperties bean 以这种方式注册时,bean 有一个常规名称: <prefix>-<fqn>,其中 <prefix>@ConfigurationProperties 注解中指定的环境键前缀,<fqn> 是 bean 的完全限定名称。如果注解没有提供任何前缀,则只使用 bean 的完全限定名。
上面示例中的 bean 名称是 acme-com.example.AcmeProperties

即使前面的配置为 AcmeProperties 创建了一个常规 bean,我们建议 @ConfigurationProperties 只处理环境,特别是不从上下文注入其他 bean。已经说过,@EnableConfigurationProperties 注解也会自动地应用到您的项目中,这样就可以从 Environment 中配置任何带有 @ConfigurationProperties 的现有 bean。您可以通过确保 AcmeProperties 已经是一个 bean 来快捷地进行 MyConfiguration,如下面的示例所示:

@Component
@ConfigurationProperties(prefix="acme")
public class AcmeProperties {

    // ... see the preceding example

}

这种类型的配置与 SpringApplication 外部 YAML 配置特别有效,如下例所示:

# application.yml

acme:
    remote-address: 192.168.1.1
    security:
        username: admin
        roles:
          - USER
          - ADMIN

# additional configuration as required

要使用 @ConfigurationProperties bean,您可以像其他 bean 一样注入它们,如下例所示:

@Service
public class MyService {

    private final AcmeProperties properties;

    @Autowired
    public MyService(AcmeProperties properties) {
        this.properties = properties;
    }

    //...

    @PostConstruct
    public void openConnection() {
        Server server = new Server(this.properties.getRemoteAddress());
        // ...
    }

}

使用 @ConfigurationProperties 还可以生成可以被 IDE 使用的 metadata 文件,为您自己的键提供自动完成。详见附录 B 配置 Metadata

  1. 第三方配置

除了使用 @ConfigurationProperties 来注解一个类之外,还可以在 public @Bean 方法上使用它。当您希望将属性绑定到控件之外的第三方组件时,这样做尤其有用。

要从 Environment 属性配置 bean,请将 @ConfigurationProperties 添加到它的 bean 注册,如下例所示:

@ConfigurationProperties(prefix = "another")
@Bean
public AnotherComponent anotherComponent() {
    ...
}

another 前缀定义的任何属性都被映射到与前面的 AcmeProperties 示例类似的 AnotherComponent bean。

  1. 松散绑定

Spring Boot 使用一些松散的规则将 Environment 属性绑定到 @ConfigurationProperties bean,因此 Environment 属性名和 bean 属性名之间不需要精确匹配。常见的示例中,这是有用的,其中包括短横线分隔的环境属性(例如,context-path 绑定到 contextPath),以及大写的环境属性(例如,PORT 绑定到 port)。

例如,考虑以下 @ConfigurationProperties 类:

@ConfigurationProperties(prefix="acme.my-project.person")
public class OwnerProperties {

    private String firstName;

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

}

在前面的示例中,可以使用以下属性名称:

属性 注释
acme.my-project.person.first-name Kebab 风格,推荐使用在 .properties 和 .yml 文件中
acme.myProject.person.firstName 标准驼峰语法
acme.my_project.person.first_name 下划线符号,使用在 .properties 和 .yml 文件中的替代格式
ACME_MYPROJECT_PERSON_FIRSTNAME 大写格式,推荐系统环境变量使用

注解的 prefix 必须是 kebab 风格(小写字母、- 分隔,如 acme.my-project.person)。

属性源 简单的 List
Properties Files Camel case、kebab case 或 underscore notation Standard list syntax using [ ] or comma-separated values
YAML Files Camel case、kebab case 或 underscore notation Standard YAML list syntax or comma-separated values
Environment Variables 使用下划线作为定界符的大写格式。_ 不应该在属性名称中使用 Numeric values surrounded by underscores, such as MY_ACME_1_OTHER = my.acme[1].other
System properties Camel case、kebab case 或 underscore notation Standard list syntax using [ ] or comma-separated values
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容