# 用 Spring boot 开发

本节将更详细地介绍如何使用 Spring 引导。它涵盖了诸如构建系统、自动配置以及如何运行应用程序等主题。我们还介绍了一些引导最佳实践。虽然 Spring boot 并没有什么特别之处(它只是另一个你可以使用的库),但有一些建议,如果遵循这些建议,将使你的开发过程变得更容易一些。

如果你是从 Spring boot 开始的,那么在深入讨论这一部分之前,你可能应该阅读 开始 指南。

# 1. 建立系统

强烈建议你选择一个支持* 扶养管理 *并且可以使用发布到“ Maven Central”存储库的工件的构建系统。我们建议你选择 Maven 或 Gradle。让 Spring 引导与其他构建系统(例如 Ant)一起工作是可能的,但是它们没有得到特别好的支持。

# 1.1.依赖管理

Spring 启动的每个版本都提供了它所支持的依赖关系的精心策划的列表。在实践中,你不需要在构建配置中为这些依赖项中的任何一个提供版本,因为 Spring boot 为你管理这些依赖项。当你升级 Spring 引导本身时,这些依赖关系也会以一致的方式进行升级。

你仍然可以指定一个版本,并在需要时重写 Spring Boot 的建议。

这个精心策划的列表包含你可以在 Spring 启动时使用的所有 Spring 模块,以及第三方库的完善列表。该清单是一份标准的材料清单(spring-boot-dependencies),可用于MavenGradle

Spring 启动的每个版本都与 Spring 框架的基本版本相关联。
我们高度建议你不要指定其版本。

# 1.2. Maven

要了解如何在 Maven 中使用 Spring boot,请参阅 Spring boot 的 Maven 插件的文档:

# 1.3. Gradle

要了解如何在 Gradle 中使用 Spring boot,请参阅 Spring boot 的 Gradle 插件的文档:

# 1.4. Ant

可以使用 Apache Ant +Ivy 构建 Spring 引导项目。spring-boot-antlib“antlib”模块也可用于帮助 Ant 创建可执行 JAR。

要声明依赖关系,典型的ivy.xml文件类似于以下示例:

<ivy-module version="2.0">
    <info organisation="org.springframework.boot" module="spring-boot-sample-ant" />
    <configurations>
        <conf name="compile" description="everything needed to compile this module" />
        <conf name="runtime" extends="compile" description="everything needed to run this module" />
    </configurations>
    <dependencies>
        <dependency org="org.springframework.boot" name="spring-boot-starter"
            rev="${spring-boot.version}" conf="compile" />
    </dependencies>
</ivy-module>

一个典型的build.xml看起来像以下示例:

<project
    xmlns:ivy="antlib:org.apache.ivy.ant"
    xmlns:spring-boot="antlib:org.springframework.boot.ant"
    name="myapp" default="build">

    <property name="spring-boot.version" value="2.6.4" />

    <target name="resolve" description="--> retrieve dependencies with ivy">
        <ivy:retrieve pattern="lib/[conf]/[artifact]-[type]-[revision].[ext]" />
    </target>

    <target name="classpaths" depends="resolve">
        <path id="compile.classpath">
            <fileset dir="lib/compile" includes="*.jar" />
        </path>
    </target>

    <target name="init" depends="classpaths">
        <mkdir dir="build/classes" />
    </target>

    <target name="compile" depends="init" description="compile">
        <javac srcdir="src/main/java" destdir="build/classes" classpathref="compile.classpath" />
    </target>

    <target name="build" depends="compile">
        <spring-boot:exejar destfile="build/myapp.jar" classes="build/classes">
            <spring-boot:lib>
                <fileset dir="lib/runtime" />
            </spring-boot:lib>
        </spring-boot:exejar>
    </target>
</project>
如果你不想使用spring-boot-antlib模块,请参阅 howto.html“how-to”。

# 1.5.初学者

启动器是一组方便的依赖关系描述符,你可以将它们包含在应用程序中。你可以获得所需的所有 Spring 和相关技术的一站式服务,而无需搜索示例代码和复制粘贴依赖描述符的负载。例如,如果你希望开始使用 Spring 和 JPA 进行数据库访问,那么在你的项目中包含spring-boot-starter-data-jpa依赖项。

启动器包含许多依赖项,你需要这些依赖项才能使项目快速启动和运行,并具有一组一致的、受支持的托管传递依赖项。

名字里的含义是什么?

所有官员启动器都遵循类似的命名模式;spring-boot-starter-*,其中*是一种特定类型的应用程序。此命名结构旨在帮助你在需要查找启动器时使用。 Maven 许多 IDE 中的集成允许你按名称搜索依赖项。例如,安装了适当的 Eclipse 或 Spring Tools 插件后,你可以在 POM 编辑器中按ctrl-space并输入“ Spring-boot-starter”以获得完整的列表。

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

