Appearance
Spring Boot:使用 Spring Boot 进行开发
本节详细介绍了如何使用 Spring Boot。它涵盖了构建系统、自动配置以及如何运行应用程序等主题。还介绍了一些 Spring Boot 的最佳实践。虽然 Spring Boot 并没有什么特别之处(它只是另一个你可以使用的库),但遵循一些建议可以使你的开发过程更加轻松。
如果你刚开始使用 Spring Boot,建议在深入本节之前先阅读入门指南。
1. 构建系统
强烈建议选择支持依赖管理并且可以使用发布到 “Maven Central” 仓库的工件的构建系统。我们建议使用 Maven 或 Gradle。虽然可以使用其他构建系统(例如 Ant),但它们并不是特别受支持。
1.1. 依赖管理
每个 Spring Boot 版本都提供了一个经过精选的依赖列表。实际上,你不需要在构建配置中为这些依赖项指定版本,因为 Spring Boot 会为你管理这些依赖项。当你升级 Spring Boot 本身时,这些依赖项也会以一致的方式进行升级。
Tip:你仍然可以指定版本并覆盖 Spring Boot 的建议。
精选列表包含你可以与 Spring Boot 一起使用的所有 Spring 模块以及经过筛选的第三方库列表。该列表作为标准的 Bills of Materials(spring-boot-dependencies),可以与 Maven 和 Gradle 一起使用。
Warning:每个 Spring Boot 版本都与 Spring Framework 的基础版本相关联。我们强烈建议你不要指定其版本。
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 Boot 项目。spring-boot-antlib “AntLib” 模块也可用于帮助 Ant 创建可执行的 jar 文件。
要声明依赖项,典型的 ivy.xml 文件看起来像以下示例:
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 文件看起来像以下示例:
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.7.18" />
<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>Note:如果你不想使用
spring-boot-antlib模块,请参阅从 Ant 构建可执行归档而不使用 spring-boot-antlib “How-to”。
1.5. Starters
Starters 是一组方便的依赖描述符,你可以在应用程序中包含它们。你可以一站式获取所有 Spring 和相关技术,而无需在示例代码中查找并复制大量依赖描述符。例如,如果你想开始使用 Spring 和 JPA 进行数据库访问,请在项目中包含 spring-boot-starter-data-jpa 依赖项。
Starters 包含许多你需要的依赖项,以便快速启动项目并使用一致的、受支持的一组托管的传递依赖项。
Note 名字中的含义
所有官方 starters 都遵循相似的命名模式;
spring-boot-starter-*,其中*是特定类型的应用程序。这种命名结构旨在帮助你在需要找到 starter 时。许多 IDE 中的 Maven 集成允许你按名称搜索依赖项。例如,安装适当的 Eclipse 或 Spring Tools 插件后,你可以在 POM 编辑器中按ctrl-space并输入 “spring-boot-starter” 以获取完整列表。如 “创建你自己的 Starter” 部分所述,第三方 starters 不应以
spring-boot开头,因为它保留给官方 Spring Boot 工件。相反,第三方 starter 通常以项目名称开头。例如,名为thirdpartyproject的第三方 starter 项目通常命名为thirdpartyproject-spring-boot-starter。
Spring Boot 在 org.springframework.boot 组下提供了以下应用程序 starters:
| 名称 | 描述 |
|---|---|
spring-boot-starter | 核心 starter,包括自动配置支持、日志记录和 YAML |
spring-boot-starter-activemq | 使用 Apache ActiveMQ 进行 JMS 消息传递的 starter |
spring-boot-starter-amqp | 使用 Spring AMQP 和 Rabbit MQ 的 starter |
spring-boot-starter-aop | 使用 Spring AOP 和 AspectJ 进行面向方面编程的 starter |
spring-boot-starter-artemis | 使用 Apache Artemis 进行 JMS 消息传递的 starter |
spring-boot-starter-batch | 使用 Spring Batch 的 starter |
spring-boot-starter-cache | 使用 Spring Framework 的缓存支持的 starter |
spring-boot-starter-data-cassandra | 使用 Cassandra 分布式数据库和 Spring Data Cassandra 的 starter |
spring-boot-starter-data-cassandra-reactive | 使用 Cassandra 分布式数据库和 Spring Data Cassandra Reactive 的 starter |
spring-boot-starter-data-couchbase | 使用 Couchbase 面向文档的数据库和 Spring Data Couchbase 的 starter |
spring-boot-starter-data-couchbase-reactive | 使用 Couchbase 面向文档的数据库和 Spring Data Couchbase Reactive 的 starter |
spring-boot-starter-data-elasticsearch | 使用 Elasticsearch 搜索和分析引擎和 Spring Data Elasticsearch 的 starter |
spring-boot-starter-data-jdbc | 使用 Spring Data JDBC 的 starter |
spring-boot-starter-data-jpa | 使用 Spring Data JPA 和 Hibernate 的 starter |
spring-boot-starter-data-ldap | 使用 Spring Data LDAP 的 starter |
spring-boot-starter-data-mongodb | 使用 MongoDB 面向文档的数据库和 Spring Data MongoDB 的 starter |
spring-boot-starter-data-mongodb-reactive | 使用 MongoDB 面向文档的数据库和 Spring Data MongoDB Reactive 的 starter |
spring-boot-starter-data-neo4j | 使用 Neo4j 图数据库和 Spring Data Neo4j 的 starter |
spring-boot-starter-data-r2dbc | 使用 Spring Data R2DBC 的 starter |
spring-boot-starter-data-redis | 使用 Redis 键值数据存储与 Spring Data Redis 和 Lettuce 客户端的 starter |
spring-boot-starter-data-redis-reactive | 使用 Redis 键值数据存储与 Spring Data Redis reactive 和 Lettuce 客户端的 starter |
spring-boot-starter-data-rest | 使用 Spring Data REST 和 Spring MVC 通过 REST 暴露 Spring Data 存储库的 starter |
spring-boot-starter-freemarker | 使用 FreeMarker 视图构建 MVC Web 应用程序的 starter |
spring-boot-starter-graphql | 使用 Spring GraphQL 构建 GraphQL 应用程序的 starter |
spring-boot-starter-groovy-templates | 使用 Groovy Templates 视图构建 MVC Web 应用程序的 starter |
spring-boot-starter-hateoas | 使用 Spring MVC 和 Spring HATEOAS 构建基于超媒体的 RESTful Web 应用程序的 starter |
spring-boot-starter-integration | 使用 Spring Integration 的 starter |
spring-boot-starter-jdbc | 使用 JDBC 和 HikariCP 连接池的 starter |
spring-boot-starter-jersey | 使用 JAX-RS 和 Jersey 构建 RESTful Web 应用程序的 starter。spring-boot-starter-web 的替代方案 |
spring-boot-starter-jooq | 使用 jOOQ 通过 JDBC 访问 SQL 数据库的 starter。spring-boot-starter-data-jpa 或 spring-boot-starter-jdbc 的替代方案 |
spring-boot-starter-json | 用于读取和写入 json 的 starter |
spring-boot-starter-jta-atomikos | 使用 Atomikos 进行 JTA 事务的 starter |
spring-boot-starter-mail | 使用 Java Mail 和 Spring Framework 的电子邮件发送支持的 starter |
spring-boot-starter-mustache | 使用 Mustache 视图构建 Web 应用程序的 starter |
spring-boot-starter-oauth2-client | 使用 Spring Security 的 OAuth2/OpenID Connect 客户端功能的 starter |
spring-boot-starter-oauth2-resource-server | 使用 Spring Security 的 OAuth2 资源服务器功能的 starter |
spring-boot-starter-quartz | 使用 Quartz 调度器的 starter |
spring-boot-starter-rsocket | 构建 RSocket 客户端和服务器的 starter |
spring-boot-starter-security | 使用 Spring Security 的 starter |
spring-boot-starter-test | 使用包括 JUnit Jupiter、Hamcrest 和 Mockito 在内的库测试 Spring Boot 应用程序的 starter |
spring-boot-starter-thymeleaf | 使用 Thymeleaf 视图构建 MVC Web 应用程序的 starter |
spring-boot-starter-validation | 使用 Java Bean Validation 和 Hibernate Validator 的 starter |
spring-boot-starter-web | 使用 Spring MVC 构建 Web(包括 RESTful)应用程序的 starter。使用 Tomcat 作为默认嵌入式容器 |
spring-boot-starter-web-services | 使用 Spring Web Services 的 starter |
spring-boot-starter-webflux | 使用 Spring Framework 的 Reactive Web 支持构建 WebFlux 应用程序的 starter |
spring-boot-starter-websocket | 使用 Spring Framework 的 MVC WebSocket 支持构建 WebSocket 应用程序的 starter |
除了应用程序 starters,还可以使用以下 starters 添加生产就绪功能:
| 名称 | 描述 |
|---|---|
spring-boot-starter-actuator | 使用 Spring Boot 的 Actuator 提供生产就绪功能,帮助你监控和管理应用程序 |
最后,Spring Boot 还包括以下 starters,如果你想排除或替换特定技术方面,可以使用它们:
| 名称 | 描述 |
|---|---|
spring-boot-starter-jetty | 使用 Jetty 作为嵌入式 servlet 容器的 starter。spring-boot-starter-tomcat 的替代方案 |
spring-boot-starter-log4j2 | 使用 Log4j2 进行日志记录的 starter。spring-boot-starter-logging 的替代方案 |
spring-boot-starter-logging | 使用 Logback 进行日志记录的 starter。默认日志记录 starter |
spring-boot-starter-reactor-netty | 使用 Reactor Netty 作为嵌入式响应式 HTTP 服务器的 starter。 |
spring-boot-starter-tomcat | 使用 Tomcat 作为嵌入式 servlet 容器的 starter。spring-boot-starter-web 使用的默认 servlet 容器 starter |
spring-boot-starter-undertow | 使用 Undertow 作为嵌入式 servlet 容器的 starter。spring-boot-starter-tomcat 的替代方案 |
要了解如何替换技术方面,请参阅有关切换 Web 服务器和配置 Log4j 进行日志记录的 “How-to” 文档。
Note:有关社区贡献的其他 starters 列表,请参阅 GitHub 上
spring-boot-starters模块中的 README 文件。
2. 结构化你的代码
Spring Boot 不需要任何特定的代码布局才能工作。但是,有一些最佳实践可以帮助你。
2.1. 使用 “默认” 包
当一个类不包含 package 声明时,它被认为在 “默认包” 中。一般不建议使用 “默认包”,应避免使用。它可能会对使用 @ComponentScan、@ConfigurationPropertiesScan、@EntityScan 或 @SpringBootApplication 注解的 Spring Boot 应用程序造成特定问题,因为每个 jar 的每个类都会被读取。
Note:我们建议你遵循 Java 的推荐包命名约定,使用反向域名(例如,
com.example.project)。
2.2. 定位主应用程序类
我们通常建议你将主应用程序类放在根包中,位于其他类之上。@SpringBootApplication 注解(Spring Boot 入门指南)通常放在你的主类上,它隐式定义了某些项目的 “基础搜索包”。例如,如果你在编写 JPA 应用程序,@SpringBootApplication 注解类的包将用于搜索 @Entity 项目。使用根包也允许组件扫描仅应用于你的项目。
Note:如果你不想使用
@SpringBootApplication,@EnableAutoConfiguration和@ComponentScan注解也定义了该行为,因此你也可以使用它们。
以下列表显示了典型的布局:
Text
com
+- example
+- myapplication
+- MyApplication.java
|
+- customer
| +- Customer.java
| +- CustomerController.java
| +- CustomerService.java
| +- CustomerRepository.java
|
+- order
+- Order.java
+- OrderController.java
+- OrderService.java
+- OrderRepository.javaMyApplication.java 文件将声明 main 方法,以及基本的 @SpringBootApplication,如下所示:
Java
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);
}
}1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
3. 配置类
Spring Boot 更喜欢基于 Java 的配置。虽然可以使用 SpringApplication 与 XML 源一起使用,但我们通常建议你的主要源是一个 @Configuration 类。通常定义 main 方法的类是一个不错的主 @Configuration 候选者。
Note:许多 Spring 配置示例已在互联网上发布,使用 XML 配置。如果可能,始终尝试使用等效的基于 Java 的配置。搜索
Enable*注解可以是一个很好的起点。
3.1. 导入其他配置类
你不需要将所有 @Configuration 放在一个类中。@Import 注解可以用于导入其他配置类。或者,你可以使用 @ComponentScan 自动捕获所有 Spring 组件,包括 @Configuration 类。
3.2. 导入 XML 配置
如果你绝对必须使用基于 XML 的配置,我们建议你仍然从 @Configuration 类开始。然后你可以使用 @ImportResource 注解加载 XML 配置文件。
4. 自动配置
Spring Boot 自动配置尝试根据你添加的 jar 依赖项自动配置你的 Spring 应用程序。例如,如果 HSQLDB 在你的类路径上,并且你没有手动配置任何数据库连接 bean,那么 Spring Boot 会自动配置一个内存数据库。
你需要通过在你的 @Configuration 类中添加 @EnableAutoConfiguration 或 @SpringBootApplication 注解来选择加入自动配置。
Note:你应该只添加一个
@SpringBootApplication或@EnableAutoConfiguration注解。我们通常建议你只将其中一个添加到你的主@Configuration类中。
4.1. 逐步替换自动配置
自动配置是非侵入性的。在任何时候,你都可以开始定义自己的配置以替换自动配置的特定部分。例如,如果你添加自己的 DataSource bean,默认的嵌入式数据库支持将退出。
如果你想知道当前应用了哪些自动配置以及原因,请使用 --debug 开关启动你的应用程序。这样可以为一些核心日志记录器启用调试日志,并将条件报告记录到控制台。
4.2. 禁用特定自动配置类
如果你发现应用了你不想要的特定自动配置类,可以使用 @SpringBootApplication 的 exclude 属性禁用它们,如下例所示:
Java
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class MyApplication {
}1
2
3
4
5
6
7
2
3
4
5
6
7
如果该类不在类路径上,你可以使用注解的 excludeName 属性并指定完全限定名称。如果你更喜欢使用 @EnableAutoConfiguration 而不是 @SpringBootApplication,exclude 和 excludeName 也可用。最后,你还可以使用 spring.autoconfigure.exclude 属性控制要排除的自动配置类列表。
Note:你可以在注解级别和使用属性两者都定义排除项。
Tip:尽管自动配置类是
public的,但类的唯一公共 API 部分是类名,可以用于禁用自动配置。类的实际内容,例如嵌套配置类或 bean 方法,仅供内部使用,我们不建议直接使用它们。
4.3. 自动配置包
自动配置包是各种自动配置功能默认查找的包,例如实体和 Spring Data 存储库。@EnableAutoConfiguration 注解(直接或通过其存在于 @SpringBootApplication 上)确定默认的自动配置包。可以使用 @AutoConfigurationPackage 注解配置其他包。
5. Spring Beans 和依赖注入
你可以使用任何标准的 Spring Framework 技术来定义你的 beans 及其注入的依赖项。我们通常建议使用构造函数注入来连接依赖项,并使用 @ComponentScan 查找 beans。
如果你按照上面的建议结构化你的代码(将应用程序类放在顶级包中),你可以添加 @ComponentScan 而不带任何参数,或者使用 @SpringBootApplication 注解,它隐式包含它。所有你的应用程序组件(@Component、@Service、@Repository、@Controller 等)都会自动注册为 Spring Beans。
以下示例显示了一个 @Service Bean,它使用构造函数注入获取必需的 RiskAssessor bean:
Java
import org.springframework.stereotype.Service;
@Service
public class MyAccountService implements AccountService {
private final RiskAssessor riskAssessor;
public MyAccountService(RiskAssessor riskAssessor) {
this.riskAssessor = riskAssessor;
}
// ...
}1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
如果一个 bean 有多个构造函数,你需要使用 @Autowired 标记你希望 Spring 使用的构造函数:
Java
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;
}
// ...
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Note:请注意,使用构造函数注入可以将
riskAssessor字段标记为final,表示它不能随后更改。
6. 使用 @SpringBootApplication 注解
许多 Spring Boot 开发者喜欢他们的应用程序使用自动配置、组件扫描,并能够在 “应用程序类” 上定义额外的配置。可以使用单个 @SpringBootApplication 注解来启用这三个功能,即:
@EnableAutoConfiguration:启用 Spring Boot 的自动配置机制@ComponentScan:在应用程序所在的包上启用@Component扫描(参见最佳实践)@SpringBootConfiguration:启用在上下文中注册额外的 bean 或导入其他配置类。这是 Spring 标准@Configuration的替代方案,有助于在集成测试中检测配置(参见检测测试配置)。
Java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
// 相当于 @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
Tip:
@SpringBootApplication还提供了别名来自定义@EnableAutoConfiguration和@ComponentScan的属性。
Tip
这些功能都不是强制性的,您可以选择用这个单一注解替换它启用的任何功能。例如,您可能不希望在应用程序中使用组件扫描或配置属性扫描:
Javaimport org.springframework.boot.SpringApplication; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.Import; @SpringBootConfiguration(proxyBeanMethods = false) @EnableAutoConfiguration @Import({ SomeConfiguration.class, AnotherConfiguration.class }) public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } }1
2
3
4
5
6
7
8
9
10
11
12
13在这个例子中,
MyApplication与其他 Spring Boot 应用程序一样,只是@Component注解的类和@ConfigurationProperties注解的类不会自动检测到,而是显式导入用户定义的 bean(参见@Import)。
7. 运行您的应用程序
将应用程序打包为 jar 并使用嵌入式 HTTP 服务器的最大优势之一是,您可以像运行任何其他应用程序一样运行您的应用程序。这同样适用于调试 Spring Boot 应用程序。您不需要任何特殊的 IDE 插件或扩展。
Tip:本节仅涵盖基于 jar 的打包。如果您选择将应用程序打包为 war 文件,请参阅您的服务器和 IDE 文档。
7.1. 从 IDE 运行
您可以从 IDE 作为 Java 应用程序运行 Spring Boot 应用程序。但是,您首先需要导入您的项目。导入步骤因 IDE 和构建系统而异。大多数 IDE 可以直接导入 Maven 项目。例如,Eclipse 用户可以从 File 菜单中选择 Import… → Existing Maven Projects。
如果您无法直接将项目导入 IDE,您可能可以使用构建插件生成 IDE 元数据。Maven 包括用于 Eclipse 和 IDEA 的插件。Gradle 提供用于各种 IDE 的插件。
Note:如果您意外地运行了两次 Web 应用程序,您会看到 “端口已被使用” 错误。Spring Tools 用户可以使用
Relaunch按钮而不是Run按钮,以确保关闭任何现有实例。
7.2. 作为打包应用程序运行
如果您使用 Spring Boot Maven 或 Gradle 插件创建可执行 jar,可以使用 java -jar 运行您的应用程序,如下例所示:
Bash
$ java -jar target/myapplication-0.0.1-SNAPSHOT.jar还可以使用启用远程调试支持运行打包应用程序。这样可以将调试器附加到打包应用程序,如下例所示:
Bash
$ java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n \
-jar target/myapplication-0.0.1-SNAPSHOT.jar7.3. 使用 Maven 插件
Spring Boot Maven 插件包括一个 run 目标,可以用来快速编译和运行您的应用程序。应用程序以展开形式运行,就像在 IDE 中一样。以下示例显示了运行 Spring Boot 应用程序的典型 Maven 命令:
Bash
$ mvn spring-boot:run您还可能希望使用 MAVEN_OPTS 操作系统环境变量,如下例所示:
Bash
$ export MAVEN_OPTS=-Xmx1024m7.4. 使用 Gradle 插件
Spring Boot Gradle 插件还包括一个 bootRun 任务,可以用来以展开形式运行您的应用程序。当您应用 org.springframework.boot 和 java 插件时,会添加 bootRun 任务,如下例所示:
Bash
$ gradle bootRun您还可能希望使用 JAVA_OPTS 操作系统环境变量,如下例所示:
Bash
$ export JAVA_OPTS=-Xmx1024m7.5. 热交换
由于 Spring Boot 应用程序是普通的 Java 应用程序,因此 JVM 热交换应该开箱即用。JVM 热交换在其可以替换的字节码方面有些限制。对于更完整的解决方案,可以使用 JRebel。
spring-boot-devtools 模块还包括对快速应用程序重启的支持。请参阅热交换 “操作指南” 以获取详细信息。
8. 开发者工具
Spring Boot 包括一组额外的工具,可以使应用程序开发体验更加愉快。spring-boot-devtools 模块可以包含在任何项目中,以提供额外的开发时间功能。要包含 devtools 支持,请将模块依赖项添加到您的构建中,如下面的 Maven 和 Gradle 列表所示:
XML
<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")
}Warning:Devtools 可能会导致类加载问题,特别是在多模块项目中。诊断类加载问题解释了如何诊断和解决这些问题。
Tip:开发者工具在运行完全打包的应用程序时会自动禁用。如果您的应用程序是从
java -jar启动的,或者它是从特殊的类加载器启动的,那么它被认为是 “生产应用程序”。您可以使用spring.devtools.restart.enabled系统属性来控制此行为。要无论使用哪个类加载器启动应用程序都启用 devtools,请设置-Dspring.devtools.restart.enabled=true系统属性。这在生产环境中不应该这样做,因为运行 devtools 是一个安全风险。要禁用 devtools,请排除依赖项或设置-Dspring.devtools.restart.enabled=false系统属性。
Note:将依赖项标记为 Maven 中的
optional或使用 Gradle 中的developmentOnly配置(如上所示)可以防止 devtools 被传递应用于使用您的项目的其他模块。
Note:重新打包的归档文件默认情况下不包含 devtools。如果您想使用某些远程 devtools 功能,您需要包含它。使用 Maven 插件时,将
excludeDevtools属性设置为false。使用 Gradle 插件时,配置任务的类路径以包含developmentOnly配置。
8.1. 诊断类加载问题
如 Restart vs Reload 部分所述,重启功能是通过使用两个类加载器实现的。对于大多数应用程序,这种方法效果很好。但是,它有时会导致类加载问题,特别是在多模块项目中。
要诊断类加载问题是否确实由 devtools 及其两个类加载器引起,请尝试禁用重启。如果这解决了您的问题,请自定义重启类加载器以包含您的整个项目。
8.2. 属性默认值
Spring Boot 支持的许多库使用缓存来提高性能。例如,模板引擎缓存编译的模板,以避免重复解析模板文件。此外,Spring MVC 可以在提供静态资源时向响应添加 HTTP 缓存头。
虽然缓存在生产中非常有益,但在开发过程中可能会适得其反,阻止您看到刚刚在应用程序中进行的更改。因此,spring-boot-devtools 模块默认情况下禁用缓存选项。
缓存选项通常通过 application.properties 文件中的设置进行配置。例如,Thymeleaf 提供了 spring.thymeleaf.cache 属性。不需要手动设置这些属性,spring-boot-devtools 模块会自动应用合理的开发时间配置。
以下表格列出了应用的所有属性:
| 名称 | 默认值 |
|---|---|
server.error.include-binding-errors | always |
server.error.include-message | always |
server.error.include-stacktrace | always |
server.servlet.jsp.init-parameters.development | true |
server.servlet.session.persistent | true |
spring.freemarker.cache | false |
spring.graphql.graphiql.enabled | true |
spring.groovy.template.cache | false |
spring.h2.console.enabled | true |
spring.mustache.servlet.cache | false |
spring.mvc.log-resolved-exception | true |
spring.reactor.netty.shutdown-quiet-period | 0s |
spring.template.provider.cache | false |
spring.thymeleaf.cache | false |
spring.web.resources.cache.period | 0 |
spring.web.resources.chain.cache | false |
Tip:如果您不希望应用属性默认值,可以在
application.properties中将spring.devtools.add-properties设置为false。
由于在开发 Spring MVC 和 Spring WebFlux 应用程序时需要更多关于 Web 请求的信息,因此开发者工具建议您为 web 日志组启用 DEBUG 日志记录。这将为您提供有关传入请求、处理该请求的处理程序、响应结果和其他详细信息。如果您希望记录所有请求详细信息(包括可能敏感的信息),可以打开 spring.mvc.log-request-details 或 spring.codec.log-request-details 配置属性。
8.3. 自动重启
使用 spring-boot-devtools 的应用程序会在类路径上的文件发生更改时自动重启。这是一个有用的功能,特别是在 IDE 中工作时,因为它提供了代码更改的非常快速的反馈循环。默认情况下,类路径上指向目录的任何条目都会被监视更改。请注意,某些资源(如静态资产和视图模板)不需要重启应用程序。
Note 触发重启
由于 DevTools 监视类路径资源,因此触发重启的唯一方法是更新类路径。无论您使用的是 IDE 还是构建插件,修改的文件都必须重新编译以触发重启。触发类路径更新的方式取决于您使用的工具:
在 Eclipse 中,保存修改后的文件会导致类路径更新并触发重启。
在 IntelliJ IDEA 中,构建项目(
Build +→+ Build Project)具有相同的效果。如果使用构建插件,运行 Maven 的
mvn compile或 Gradle 的gradle build将触发重启。
Tip:如果您使用 Maven 或 Gradle 构建插件进行重启,则必须将
forking设置为enabled。如果禁用forking,则不会创建 devtools 使用的隔离应用程序类加载器,并且重启将无法正常操作。
Note:自动重启与 LiveReload 结合使用效果很好。参见 LiveReload 部分以获取详细信息。如果您使用 JRebel,则会禁用自动重启,而是使用动态类重新加载。其他 devtools 功能(如 LiveReload 和属性覆盖)仍然可以使用。
Tip:DevTools 依赖于应用程序上下文的关闭钩子来关闭它在重启期间。如果您已禁用关闭钩子(
SpringApplication.setRegisterShutdownHook(false)),它将无法正常工作。
Tip:DevTools 需要自定义
ApplicationContext使用的ResourceLoader。如果您的应用程序已经提供了一个,它将被包装。不支持直接覆盖ApplicationContext上的getResource方法。
Warning:不支持使用 AspectJ 编织的自动重启。
Note 重启 vs 重新加载
Spring Boot 提供的重启技术通过使用两个类加载器来工作。不会更改的类(例如,来自第三方 jar 的类)被加载到 base 类加载器中。您正在积极开发的类被加载到 restart 类加载器中。当应用程序重新启动时,restart 类加载器被丢弃,并创建一个新的类加载器。这种方法意味着应用程序重启通常比 “冷启动” 快得多,因为 base 类加载器已经可用并且已经填充。
如果您发现重启对于您的应用程序来说不够快,或者遇到类加载问题,您可以考虑使用 ZeroTurnaround 的 JRebel 等重新加载技术。这些技术通过在加载类时重写它们来使它们更适合重新加载。
8.3.1. 记录条件评估的更改
默认情况下,每次应用程序重启时,都会记录显示条件评估增量的报告。该报告显示了您对应用程序的自动配置进行的更改,例如添加或删除 bean 以及设置配置属性。
要禁用记录报告,请设置以下属性:
Properties
spring.devtools.restart.log-condition-evaluation-delta=false8.3.2. 排除资源
某些资源不一定需要在更改时触发重启。例如,Thymeleaf 模板可以就地编辑。默认情况下,更改 /META-INF/maven、/META-INF/resources、/resources、/static、/public 或 /templates 中的资源不会触发重启,但会触发 live reload。如果您想自定义这些排除项,可以使用 spring.devtools.restart.exclude 属性。例如,要仅排除 /static 和 /public,请设置以下属性:
Properties
spring.devtools.restart.exclude=static/**,public/**Note:如果您想保留这些默认值并添加其他排除项,请改用
spring.devtools.restart.additional-exclude属性。
8.3.3. 监视其他路径
您可能希望在对不在类路径上的文件进行更改时重新启动或重新加载您的应用程序。为此,请使用 spring.devtools.restart.additional-paths 属性配置要监视更改的其他路径。您可以使用上面描述的 spring.devtools.restart.exclude 属性来控制是否在其他路径下的更改触发完全重启或 live reload。
8.3.4. 禁用重启
如果您不想使用重启功能,可以使用 spring.devtools.restart.enabled 属性禁用它。在大多数情况下,您可以在 application.properties 中设置此属性(这样做仍然会初始化重启类加载器,但不会监视文件更改)。
如果您需要完全禁用重启支持(例如,因为它与特定库不兼容),则需要在调用 SpringApplication.run(…) 之前将 spring.devtools.restart.enabled System 属性设置为 false,如下例所示:
Java
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);
}
}1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
8.3.5. 使用触发文件
如果您使用的是持续编译更改文件的 IDE,您可能更喜欢仅在特定时间触发重启。为此,您可以使用 “触发文件”,这是一个特殊文件,必须在您想要实际触发重启检查时进行修改。
Tip:对文件的任何更新都会触发检查,但重启实际上仅在 Devtools 检测到有事情要做时才会发生。
要使用触发文件,请将 spring.devtools.restart.trigger-file 属性设置为触发文件的名称(不包括任何路径)。触发文件必须出现在类路径的某个位置。
例如,如果您有一个具有以下结构的项目:
Text
src
+- main
+- resources
+- .reloadtrigger那么您的 trigger-file 属性将是:
Properties
spring.devtools.restart.trigger-file=.reloadtrigger现在重启只会在更新 src/main/resources/.reloadtrigger 时发生。
Note:您可能希望将
spring.devtools.restart.trigger-file设置为全局设置,以便所有项目的行为相同。
某些 IDE 具有功能,可以使您无需手动更新触发文件。Spring Tools for Eclipse 和 IntelliJ IDEA (Ultimate Edition) 都有这样的支持。使用 Spring Tools,您可以使用控制台视图中的 “重新加载” 按钮(只要您的 trigger-file 命名为 .reloadtrigger)。对于 IntelliJ IDEA,您可以按照其文档中的说明进行操作。
8.3.6. 自定义重启类加载器
如 Restart vs Reload 部分所述,重启功能是通过使用两个类加载器实现的。如果这导致问题,您可能需要自定义哪个类加载器加载哪些内容。
默认情况下,IDE 中的任何打开项目都会使用 “restart” 类加载器加载,而任何常规 .jar 文件都会使用 “base” 类加载器加载。如果您使用 mvn spring-boot:run 或 gradle bootRun,则包含您的 @SpringBootApplication 的项目将使用 “restart” 类加载器加载,其他所有内容都使用 “base” 类加载器加载。
您可以通过创建 META-INF/spring-devtools.properties 文件来指示 Spring Boot 使用不同的类加载器加载项目的一部分。spring-devtools.properties 文件可以包含以 restart.exclude 和 restart.include 为前缀的属性。include 元素是应该拉入 “restart” 类加载器的项目,而 exclude 元素是应该推入 “base” 类加载器的项目。属性的值是应用于类路径的正则表达式,如下例所示:
Properties
restart.exclude.companycommonlibs=/mycorp-common-[\\w\\d-\\.]+\\.jar
restart.include.projectcommon=/mycorp-myproj-[\\w\\d-\\.]+\\.jarTip:所有属性键必须是唯一的。只要属性以
restart.include.或restart.exclude.开头,它就会被考虑。
Note:类路径中的所有
META-INF/spring-devtools.properties文件都会被加载。您可以在项目中打包文件,也可以在项目消费的库中打包文件。
8.3.7. 已知限制
重启功能与使用标准 ObjectInputStream 反序列化的对象不兼容。如果您需要反序列化数据,您可能需要结合 Thread.currentThread().getContextClassLoader() 使用 Spring 的 ConfigurableObjectInputStream。
不幸的是,一些第三方库在不考虑上下文类加载器的情况下进行反序列化。如果您发现这样的问题,您需要向原始作者请求修复。
8.4. LiveReload
spring-boot-devtools 模块包括一个嵌入式 LiveReload 服务器,可以用来在资源更改时触发浏览器刷新。LiveReload 浏览器扩展可以免费用于 Chrome、Firefox 和 Safari。您可以通过在市场或商店中搜索 'LiveReload' 来找到这些扩展。
如果您不想在应用程序运行时启动 LiveReload 服务器,可以将 spring.devtools.livereload.enabled 属性设置为 false。
Tip:您一次只能运行一个 LiveReload 服务器。在启动应用程序之前,请确保没有其他 LiveReload 服务器正在运行。如果您从 IDE 启动多个应用程序,则只有第一个应用程序具有 LiveReload 支持。
Warning:要在文件更改时触发 LiveReload,必须启用自动重启。
8.5. 全局设置
您可以通过将以下任何文件添加到 $HOME/.config/spring-boot 目录来配置全局 devtools 设置:
spring-boot-devtools.propertiesspring-boot-devtools.yamlspring-boot-devtools.yml
添加到这些文件中的任何属性都适用于所有机器上使用 devtools 的 Spring Boot 应用程序。例如,要配置重启以始终使用触发文件,请将以下属性添加到您的 spring-boot-devtools 文件中:
Properties
spring.devtools.restart.trigger-file=.reloadtrigger默认情况下,$HOME 是用户的主目录。要自定义此位置,请设置 SPRING_DEVTOOLS_HOME 环境变量或 spring.devtools.home 系统属性。
Tip:如果在
$HOME/.config/spring-boot中找不到 devtools 配置文件,则会搜索$HOME目录的根目录,以查找.spring-boot-devtools.properties文件的存在。这允许您与使用旧版本 Spring Boot 的应用程序共享 devtools 全局配置,该版本不支持$HOME/.config/spring-boot位置。
Tip
不支持 devtools 属性/yaml 文件中的配置文件。
.spring-boot-devtools.properties中激活的任何配置文件都不会影响加载特定于配置文件的文件。不支持 YAML 和 Properties 文件中的特定于配置文件的文件名(形式为spring-boot-devtools-<profile>.properties)和spring.config.activate.on-profile文档。
8.5.1. 配置文件系统监视器
FileSystemWatcher 通过以某个时间间隔轮询类更改,然后等待预定义的静默期以确保没有更多更改来工作。由于 Spring Boot 完全依赖 IDE 编译和复制文件到 Spring Boot 可以读取它们的位置,因此您可能会发现某些更改在 devtools 重启应用程序时未反映。如果您经常观察到这种问题,请尝试将 spring.devtools.restart.poll-interval 和 spring.devtools.restart.quiet-period 参数增加到适合您的开发环境的值:
Properties
spring.devtools.restart.poll-interval=2s
spring.devtools.restart.quiet-period=1s监视的类路径目录现在每 2 秒轮询一次更改,并保持 1 秒的静默期以确保没有额外的类更改。
8.6. 远程应用程序
Spring Boot 开发者工具不仅限于本地开发。您还可以在远程运行应用程序时使用几个功能。远程支持是可选的,因为启用它可能会带来安全风险。它应该只在受信任的网络上运行时启用,或者在使用 SSL 时启用。如果这两个选项对您都不可用,您不应该使用 DevTools 的远程支持。您绝对不应该在生产部署中启用支持。
要启用它,您需要确保 devtools 包含在重新打包的归档文件中,如下例所示:
XML
<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 属性时,会自动启用服务器组件。客户端组件必须手动启动。
Tip:远程 devtools 不支持 Spring WebFlux 应用程序。
8.6.1. 运行远程客户端应用程序
远程客户端应用程序设计为在 IDE 中运行。您需要使用与远程项目相同的类路径运行 org.springframework.boot.devtools.RemoteSpringApplication。应用程序的单个必需参数是它连接的远程 URL。
例如,如果您使用的是 Eclipse 或 Spring Tools,并且您有一个名为 my-app 的项目,您已将其部署到 Cloud Foundry,您将执行以下操作:
从
Run菜单中选择Run Configurations…。创建一个新的
Java Application“启动配置”。浏览
my-app项目。使用
org.springframework.boot.devtools.RemoteSpringApplication作为主类。将
https://myapp.cfapps.io添加到Program arguments(或者您的远程 URL 是什么)。
运行的远程客户端可能类似于以下列表:
Text
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ ___ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | | _ \___ _ __ ___| |_ ___ \ \ \ \
\\/ ___)| |_)| | | | | || (_| []::::::[] / -_) ' \/ _ \ _/ -_) ) ) ) )
' |____| .__|_| |_|_| |_\__, | |_|_\___|_|_|_\___/\__\___|/ / / /
=========|_|==============|___/===================================/_/_/_/
:: Spring Boot Remote :: (v2.7.18)
2023-11-23 07:23:21.930 INFO 28462 --- [ main] o.s.b.devtools.RemoteSpringApplication : Starting RemoteSpringApplication v2.7.18 using Java 1.8.0_392 on myhost with PID 28462 (/Users/myuser/.m2/repository/org/springframework/boot/spring-boot-devtools/2.7.18/spring-boot-devtools-2.7.18.jar started by myuser in /opt/apps/)
2023-11-23 07:23:21.936 INFO 28462 --- [ main] o.s.b.devtools.RemoteSpringApplication : No active profile set, falling back to 1 default profile: "default"
2023-11-23 07:23:22.314 INFO 28462 --- [ main] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2023-11-23 07:23:22.338 INFO 28462 --- [ main] o.s.b.devtools.RemoteSpringApplication : Started RemoteSpringApplication in 0.858 seconds (JVM running for 1.35)Tip:因为远程客户端使用与实际应用程序相同的类路径,所以它可以直接读取应用程序属性。这是
spring.devtools.remote.secret属性如何被读取并传递给服务器进行身份验证的方式。
Note:始终建议使用
https://作为连接协议,以便加密流量并防止拦截密码。
Note:如果您需要使用代理访问远程应用程序,请配置
spring.devtools.remote.proxy.host和spring.devtools.remote.proxy.port属性。
8.6.2. 远程更新
远程客户端监视您的应用程序类路径以查找更改,方式与本地重启相同。任何更新的资源都会推送到远程应用程序,并(如果需要)触发重启。如果您正在迭代使用云服务的功能,而您没有本地服务,这可能会很有帮助。通常,远程更新和重启比完整的重建和部署周期快得多。
在较慢的开发环境中,可能会发生静默期不够的情况,并且类更改可能会分成批次。在上传第一批类更改后,服务器会重新启动。下一批无法发送到应用程序,因为服务器正在重新启动。
这通常表现为 RemoteSpringApplication 日志中关于无法上传某些类的警告,以及随后的重试。但它也可能导致应用程序代码不一致和第一批更改上传后无法重新启动。如果您经常观察到这种问题,请尝试将 spring.devtools.restart.poll-interval 和 spring.devtools.restart.quiet-period 参数增加到适合您的开发环境的值。请参阅配置文件系统监视器部分以配置这些属性。
Tip:仅在远程客户端运行时监视文件。如果您在启动远程客户端之前更改了文件,则不会将其推送到远程服务器。
9. 为生产打包您的应用程序
可执行 jar 可以用于生产部署。由于它们是自包含的,因此它们也非常适合基于云的部署。
有关其他 “生产就绪” 功能(例如健康、审计和指标 REST 或 JMX 端点),请考虑添加 spring-boot-actuator。请参阅生产就绪功能以获取详细信息。
10. 接下来阅读什么
您现在应该了解如何使用 Spring Boot 以及应该遵循的一些最佳实践。您现在可以继续深入学习特定的 Spring Boot 功能,或者您可以跳过并阅读 Spring Boot 的 “生产就绪” 方面。