Spring Boot 在org.springframework.boot组下提供了以下应用程序启动器:

Name 说明
spring-boot-starter 核心启动器,包括自动配置支持、日志记录和 YAML
spring-boot-starter-activemq 使用 Apache ActiveMQ 进行 JMS 消息传递的启动器
spring-boot-starter-amqp Spring AMQP 和兔 MQ 使用启动器
spring-boot-starter-aop Spring AOP 和 AspectJ 用于面向方面编程的启动器
spring-boot-starter-artemis 使用 Apache Artemis 进行 JMS 消息传递的启动器
spring-boot-starter-batch 用于使用 Spring 批的启动器
spring-boot-starter-cache 使用 Spring Framework 的缓存支持的入门工具
spring-boot-starter-data-cassandra 用于使用 Cassandra 分布式数据库的启动器和 Spring 数据 Cassandra
spring-boot-starter-data-cassandra-reactive 用于使用 Cassandra 分布式数据库的启动器和 Spring 数据 Cassandra 反应
spring-boot-starter-data-couchbase 用于使用 CouchBase 文档的面向数据库和 Spring 数据 CouchBase 的启动器
spring-boot-starter-data-couchbase-reactive 用于使用 CouchBase 面向文档的数据库和 Spring CouchBase 数据库的启动器
spring-boot-starter-data-elasticsearch Spring 用于使用 ElasticSearch 搜索和分析引擎的启动器和数据 ElasticSearch
spring-boot-starter-data-jdbc 用于使用 Spring 数据 JDBC 的启动器
spring-boot-starter-data-jpa 用于使用 Spring 数据 JPA 和 Hibernate 的启动器
spring-boot-starter-data-ldap 用于使用 Spring 数据 LDAP 的启动器
spring-boot-starter-data-mongodb 用于使用 MongoDB 面向文档的数据库和 Spring 数据 MongoDB 的启动器
spring-boot-starter-data-mongodb-reactive 用于使用 MongoDB 面向文档的数据库和 Spring MongoDB 数据的启动器
spring-boot-starter-data-neo4j 用于使用 NEO 的启动器 4j 图数据库和 Spring 数据 NEO4j
spring-boot-starter-data-r2dbc 用于使用 Spring 数据 R2DBC 的启动器
spring-boot-starter-data-redis 用 Spring 数据 Redis 和生菜客户机使用 Redis 键值数据存储的启动器
spring-boot-starter-data-redis-reactive 用于使用 Redis 键值数据存储 Spring 数据的启动器 Redis Reactive 和 Lettuce 客户端
spring-boot-starter-data-rest 使用 Spring 数据 REST 在 REST 上公开 Spring 数据存储库的启动器
spring-boot-starter-freemarker 使用 Freemarker 视图构建 MVC Web 应用程序的启动器
spring-boot-starter-groovy-templates 使用 Groovy Templates 视图构建 MVC Web 应用程序的入门工具
spring-boot-starter-hateoas 用 Spring MVC 和 Spring Hateoas 构建基于超媒体的 RESTful Web 应用程序的启动器
spring-boot-starter-integration 用于使用 Spring 集成的启动器
spring-boot-starter-jdbc 使用 JDBC 和 HikarICP 连接池的启动器
spring-boot-starter-jersey 使用 JAX-RS 和 Jersey 构建 RESTful Web 应用程序的入门工具。[spring-boot-starter-web](# Spring-boot-starter-web)的一种替代方法
spring-boot-starter-jooq 使用 Jooq 使用 JDBC 访问 SQL 数据库的启动器。[spring-boot-starter-data-jpa](# Spring-boot-starter-data- JPA)或[spring-boot-starter-jdbc](# Spring-boot-starter-jdbc)的替代方案)
spring-boot-starter-json 读写 JSON 的启动器
spring-boot-starter-jta-atomikos 使用 Atomikos 的 JTA 事务启动器
spring-boot-starter-mail 使用 Java Mail 的启动器和 Spring Framework 的电子邮件发送支持
spring-boot-starter-mustache 使用 Mustache 视图构建 Web 应用程序的入门工具
spring-boot-starter-oauth2-client 使用 Spring Security 的 OAuth2/OpenID Connect 客户端功能的启动器
spring-boot-starter-oauth2-resource-server 使用 Spring Security 的 OAuth2Resource Server 特性的启动器
spring-boot-starter-quartz 使用 Quartz 调度器的启动器
spring-boot-starter-rsocket 用于构建 RSocket 客户机和服务器的启动器
spring-boot-starter-security 使用 Spring 安全性的启动器
spring-boot-starter-test 用包括 JUnit Jupiter、Hamcrest 和 Mockito 在内的库测试 Spring 引导应用程序的启动器
spring-boot-starter-thymeleaf 使用 ThymeLeaf 视图构建 MVC Web 应用程序的启动器
spring-boot-starter-validation 用 Hibernate 验证器使用 Java Bean 验证的启动器
spring-boot-starter-web 用于使用 Spring MVC 构建 Web(包括 RESTful)应用程序的启动器。使用 Tomcat 作为默认的嵌入式容器
spring-boot-starter-web-services 用于使用 Spring Web 服务的启动器
spring-boot-starter-webflux 使用 Spring 框架的反应式 Web 支持构建 WebFlux 应用程序的启动器
spring-boot-starter-websocket 用于使用 Spring 框架的 WebSocket 支持构建 WebSocket 应用程序的启动器

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

Name 说明
spring-boot-starter-actuator 使用 Spring Boot’s Actuator 的启动器,它提供了生产就绪功能,可帮助你监视和管理你的应用程序

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

Name 说明
spring-boot-starter-jetty 用于使用 Jetty 作为嵌入式 Servlet 容器的启动器。[spring-boot-starter-tomcat]的替代方法(# Spring-boot-starter- Tomcat)
spring-boot-starter-log4j2 使用 log4j2 进行日志记录的启动器。[spring-boot-starter-logging](# Spring-boot-starter-logging)的一种替代方法)
spring-boot-starter-logging 使用日志记录的启动器。默认日志启动器
spring-boot-starter-reactor-netty 使用反应器网络作为嵌入式反应性 HTTP 服务器的启动器。
spring-boot-starter-tomcat 用于使用 Tomcat 作为嵌入式 Servlet 容器的启动器。[spring-boot-starter-web]使用的默认 Servlet 容器启动器(# Spring-boot-starter-web)
spring-boot-starter-undertow 用于使用 Undertow 作为嵌入式 Servlet 容器的启动器。[spring-boot-starter-tomcat](# Spring-boot-starter- Tomcat)的替代方案)

要了解如何交换技术方面,请参阅交换 Web 服务器测井系统的操作文档。

有关其他社区贡献的启动器的列表,请参见 Github 上spring-boot-starters模块中的自述文件 (opens new window)

# 2. 构建你的代码

Spring 启动不需要任何特定的代码布局来工作。然而,有一些最佳实践是有帮助的。

# 2.1.使用“默认”包

当一个类不包含package声明时,它被认为是在“缺省包”中。“默认包”的使用通常是不鼓励的,应该避免。对于使用@ComponentScan@Configuration属性Scan@EntityScan@SpringBootApplication注释的 Spring 引导应用程序来说,这可能会导致特殊的问题,因为每个 jar 中的每个类都被读取。

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

# 2.2.定位主应用程序类

我们通常建议你将主应用程序类定位在一个根包中,而不是其他类。[@SpringBootApplication注释](#using.using-the-springbootapplication-annotation)通常放在主类上,它隐式地为某些项定义了一个基本的“搜索包”。例如,如果你正在编写 JPA 应用程序,则使用@SpringBootApplication注释类的包来搜索@Entity项。使用根包还允许组件扫描仅应用于你的项目。

如果不想使用@SpringBootApplication,则它导入的@EnableAutoConfiguration@ComponentScan注释定义了该行为,因此你也可以使用这些注释。

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

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

MyApplication.java文件将声明main方法,以及基本的@SpringBootApplication,如下所示:

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

@SpringBootApplication
public class MyApplication {

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

}

# 3. 配置类

Spring 引导有利于基于 Java 的配置。尽管在 XML 源中可以使用SpringApplication,但我们通常建议你的主要源是一个单独的@Configuration类。通常,定义main方法的类是作为主要@Configuration方法的很好的候选者。

Spring 互联网上已经发布了许多使用 XML 配置的配置示例。
如果可能的话,总是尝试使用等效的基于 Java 的配置。
搜索Enable*注释可以是一个很好的起点。

# 3.1.导入额外的配置类

你不需要将所有的@Configuration都放入一个类中。@Import注释可用于导入其他配置类。或者,你可以使用@ComponentScan来自动拾取所有 Spring 组件,包括@Configuration类。

# 3.2.导入 XML 配置

如果你绝对必须使用基于 XML 的配置,我们建议你仍然从@Configuration类开始。然后可以使用@ImportResource注释来加载 XML 配置文件。

# 4. 自动配置

Spring 引导自动配置尝试基于你已添加的 jar 依赖项自动配置你的 Spring 应用程序。例如,如果HSQLDB在你的 Classpath 上,并且你还没有手动配置任何数据库连接 bean,那么 Spring 引导自动配置内存中的数据库。

你需要通过将@EnableAutoConfiguration@SpringBootApplication注释添加到你的@Configuration类中来 OPT 到自动配置中。

你应该只添加一个@SpringBootApplication@EnableAutoConfiguration注释。
我们通常建议你只在主@Configuration类中添加一个或另一个。

# 4.1.逐步取代自动配置

自动配置是非侵入性的。在任何时候,你都可以开始定义自己的配置,以替换自动配置的特定部分。例如,如果你添加了自己的DataSource Bean,那么默认的嵌入式数据库支持就退后了。

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

# 4.2.禁用特定的自动配置类

如果你发现你不想要的特定自动配置类正在被应用,那么你可以使用@SpringBootApplication的 exclude 属性来禁用它们,如下面的示例所示:

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class MyApplication {

}

如果类不在 Classpath 上,则可以使用注释的excludeName属性并指定完全限定的名称。如果你更喜欢使用@EnableAutoConfiguration而不是@SpringBootApplication,也可以使用excludeexcludeName。最后,你还可以使用spring.autoconfigure.exclude属性来控制要排除的自动配置类列表。

你可以在注释级别和通过使用属性来定义排除。
尽管自动配置类是public,但该类中唯一被认为是公共 API 的方面是可用于禁用自动配置的类的名称,
这些类的实际内容,例如嵌套配置类或 Bean 方法仅供内部使用,我们不建议直接使用这些方法。

# 5. Spring bean 和依赖注入

你可以自由地使用任何标准的 Spring 框架技术来定义你的 bean 及其注入的依赖项。我们通常建议使用构造函数注入来连接依赖项,并使用@ComponentScan来查找 bean。

如果按照上面的建议对代码进行结构设计(将应用程序类定位在顶级包中),则可以添加@ComponentScan而不带任何参数,或者使用@SpringBootApplication注释,隐式地包含它。你的所有应用程序组件(@Component@Service@Repository@Controller,以及其他)都会自动注册为 Spring bean。

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

import org.springframework.stereotype.Service;

@Service
public class MyAccountService implements AccountService {

    private final RiskAssessor riskAssessor;

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

    // ...

}

如果 Bean 具有多个构造函数,则需要将希望 Spring 使用的构造函数标记为@Autowired:

import java.io.PrintStream;

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

@Service
public class MyAccountService implements AccountService {

    private final RiskAssessor riskAssessor;

    private final PrintStream out;

    @Autowired
    public MyAccountService(RiskAssessor riskAssessor) {
        this.riskAssessor = riskAssessor;
        this.out = System.out;
    }

    public MyAccountService(RiskAssessor riskAssessor, PrintStream out) {
        this.riskAssessor = riskAssessor;
        this.out = out;
    }

    // ...

}

请注意,如何使用构造函数注入使riskAssessor字段标记为final,这表明它不能随后进行更改。

# 6. 使用 @SpringBootApplication 注释

Spring 许多引导开发人员喜欢他们的应用程序使用自动配置、组件扫描,并能够在他们的“应用程序类”上定义额外的配置。可以使用一个@SpringBootApplication注释来启用这三个特性,即:

  • @EnableAutoConfiguration:启用Spring Boot’s auto-configuration mechanism

  • @ComponentScan:在应用程序所在的包上启用@Component扫描(参见最佳实践

  • @SpringBootConfiguration:允许在上下文中注册额外的 bean 或导入额外的配置类。 Spring 的标准@Configuration的一种替代方法,在集成测试中辅助配置检测

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

// Same as @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan
@SpringBootApplication
public class MyApplication {

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

}

@SpringBootApplication还提供别名来定制@EnableAutoConfiguration@ComponentScan的属性。
这些特性都不是强制性的,你可以选择用它启用的任何特性来替换这个注释。
例如,你可能不希望在应用程序中使用组件扫描或配置属性扫描:

<br/>import org.springframework.boot.SpringApplication;<br/>import org.springframework.boot.SpringBootConfiguration;<br/>import org.springframework.boot.autoconfigure.EnableAutoConfiguration;<br/>import org.springframework.context.annotation.Import;<br/><br/>@SpringBootConfiguration(proxyBeanMethods = false)<br/>@EnableAutoConfiguration<br/>@Import({ SomeConfiguration.class, AnotherConfiguration.class })<br/>public class MyApplication {<br/><br/> public static void main(String[] args) {<br/> SpringApplication.run(MyApplication.class, args);<br/> }<br/><br/>}<br/><br/>
在此示例中,MyApplication就像任何其他 Spring 启动应用程序一样,除了@Component-带注释的类和@Configuration属性-带注释的类不会自动检测到,并且显式地导入了用户定义的 bean(参见@Import)。

# 7. 运行你的应用程序

将应用程序打包为 jar 并使用嵌入式 HTTP 服务器的最大优势之一是,你可以像运行其他应用程序一样运行你的应用程序。该示例应用于调试 Spring 引导应用程序。你不需要任何特殊的 IDE 插件或扩展。

本节只讨论基于 jar 的打包。
如果你选择将应用程序打包为 WAR 文件,请参阅你的服务器和 IDE 文档。

# 7.1.从 IDE 中运行

你可以将 IDE 中的 Spring 引导应用程序作为 Java 应用程序运行。然而,你首先需要导入你的项目。导入步骤根据你的 IDE 和构建系统而有所不同。大多数 IDE 可以直接导入 Maven 项目。例如,Eclipse 用户可以从File菜单中选择Import…​``Existing Maven Projects

如果不能直接将项目导入 IDE,则可以使用构建插件生成 IDE 元数据。 Maven 包括用于Eclipse (opens new window)IDEA (opens new window)的插件。 Gradle 为各种 IDE (opens new window)提供插件。

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

# 7.2.以打包应用程序的形式运行

如果使用 Spring 引导 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

# 7.3.使用 Maven 插件

Spring 引导 Maven 插件包括一个run目标,该目标可用于快速编译和运行你的应用程序。应用程序以分块的形式运行,就像它们在你的 IDE 中一样。下面的示例显示了用于运行 Spring 引导应用程序的典型 Maven 命令:

$ mvn spring-boot:run

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

$ export MAVEN_OPTS=-Xmx1024m

# 7.4.使用 Gradle 插件

Spring boot Gradle 插件还包括一个bootRun任务,该任务可用于以扩展形式运行你的应用程序。每当你应用org.springframework.bootjava插件时,都会添加bootRun任务,如下例所示:

$ gradle bootRun

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

$ export JAVA_OPTS=-Xmx1024m

# 7.5.热交换

Spring 由于引导应用程序是普通的 Java 应用程序,所以 JVM 热交换应该是开箱即用的。JVM 热交换在一定程度上受到它可以替换的字节码的限制。对于更完整的解决方案,可以使用JRebel (opens new window)

spring-boot-devtools模块还包括对快速应用程序重启的支持。有关详细信息,请参见热点交换“操作”

# 8. 开发工具

Spring 启动包括一组额外的工具,这些工具可以使应用程序的开发体验稍微更愉快一些。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 {
    developmentOnly("org.springframework.boot:spring-boot-devtools")
}
DevTools 可能会导致类加载问题,特别是在多模块项目中。诊断类加载问题解释了如何诊断和解决它们。
在运行完全打包的应用程序时,开发人员工具会自动禁用。
如果你的应用程序是从java -jar启动的,或者是从一个特殊的类加载器启动的,然后,它被认为是一个“生产应用程序”,
你可以通过使用spring.devtools.restart.enabled系统属性来控制这种行为,
可以启用 DevTools,而不考虑启动应用程序所使用的类装入器,设置-Dspring.devtools.restart.enabled=true系统属性。
在运行 DevTools 存在安全风险的生产环境中,不能这样做。
要禁用 DevTools,排除依赖关系或设置-Dspring.devtools.restart.enabled=false系统属性。
在 Maven 中将依赖标记为可选的,或者在 Gradle 中使用developmentOnly配置(如上图所示),可以防止将 DevTools 传递地应用于使用你的项目的其他模块。
重新打包的归档文件默认情况下不包含 DevTools。
如果你想使用某些远程 DevTools 功能,则需要包含它。
在使用 Maven 插件时,将excludeDevtools属性设置为false。在使用 Gradle 插件时,
,[将任务的 Classpath 配置为包括developmentOnly配置](https://DOCS. Spring.io/ Spring-boot/DOCS/2.6.4/ Gradle-plugin/reference/htmlsingle/#packaging-executable-configuring-inuiting-including-development-only-dependencies)。

# 8.1.诊断类加载问题

重新启动 VS 重新加载小节中所述,重新启动功能是通过使用两个类装入器来实现的。对于大多数应用程序来说,这种方法效果很好。然而,它有时会导致类加载问题,特别是在多模块项目中。

要诊断类加载问题是否确实是由 DevTools 及其两个类加载器引起的,尝试禁用重新启动。如果这解决了你的问题,自定义重新启动类装入器将包含你的整个项目。

# 8.2.属性默认值

Spring 引导支持的几个库使用缓存来提高性能。例如,模板引擎缓存已编译的模板,以避免重复解析模板文件。另外, Spring MVC 可以在提供静态资源时将 HTTP 缓存头添加到响应中。

虽然缓存在生产中非常有益,但在开发过程中可能会适得其反,从而使你无法看到刚刚在应用程序中所做的更改。出于这个原因, Spring-boot-devtools 默认禁用缓存选项。

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

由于在开发 Spring MVC 和 Spring WebFlux 应用程序时需要有关 Web 请求的更多信息,因此 Developer Tools 建议你为DEBUG日志记录组启用web日志记录。这将为你提供有关传入请求的信息、处理该请求的处理程序、响应结果以及其他详细信息。如果希望记录所有请求细节(包括可能敏感的信息),可以打开spring.mvc.log-request-detailsspring.codec.log-request-details配置属性。

如果不希望应用属性默认值,可以在application.properties中将spring.devtools.add-properties设置为false
有关 DevTools 应用的属性的完整列表,请参见DevToolsPropertyDefaultSpostProcessor (opens new window)

# 8.3.自动重启

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

触发重新启动

由于 DevTools 监视 Classpath 资源,触发重启的唯一方法是更新 Classpath。使 Classpath 更新的方式取决于你使用的 IDE:

  • 在 Eclipse 中,保存修改后的文件会导致 Classpath 被更新并触发重新启动。

  • 在 IntelliJ IDEA 中,构建项目(Build +→+ Build Project)具有相同的效果。

  • 如果使用构建插件,对 Maven 运行mvn compile或对 Gradle 运行gradle build将触发重新启动。

如果使用 Maven 或 Gradle 使用构建插件重新启动,则必须将forking设置为enabled
如果禁用分叉,将不会创建 DevTools 使用的隔离应用程序类装入器,并且重新启动将无法正常运行。
当与 LiveReload 一起使用时,自动重启非常有效。参见 LiveReload 部分有关详细信息。
如果使用 JRebel,自动重启将被禁用,以利于动态类重新加载。
其他 DevTools 功能(例如 LiveReload 和 Property overrides)仍然可以使用。
DevTools 依赖应用程序上下文的关机钩子在重新启动时关闭它。
如果禁用了关机钩子(SpringApplication.setRegisterShutdownHook(false)),它将无法正常工作。
DevTools 需要自定义ApplicationContext所使用的ResourceLoader
如果你的应用程序已经提供了一个,它将被包装。
不支持getResource方法上的getResource直接覆盖。
使用 AspectJ 编织时不支持自动重新启动。

重新启动 VS 重新加载

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

如果你发现应用程序的重新启动速度不够快,或者遇到类加载问题,那么可以考虑重新加载 ZeroTurnaround 中的JRebel (opens new window)等技术。这些工作是在加载时重写类,以使它们更易于重新加载。

# 8.3.1.状态评估中的测井变化

默认情况下,每次应用程序重新启动时,都会记录一份显示条件评估增量的报告。当你进行添加或删除 bean 和设置配置属性等更改时,该报告将显示对应用程序自动配置的更改。

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

属性

spring.devtools.restart.log-condition-evaluation-delta=false

Yaml

spring:
  devtools:
    restart:
      log-condition-evaluation-delta: false

# 8.3.2.不包括资源

某些资源在被更改时不一定需要触发重新启动。例如,胸腺叶模板可以就地编辑。默认情况下,在/META-INF/maven/META-INF/resources/resources/static/public/templates中更改资源不会触发重启,但会触发实时重新加载。如果希望自定义这些排除,可以使用spring.devtools.restart.exclude属性。例如,要仅排除/static/public,你需要设置以下属性:

属性

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

Yaml

spring:
  devtools:
    restart:
      exclude: "static/**,public/**"
如果你希望保留这些默认值和添加附加排除项,请使用spring.devtools.restart.additional-exclude属性。

# 8.3.3.观看其他路径

当你对不在 Classpath 上的文件进行更改时,你可能希望你的应用程序被重新启动或重新加载。要做到这一点,请使用spring.devtools.restart.additional-paths属性来配置其他路径,以监视更改。你可以使用spring.devtools.restart.exclude属性前面描述的来控制附加路径下方的更改是否触发完全重新启动或实时重新加载

# 8.3.4.禁用重新启动

如果不想使用 Restart 特性,可以使用spring.devtools.restart.enabled属性禁用它。在大多数情况下,你可以在application.properties中设置此属性(这样做仍然会初始化 Restart 类装入器,但它不会监视文件更改)。

如果需要完全禁用重启支持(例如,因为它不能与特定的库一起工作),则需要在调用spring.devtools.restart.enabled``System之前将false属性设置为false,如下面的示例所示:

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

@SpringBootApplication
public class MyApplication {

    public static void main(String[] args) {
        System.setProperty("spring.devtools.restart.enabled", "false");
        SpringApplication.run(MyApplication.class, args);
    }

}

# 8.3.5.使用触发器文件

如果你使用的 IDE 不断编译更改的文件,那么你可能更喜欢只在特定的时间触发重启。要做到这一点,你可以使用“触发器文件”,这是一种特殊的文件,当你想要实际触发重新启动检查时,必须对其进行修改。

对该文件的任何更新都会触发检查,但只有在 DevTools 检测到有事情要做时,才会真正重新启动。

要使用触发器文件,请将spring.devtools.restart.trigger-file属性设置为触发器文件的名称(不包括任何路径)。触发器文件必须出现在你的 Classpath 上的某个地方。

例如,如果你的项目具有以下结构:

src
+- main
   +- resources
      +- .reloadtrigger

那么你的trigger-file属性将是:

属性

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

Yaml

spring:
  devtools:
    restart:
      trigger-file: ".reloadtrigger"

现在只有更新src/main/resources/.reloadtrigger时才会重新启动。

你可能希望将spring.devtools.restart.trigger-file设置为全局设置,以便所有项目都以相同的方式运行。

有些 IDE 有一些特性,可以使你不必手动更新触发器文件。Spring Tools for Eclipse (opens new window)Intellij Idea(终极版) (opens new window)都有这样的支持。使用 Spring 工具,你可以使用控制台视图中的“Reload”按钮(只要你的trigger-file名为.reloadtrigger)。对于 IntelliJ IDEA,你可以遵循文件中的说明 (opens new window)

# 8.3.6.自定义重新启动类装入器

如前面重新启动 VS 重新加载小节中所述,重新启动功能是通过使用两个类装入器来实现的。如果这会导致问题,你可能需要定制由哪个类装入器加载的内容。

默认情况下,你的 IDE 中的任何打开的项目都是用“restart”类加载器加载的,而任何常规的.jar文件都是用“base”类加载器加载的。如果使用mvn spring-boot:rungradle bootRun,情况也是如此:包含@SpringBootApplication的项目是用“重新启动”类装入器加载的,其他所有内容都是用“基本”类装入器加载的。

通过创建META-INF/spring-devtools.properties文件,你可以指示 Spring boot 使用不同的类装入器加载项目的部分内容。spring-devtools.properties文件可以包含以restart.excluderestart.include为前缀的属性。include元素是应该被拉到“重新启动”类装入器中的项,而exclude元素是应该被下推到“基本”类装入器中的项。该属性的值是应用于 Classpath 的正则表达式模式,如以下示例所示:

属性

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

Yaml

restart:
  exclude:
    companycommonlibs: "/mycorp-common-[\\w\\d-\\.]+\\.jar"
  include:
    projectcommon: "/mycorp-myproj-[\\w\\d-\\.]+\\.jar"
所有属性键必须是唯一的。
只要一个属性以restart.include.restart.exclude.开头,就被认为是唯一的。
Classpath 中的所有META-INF/spring-devtools.properties都已加载。
你可以将文件打包到你的项目中,或者打包到项目使用的库中。

# 8.3.7.已知限制

对于使用标准ObjectInputStream进行反序列化的对象,重启功能不能很好地工作。如果需要反序列化数据,则可能需要结合使用 Spring 的ConfigurableObjectInputStreamThread.currentThread().getContextClassLoader()

遗憾的是,一些第三方库在反序列化时没有考虑上下文类装入器。如果你发现了这样的问题,你需要向原始作者请求修复。

# 8.4.LiveReload

spring-boot-devtools模块包括一个嵌入式 LiveReload 服务器,该服务器可用于在更改资源时触发浏览器刷新。LiveReload 浏览器扩展从LiveReload.com (opens new window)免费提供给 Chrome、Firefox 和 Safari。

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

一次只能运行一个 LiveReload 服务器。
在启动应用程序之前,请确保没有其他 LiveReload 服务器在运行。
如果你从 IDE 启动多个应用程序,则只有第一个应用程序具有 LiveReload 支持。
要在文件更改时触发 LiveReload,必须启用自动重启

# 8.5.全局设置

你可以通过向$HOME/.config/spring-boot目录添加以下任意文件来配置全局 devtools 设置:

  1. spring-boot-devtools.properties

  2. spring-boot-devtools.yaml

  3. spring-boot-devtools.yml

添加到这些文件中的任何属性都适用于机器上使用 DevTools 的全部 Spring 引导应用程序。例如,要将 Restart 配置为始终使用触发器文件,你可以将以下属性添加到spring-boot-devtools文件中:

Properties

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

Yaml

spring:
  devtools:
    restart:
      trigger-file: ".reloadtrigger"

默认情况下,$HOME是用户的主目录。要自定义此位置,请设置SPRING_DEVTOOLS_HOME环境变量或spring.devtools.home系统属性。

如果在$HOME/.config/spring-boot中未找到 DevTools 配置文件,在$HOME目录的根目录中搜索是否存在.spring-boot-devtools.properties文件。
这允许你与不支持$HOME/.config/spring-boot位置的旧版本 Spring 启动上的应用程序共享 DevTools 全局配置。
在 DevTools Properties/YAML 文件中不支持配置文件。

.spring-boot-devtools.properties中激活的任何配置文件都不会影响特定于配置文件的配置文件的加载。
配置文件特定的文件名(spring-boot-devtools-<profile>.properties)和spring.config.activate.on-profile文件在 YAML 和属性文件中都不受支持。

# 8.5.1.配置文件系统监视器

Filesystemwatcher (opens new window)的工作原理是轮询具有一定时间间隔的类更改,然后等待预定义的静默期,以确保没有更多更改。由于 Spring 启动完全依赖于 IDE 来编译并将文件复制到 Spring 启动可以读取它们的位置,因此你可能会发现,当 DevTools 重新启动应用程序时,有时某些更改没有得到反映。如果你经常看到这样的问题,请尝试将spring.devtools.restart.poll-intervalspring.devtools.restart.quiet-period参数增加到适合你的开发环境的值:

Properties

spring.devtools.restart.poll-interval=2s
spring.devtools.restart.quiet-period=1s

Yaml

spring:
  devtools:
    restart:
      poll-interval: "2s"
      quiet-period: "1s"

Classpath 监视的目录现在每 2 秒对更改进行一次轮询,并保持 1 秒的静默期,以确保没有额外的类更改。

# 8.6.远程应用程序

Spring 引导开发人员工具不限于本地开发。在远程运行应用程序时,你还可以使用几个功能。远程支持是 OPT 的,因为启用它可能会带来安全风险。只有在运行在受信任的网络上或使用 SSL 进行安全保护时,才应启用它。如果这两个选项都不对你可用,那么你不应该使用 DevTools 的远程支持。你永远不应该在生产部署中启用支持。

要启用它,你需要确保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属性。像任何重要的密码或秘密一样,该值应该是唯一的和强大的,以便它不能被猜测或暴力强迫。

远程 DevTools 支持由两部分提供:接受连接的服务器端端点和在 IDE 中运行的客户机应用程序。设置spring.devtools.remote.secret属性后,服务器组件将自动启用。客户端组件必须手动启动。

Spring WebFlux 应用程序不支持远程 DevTools。

# 8.6.1.运行远程客户端应用程序

远程客户机应用程序被设计为在你的 IDE 中运行。你需要以与你所连接的远程项目相同的 Classpath 运行org.springframework.boot.devtools.RemoteSpringApplication。应用程序唯一需要的参数是它所连接的远程 URL。

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

  • Run菜单中选择Run Configurations…​

  • 创建一个新的Java Application“启动配置”。

  • 浏览my-app项目。

  • 使用org.springframework.boot.devtools.RemoteSpringApplication作为主类。

  • https://myapp.cfapps.io添加到Program arguments(或你的远程 URL 是什么)。

正在运行的远程客户端可能类似于以下清单:

  .   ____          _                                              __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _          ___               _      \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` |        | _ \___ _ __  ___| |_ ___ \ \ \ \
 \\/  ___)| |_)| | | | | || (_| []::::::[]   / -_) '  \/ _ \  _/ -_) ) ) ) )
  '  |____| .__|_| |_|_| |_\__, |        |_|_\___|_|_|_\___/\__\___|/ / / /
 =========|_|==============|___/===================================/_/_/_/
 :: Spring Boot Remote :: 2.6.4

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-project/spring-boot-devtools/target/classes started by pwebb in /Users/pwebb/projects/spring-boot/code)
2015-06-10 18:25:06.671  INFO 14938 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.spring[email protected]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)
Classpath 因为远程客户端使用的是与实际应用相同的应用程序,所以它可以直接读取应用程序属性。
这就是spring.devtools.remote.secret属性的读取方式,并将其传递给服务器以进行身份验证。
始终建议使用https://作为连接协议,以便对流量进行加密,并且不能拦截密码。
如果需要使用代理来访问远程应用程序,请配置spring.devtools.remote.proxy.hostspring.devtools.remote.proxy.port属性。

# 8.6.2.远程更新

远程客户端以与本地重启相同的方式监视你的应用程序 Classpath 的更改。任何更新的资源都会被推送到远程应用程序,并(* 如果需要 *)触发重新启动。如果你迭代使用本地不具备的云服务的功能,这将很有帮助。通常,远程更新和重启要比完整的重建和部署周期快得多。

在较慢的开发环境中,可能会出现静默期不够的情况,并且类中的更改可能会被分解为批处理。上载第一批类更改后,服务器将重新启动。由于服务器正在重新启动,下一个批处理不能发送到应用程序。

这通常表现为RemoteSpringApplication日志中有关于未能上载某些类的警告,以及随后的重试。但这也可能导致应用程序代码不一致,以及在上传第一批更改后无法重新启动。如果你经常观察到这样的问题,请尝试将spring.devtools.restart.poll-intervalspring.devtools.restart.quiet-period参数增加到适合你的开发环境的值。有关这些属性的配置,请参见配置文件系统监视器小节。

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

# 9. 包装你的应用程序以进行生产

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

对于额外的“生产就绪”特性,例如健康状态、审计和度量休息或 JMX 端点,可以考虑添加spring-boot-actuator。详见 actuator.html

# 10. 接下来要读什么?

你现在应该了解如何使用 Spring 引导和一些你应该遵循的最佳实践。你现在可以继续深入了解特定的 Spring Boot features,或者你可以跳过并阅读 Spring boot 的“生产准备就绪”方面。