6. 使用 Spring Boot进行开发(Developing with Spring Boot)
本节详细介绍了如何使用Spring Boot。它涵盖考虑构建系统、自动配置以及如何运行应用程序等主题。我们还介绍一些 Spring Boot 最新做法。虽然 Spring Boot 没有什么特别之处(它只是你使用的一个库),它会有一些建议,当您遵循这些建议,可以使您的开发过程更容易一些。
如果您从 Spring Boot 开始,在进入本章节之前,你应该阅读 入门指南 。
6.1 构建系统(Build Systems)
强烈建议您选择一个 依赖管理 来构建项目,而且可以使用发布到 “Maven Central” 库的组件。我们建议您选择 Maven 或 Gradle。你也可以让 Spring Boot 和其它构建系统(例如Ant)配合使用,但是它们的支持并不完善。
6.1.1 依赖管理(Dependency Management)
Spring Boot 的每个版本都会提供其支持的依赖项列表。实际上,你不需要提供构建配置中依赖项的版本,因为Spring Boot 会为您管理这些依赖项。当您升级 Spring Boot 本身时,这些依赖项也会统一升级。
::: tip 提示
如果需要,您仍然可以指定依赖版本并覆盖 Spring Boot 的设置版本。
:::
列表中包含了所有的 Spring 模块,以及第三方库的详细列表。该列表以标准清单spring-boot-dependencies
的形式提供,可以与 Maven 和 Gradle 一起使用。
::: warning 警告
Spring Boot 的每个版本都与 Spring Framework 的集成版本息息相关。我们强烈建议你不要指定它的版本。
:::
6.1.2 Maven
要了解如何将 Spring Boot 与 Maven 结合使用,请参阅 Spring Boot 的 Maven 插件文档:
- 参考资料 (HTML 和 PDF)
- API
6.1.3 Gradle
要了解如何将 Spring Boot 与 Gradle 结合使用,请参阅 Spring Boot 的 Gradle 插件文档:
- 参考资料(HTML 和 PDF)
- API
6.1.4 Ant
使用 Apache Ant+Ivy 可以构建 Spring Boot 项目。此外,“AntLib” 模块 spring-boot-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
文件应与下方示例类似:
<projectxmlns: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-SNAPSHOT"/><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>
::: tip 提示
如果不想使用 spring-boot-antlib
模块,请参阅 Build an Executable Archive From Ant without Using spring-boot-antlib 。
:::
6.1.5 Starters
场景启动器是一组依赖关系的描述,您可以将其包含在应用程序中。你可以获得所需的全部 Spring 以及相关技术的一站式服务,而无需搜索示例代码和复制粘贴依赖描述符。例如,如果您开始使用 Spring 和 JPA 进行数据库访问,请在项目中包含 spring-boot-starter-data-jpa
依赖。
场景启动器包含大量的依赖项,这些依赖项可以让项目快速启动和运行,并提供一套一致的、受支持的依赖项传递。
::: tip What is in a name
所有官方场景启动器都遵循类型的命名模式; spring-boot-starter-*
,其中 *
为特定类型的应用程序。这种命名结构的目的是需要查找场景启动器时提供帮助。许多集成开发环境中的 Maven 都可以让您按名称搜索依赖项。例如,如果安装了相应的 Eclipse 或 Spring 插件,就可以在 POM 编辑器中键入 ctrl-space
键,然后键入“spring-boot-starter”,查看完整列表。
在 “创建自己的场景启动器” 部分所述,第三方启动器不应该以spring-boot
开头,因为spring-boot
是 Spring Boot 官方库的专属开通。相反,第三方启动器通常以项目名称开通,例如,名为 thirdpartyproject
的第三方启动器通常会命名为thirdpartyproject-spring-boot-starter
。
:::
以下场景启动器是 Spring Boot 官方提供的,都属于 org.springframework.boot
组:
表 1. Spring Boot 应用程序启动器
Name | Description |
---|---|
spring-boot-starter | 核心启动器,包括自动配置、日志记录和 YAML |
spring-boot-starter-activemq | 集成 Apache ActiveMQ 的 JMS messaging 启动器 |
spring-boot-starter-amqp | 集成 Spring AMQP 和 Rabbit MQ 的启动器 |
spring-boot-starter-aop | 集成 Spring AOP 和 AspectJ 进行面向切面编程的启动器 |
spring-boot-starter-artemis | 集成 Apache Artemis 的 JMS messaging 启动器 |
spring-boot-starter-batch | 集成 Spring Batch 的启动器 |
spring-boot-starter-cache | 集成 Spring Framework 缓存支持的启动器 |
spring-boot-starter-data-cassandra | 集成 Cassandra 分布式数据库和 Spring Data Cassandra 的启动器 |
spring-boot-starter-data-cassandra-reactive | 集成 Cassandra 分布式数据库和 Spring Data Cassandra Reactive 的启动器 |
spring-boot-starter-data-couchbase | 集成面向文档的 Couchbase 数据库和 Spring Data Couchbase 的启动器 |
spring-boot-starter-data-couchbase-reactive | 集成面向文档的 Couchbase 数据库和 Spring Data Couchbase Reactive 的启动器 |
spring-boot-starter-data-elasticsearch | 集成 Elasticsearch 搜索、分析引擎和 Spring Data Elasticsearch 的启动器 |
spring-boot-starter-data-jdbc | 集成 Spring Data JDBC 的启动器 |
spring-boot-starter-data-jpa | 集成 Spring Data JPA 和 Hibernate 的启动器 |
spring-boot-starter-data-ldap | 集成 Spring Data LDAP 的启动器 |
spring-boot-starter-data-mongodb | 集成面向文档的 MongoDB 数据库和 Spring Data MongoDB 的启动器 |
spring-boot-starter-data-mongodb-reactive | 集成面向文档的 MongoDB 数据库和 Spring Data MongoDB Reactive 的启动器 |
spring-boot-starter-data-neo4j | 集成 Neo4j 图形数据库和 Spring Data Neo4j 的启动器 |
spring-boot-starter-data-r2dbc | 集成 Spring Data R2DBC 的启动器 |
spring-boot-starter-data-redis | 集成 Redis 存储、Spring Data Redis 和 Lettuce 客户端的启动器 |
spring-boot-starter-data-redis-reactive | 集成 Redis 存储、Spring Data Redis reactive 和 Lettuce 客户端的启动器 |
spring-boot-starter-data-rest | 使用 Spring Data REST 和 Spring MVC 通过 REST 访问 Spring Data存储库的启动器 |
spring-boot-starter-freemarker | 使用 FreeMarker 视图构建 MVC 网络应用程序的启动器 |
spring-boot-starter-graphql | 使用 Spring GraphQL 构建 GraphQL 应用程序的启动器 |
spring-boot-starter-groovy-templates | 使用 Groovy 模板视图构建 MVC 网络应用程序的启动器 |
spring-boot-starter-hateoas | 使用 Spring MVC 和 Spring HATEOAS 构建基于超媒体的 RESTful 网络应用程序的启动器 |
spring-boot-starter-integration | 集成 Spring Integration 的启动器 |
spring-boot-starter-jdbc | 集成 HikariCP 连接池的JDBC启动器 |
spring-boot-starter-jersey | 使用 JAX-RS 和 Jersey 构建 RESTful 网络应用程序的启动器。可以代替 spring-boot-starter-web |
spring-boot-starter-jooq | 使用 jOOQ 通过JDBC 访问 SQL 数据库的启动器。可以代替 spring-boot-starter-data-jpa 或 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 视图构建网络应用程序的启动器 |
spring-boot-starter-oauth2-client | 使用 Spring Security 的 OAuth2/OpenID 连接客户端功能的启动器 |
spring-boot-starter-oauth2-resource-server | 使用 Spring Security 的 OAuth2 资源服务功能的启动器 |
spring-boot-starter-quartz | 集成 Quartz scheduler 的启动器 |
spring-boot-starter-rsocket | 用于构建 RSocket 客户端和服务器的启动器 |
spring-boot-starter-security | 集成 Spring Security 的启动器 |
spring-boot-starter-test | 使用 JUnit Jupiter、Hamcrest 和 Mockito 等库测试 Spring Boot 应用程序的启动器 |
spring-boot-starter-thymeleaf | 使用 Thymeleaf 视图构建 MVC 应用程序的启动器 |
spring-boot-starter-validation | 使用 Hibernate 验证器进行 Java Bean 验证的启动器 |
spring-boot-starter-web | 使用 Spring MVC 构建Web(包括 RESTful)应用程序的启动器。使用 Tomcat 作为默认嵌入式容器 |
spring-boot-starter-web-services | 集成 Spring Web Services 的启动器 |
spring-boot-starter-webflux | 使用 Spring Framework 的 Reactive Web 支持构建 WebFlux 应用程序的启动器 |
spring-boot-starter-websocket | 使用 Spring Framework 的 WebSocket 支持构建WebSocket启动器 |
除应用程序启动器外,还可使用以下启动器添加 production ready 功能:
表 2. Spring Boot 生产环境启动器
Name | Description |
---|---|
spring-boot-starter-actuator | 使用 Spring Boot 的 Actuator 的启动器,它提供production ready功能,帮助您监控和管理应用程序 |
最后,Spring Boot 还包括一些用于排除或交换特定技术方向的启动器:
表 3. Spring Boot 技术启动器
Name | Description |
---|---|
spring-boot-starter-jetty | 使用 Jetty 作为嵌入式 servlet 容器的启动器。可以替代 spring-boot-starter-tomcat |
spring-boot-starter-log4j2 | 使用 Log4j2 进行日志记录的启动器。可以替代 spring-boot-starter-logging |
spring-boot-starter-logging | 使用 Logback 进行日志记录的启动器。默认的日志启动器 |
spring-boot-starter-reactor-netty | 使用 Reactor Netty 作为嵌入式响应式 HTTP 服务器的启动器 |
spring-boot-starter-tomcat | 使用 Tomcat 作为嵌入式 servlet 容器的启动器。使用默认 servlet 容器启动器 spring-boot-starter-web |
spring-boot-starter-undertow | 使用 Undertow 作为嵌入式 servlet 容器的启动器。可以替代 spring-boot-starter-tomcat |
要深入了解技术交互方向的知识,请参阅r swapping web server 和 logging system。
::: tip 提示
有关其他社区贡献的启动器列表,请参阅 GitHub 上的spring-boot-starters
模块的 README 文件 。
:::
6.2 构建你的代码(Structuring Your Code)
Spring Boot 不需要任何特定的代码结构。然而,也有一些最佳实现是很有帮助的。
6.2.1 使用默认包(Using the “default” Package)
当一个类不包含 package
声明。它通常被认为在一个“默认包”中。一般不建议使用 “默认包” ,应该避免使用。它会给使用 @ComponentScan
, @ConfigurationPropertiesScan
, @EntityScan
或 @SpringBootApplication
注解的 Spring Boot 应用程序带来很多问题,因为每个 jar 中的每个类都会被读取。
::: tip 提示
我们建议您遵循 Java 推荐的软件包命名约定,并使用相反的域名(例如,com.example.project
)。
:::
6.2.2 定位主程序类(Locating the Main Application Class)
我们通常建议将主程序类放到根包中。 @SpringBootApplication
注解 会放在主类上,它隐式地为某些项目定义了一个基础的 “search package” 。例如,如果你正在编写一个 JPA 应用程序,那么使用 @SpringBootApplication
注解的类所在的包将会搜索 @Entity
。使用根包还可以让组件只应用到你的项目。
::: tip 提示
如果你不使用 @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
,如下所示:
@SpringBootApplicationpublic class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}}
6.3 配置类(Configuration Classes)
Spring Boot 偏好基于 Java 的配置。虽然可以将. SpringApplication
和 XML 结合使用,但是我们通常建议您将一个 @Configuration
类作为主要来源。通常,定义的 main
方法的类适合作为主要的 @Configuration
。
::: tip 提示
在互联网上发布了很多使用XML配置的Spring配置示例,如果可能,请尽量使用基于Java的等效配置。搜索 Enable*
注解是一个很多方法。
:::
6.3.1 导入其它配置类(Importing Additional Configuration Classes)
你不需要把全部的 @Configuration
放在一个类中。 @Import
注解可以用于导入其它配置类。或者,您可以使用 @ComponentScan
主动扫描注入全部的Spring组件,包括 @Configuration
。
6.3.2 导入XML配置(Importing XML Configuration)
如果您一定要使用基于XML的配置,我们建议您从 @Configuration
类开始。然后,您可以使用 @ImportResource
注解来加载XML配置文件。
6.4 自动配置(Auto-configuration)
Spring Boot 自动配置会尝试根据您添加的jar依赖关系自动配置您的 Spring 应用程序。例如,如果 HSQLDB
在类路径上,而您没有手动配置任何数据库连接nean,则 Spring Boot 会自动配置内存数据库。
你需要在其中一个 @Configuration
类中添加@EnableAutoConfiguration
或 @SpringBootApplication
注解,从而添加自动配置功能
::: tip 提示
你只能添加一个 @SpringBootApplication
或 @EnableAutoConfiguration
注解。我们通常建议你只在主要的 @Configuration
添加其中一个组件。
:::
6.4.1 逐步取代自动配置(Gradually Replacing Auto-configuration)
自动配置是非侵入性的。在任何时候,你都可以开始定义自己的配置,用来取代自动配置的特定部分。例如,如果您添加了自己的 DataSource
bean,默认嵌入式数据库不在进行支持。
个你需要了解当前应用的自动配置及其原因,请使用 --debug
开关启动应用程序。这样做可以为选定的核心日志记录器启用debug日志,并将报告记录到控制台。
6.4.2 禁用特定的自动配置类(Disabling Specific Auto-configuration Classes)
如果你发现当前应用中您不需要的特定自动配置类,你可以使用 @SpringBootApplication
的exclude属性来禁用它们,如下所示:
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })public class MyApplication {}
如果类不在classpath上,可以使用注解的 excludeName
属性来指定全限定类名。如果你更倾向于使用 @EnableAutoConfiguration
而不是 @SpringBootApplication
,也可以使用exclude
和 excludeName
,最后,你可以使用 spring.autoconfigure.exclude
属性来控制需要排除的自动配置类列表。
::: tip 提示
您可以在注解级别的和使用属性来定义排除项。
:::
::: tip 提示
尽管自动配置类是 public
,但是该类唯一被认为公共API的部分是类名,该名称可用于禁用自动配置。这些类的实际内容(比如嵌套配置类或bean方法)仅供内部使用,我们不建议直接使用这些。
:::
6.4.3 自动配置包路径(Auto-configuration Packages)
自动配置包路径是各种自动配置功能扫描实体和Spring Data repositories默认查找的包路径。 @EnableAutoConfiguration
注解(或者直接通过@SpringBootApplication
)来决定默认的自动配置包路径。可以使用@AutoConfigurationPackage
注解配置其它软件包路径。
6.5 Spring Beans 和依赖注入(Spring Beans and Dependency Injection)
你可以自由使用任何标准的 Spring Framework 技术来定义您的 bean 及其注入的依赖项。我们通常建议使用构造器注入的方式来进行依赖注入,并使用 @ComponentScan
来查找Bean。
如果你按照上面的建议(将主程序类放到顶级包中)修改代码架构,你就可以添加 @ComponentScan
(无需任何参数)或者使用 @SpringBootApplication
(包含前者)。所有的应用程序组件(@Component
, @Service
, @Repository
, @Controller
等)都会自动注入成 Spring Bean。
下面的示例显示了一个使用构造器注入获取所需 RiskAssessor
Bean 的 @Service
Bean:
@Servicepublic class MyAccountService implements AccountService {private final RiskAssessor riskAssessor;public MyAccountService(RiskAssessor riskAssessor) {this.riskAssessor = riskAssessor;}// ...}
如果一个Bean有多个构造函数,则需要用 @Autowired
来标记您希望Spring使用的构造函数:
@Servicepublic class MyAccountService implements AccountService {private final RiskAssessor riskAssessor;private final PrintStream out;@Autowiredpublic MyAccountService(RiskAssessor riskAssessor) {this.riskAssessor = riskAssessor;this.out = System.out;}public MyAccountService(RiskAssessor riskAssessor, PrintStream out) {this.riskAssessor = riskAssessor;this.out = out;}// ...}
::: tip 提示
请注意,使用构造器注入可以将 riskAssessor
字段标记为 final
字段,表示以后不能更改。
:::
6.6 使用@SpringBootApplication注解(Using the @SpringBootApplication Annotation)
许多 Spring Boot 开发人员都希望自己的应用程序能够使用自动配置、组件扫描,并能在 “application class”定义额外的配置。只需要使用 @SpringBootApplication
注解就可以启用这三个功能,即:
@EnableAutoConfiguration
:启用 Spring Boot 的自动配置机制@ComponentScan
:在应用程序所在包路径上启动@Component
扫描 (参阅 the best practices)@SpringBootConfiguration
:启用在上下文中注册额外的 Bean 或导入额外的配置类。她是Spring标准@Configuration
的替代品,有助于集成测试红的 configuration detection 。
// Same as @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan@SpringBootApplicationpublic class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}}
::: tip 提示
@SpringBootApplication
提供了别名来自定义 @EnableAutoConfiguration
和 @ComponentScan
的属性。
:::
::: tip 提示
这些功能都不是强制性的,你可以选择用它所启用的任何功能来替代这个单一注解。例如,您可能不想在应用程序中使用组件扫描或配置属性扫描:
@SpringBootConfiguration(proxyBeanMethods = false)@EnableAutoConfiguration@Import({ SomeConfiguration.class, AnotherConfiguration.class })public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}}
在上述示例中, MyApplication
和其它 Spring Boot 应用程序一样,只是 @Component
-annotated 类和 @ConfigurationProperties
-annotated 类不会被自动扫描到,而用户定义Bean的会被显式导入 (参阅 @Import
)。
:::
6.7 运行应用程序(Running Your Application)
将应用程序打包成jar并使用嵌入式HTTP服务器是最大优势之一,您可以像运行其它服务器一样运行应用程序。调试Spring Boot应用程序也很容易。您不需要任何特殊的IDE插件或扩展。
::: tip 备注
本章节仅涉及打包成jar文件。如果您选择将应用程序打包成war文件吗,请参阅服务器和IDE文档。
:::
6.7.1 使用IDE运行(Running From an IDE)
您可以将 Spring Boot 应用程序作为一个 Java 应用程序在IDE中运行。然而,您首先需要导入您的项目。导入步骤因IDE和构建系统而异。大多数 IDE 可以直接导入 Maven 项目。例如,Eclipse 用户可以 File
菜单中选择 Import…
→ Existing Maven Projects
。
如果无法直接将项目导入 IDE,则可以使用build插件生成IDE基础开发架构。Maven 包含很多用于 Eclipse 和 IDEA 的插件。 Gradle 为 various IDEs 也提供了插件。
::: tip 提示
如果无意中运行了Web应用程序两次,就会看到 “Port already in use” 错误。Spring 工具用户可以使用 重新启动(Relaunch
)按钮而不是运行(Run
)按钮以确保关闭任何现有实例。
:::
6.7.2 作为打包程序运行(Running as a Packaged Application)
如果您使用 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
6.7.3 使用Maven插件(Using the Maven Plugin)
Spring Boot Maven 插件包含 run
命令,可以用于快速编译和运行您的应用程序。应用程序以 exploded 形式运行,就像在 IDE 中一样。下面示例展示了运行SpringBoot应用程序的命令:
$ mvn spring-boot:run
您可以需要使用 MAVEN_OPTS
操作系统环境变量,如下所示:
$ export MAVEN_OPTS=-Xmx1024m
6.7.4 使用Gradle插件(Using the Gradle Plugin)
Spring Boot Gradle 插件包括 bootRun
任务,可以以1 exploded 的形式运行您的应用程序。每当您应用 org.springframework.boot
和 java
插件时,都会添加 bootRun
任务,如下所示:
$ gradle bootRun
您可以需要使用 JAVA_OPTS
操作系统环境变量,如下所示:
$ export JAVA_OPTS=-Xmx1024m
6.7.5 热插拔(Hot Swapping)
由于 Spring Boot 应用程序只是普通的 Java 应用程序,因此,JVM 热插拔可以开箱即用。 JVM 热插拔在某种程度上受限于它可以替换的字节码。要获得更完整的解决方案,可以使用 JRebel 。
spring-boot-devtools
模块也支持快速重启应用程序。详情参阅 Hot swapping “How-to” 。
6.8 Developer Tools
Spring Boot 包含一套额外的工具,可以让应用程序开发体验更加愉快。spring-boot-devtools
模块可以包含在任何项目中,以便提供额外的开发功能。如果要包含 devtools 支持,请将模块依赖添加到您的构建中,如下所示:
Maven
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency></dependencies>
Gradle
configurations {developmentOnlyruntimeClasspath {extendsFrom developmentOnly}}dependencies {developmentOnly("org.springframework.boot:spring-boot-devtools")}
::: tip 注意事项
Devtools 可能会导致类加载问题,尤其是在多模块项目中。 Diagnosing Classloading Issues 解释了如何诊断和解决这些问题。
:::
::: tip 提示
运行打包之后的应用程序是,会自动禁用devtools。
如果您的应用程序是使用 java -jar
启动,或者使用一个特定的类加载器启动,那么它将被视为“production application”。您可以使用 spring.devtools.restart.enabled
属性来控制是否启用 devtools。
如果要启用,而不考虑类加载器,请设置 -Dspring.devtools.restart.enabled=true
。在生产环境运行devtools 会带来安全风险.
如果要禁用 devtools,请排除依赖关系或设置 -Dspring.devtools.restart.enabled=false
。
:::
::: tip 提示
在 Maven 中将依赖关系标记为可选,或在Gradle 中使用 developmentOnly
配置(如上图所示),可以防止devtools 被应用到项目的其它模块中。
:::
::: tip 提示
重新打包的归档文件默认不包括 devtools 。如果需要使用 某些远程 devtools 功能,则需要包含它。当使用 Maven 插件时,将 excludeDevtools
属性设置为 false
。当使用 Gradle 插件时,配置依赖的类路径包含 developmentOnly
配置.
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludeDevtools>false</excludeDevtools></configuration></plugin></plugins></build>
:::
6.8.1 诊断类加载问题(Diagnosing Classloading Issues)
正如 重启 vs 重载 部分所述,重启功能是通过使用两个类加载器实现的,对于大多数应用程序,这种方法效果良好。然而,又是会导致类加载问题,特别是在多模块项目中。
判断类加载问题是否由devtools 和两个类加载器,可以尝试禁用重启. 如果问题得到解决,请 customize the restart classloader 使其包含整个项目。
6.8.2 Propert默认值(Property Defaults)
Spring Boot 支持一些库使用缓存来提高性能。例如,模板引擎 缓存已编译的模板,以避免重复解析模板文件。此外,Spring MVC 还可以在提供静态资源时为响应添加HTTP缓存响应头。
虽然缓存在生产中非常有益,但在开发过程中却可能适得其反,让你无法看到刚刚在应用程序中做出的更改。因此,spring-boot-devtools 默认禁用缓存选项。
缓存选项通常由 application.properties
文件来进行配置的。例如,Thymeleaf 提供了 spring.thymeleaf.cache
属性。无需手动配置这些属性, spring-boot-devtools
模块会提供开发时合理的配置
下表列出了应用的所有属性:
Name | Default Value |
---|---|
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
logging group启用 DEBUG
日志。这将为您提供有关传入请求、处理程序、响应结果和其他详细信息。如果希望记录所有请求的详细信息(包括潜在的敏感信息),您可以打开 spring.mvc.log-request-details
或 spring.codec.log-request-details
配置属性.
6.8.3 自动重启(Automatic Restart)
只要类路径上的文件发生改变,使用 spring-boot-devtools
的应用程序就会自动重启。在IDE中这是一个非常有用的功能,因为它为代码修改提供了非常快速的反馈体验。默认情况下,类路径指向的目录中所有文件都会受到控制,以防发生变化。请注意,对于某些资源(如静态资源和视图模板),不需要重新启动应用程序。
::: tip 触发重启
由于 DevTools 监控类路径上的资源,因此触发重启的唯一方式就是更新类路径上的资源。无论你使用的是 IDE还是构build插件,修改后的文件都必须重新编译才能触发重启,更新类路径的方式取决于所使用的工具:
- 在Eclipse中,保存修改后的文件会更新类路径资源并触发重启。
- 在IntelliJ IDEA中,构建项目(
Build +→+ Build Project
) 具体相同效果。 - 如果使用build插件,运行Maven插件的
mvn compile
命令或Gradle插件的gradle build
命令会触发重启。
:::
::: tip 备注
如果使用build插件Maven 或 Gradle进行重启,则必须将 forking
设置为 enabled
。如果禁用 forking,因为devtools 需要一个独立的应用程序类加载器可以使用,所以重启功能将无法使用。
:::
::: tip 提示
自动重启和LiveReload一起使用时效果非常好,详情参阅 LiveReload 部分 。如果使用 JRebel,自动重启功能将会被禁用,以支持动态类重新加载功能。其它devtools 功能(例如LiveReload 和属性覆盖)仍然可以使用。
:::
::: tip 备注
DevTools 依赖于应用程序上下文的shutdown hook 在重启的时候关闭它。如果禁用了shutdown hook (SpringApplication.setRegisterShutdownHook(false)
),它将无法正常使用。
:::
::: tip 备注
DevTools 需要自定义ApplicationContext
所使用的的 ResourceLoader
。如果您的应用程序已经提供了一个,他将会被包装。不支持直接覆盖 ApplicationContext
上的 getResource
方法。
:::
::: tip 注意事项
使用 AspectJ weaving时不支持自动重启。
:::
::: tip 重启 vs 重载
Spring Boot 提供的重启技术是通过使用两个类加载器来实现的。不会更改的类(例如,来自第三方jar的类)会被加载到 base classloader。您正在开发的类将会被加载到 restart classloader 中,当应用程序重启时,restart classloader 将会被丢弃,然后创建一个新的。这种方法意味着应用程序重启的速度比 “cold starts” 要快的多,因为 base classloader 在重启之前已经是可用且已加载。
如果你发现重启对于你的应用程序来说不够快,或者你遇到类加载问题,你可以考虑重载技术,比如 JRebel 。这些技术的原理是在加载类时对其进行重写,使其更易于重载。
:::
记录状态评估中的变化(Logging Changes in Condition Evaluation)
默认情况下,每次重新启动应用程序时,都会记录一份状态评估的报告。该报告会显示应用程序自动配置的更改情况,如添加或删除bean,和配置属性
要禁用状态评估记录,请设置以下属性:
spring:devtools:restart:log-condition-evaluation-delta: false
排除资源(Excluding Resources)
某些资源在更改时不一定需要触发重启。例如,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/**"
::: tip 提示
如果要保留这些默认值并添加其它排除项,请使用 spring.devtools.restart.additional-exclude
属性代替。
:::
监控其它路径(Watching Additional Paths)
当修改不在类路径上的文件时,您可能希望应用程序重启或重载。为此,可以使用 spring.devtools.restart.additional-paths
属性配置其它路径,以便监视修改。您可以使用 the spring.devtools.restart.exclude
属性(如上所诉) 来控制其它路径上的修改是否会触发重启和live reload.
禁用重启(Disabling Restart)
如果不想使用重启功能,您可以使用 spring.devtools.restart.enabled
属性来禁用它。多数情况下,可以在 application.properties
文件配置该属性(这样做仍会初始化restart classloader,但不会监控文件的更改)。
如果您需要完全禁用重启功能(例如,因为它无法和某些特定库一起使用),则需要在调用 SpringApplication.run(…)
之前将 系统
属性 spring.devtools.restart.enabled
设置为 false
,如下所示:
@SpringBootApplicationpublic class MyApplication {public static void main(String[] args) {System.setProperty("spring.devtools.restart.enabled", "false");SpringApplication.run(MyApplication.class, args);}}
使用触发器文件(Using a Trigger File)
如果您使用的IDE会持续编译已修改的文件,但是您更希望只在特定时间触发重启。为此,你可以使用“触发器文件”,这是一个特殊文件,当需要实际触发重启时,必须对其进行修改。
::: tip 备注
修改文件只会触发检查,只有在Devtools 检测到必须执行某些操作时,才会重启。
:::
要使用触发器文件,请将 spring.devtools.restart.trigger-file
属性设置为触发器文件的路径。触发器文件必须在类路径上。
例如,如果您有一个结构如下的项目:
src+- main +- resources+- .reloadtrigger
那么您的 trigger-file
属性如下所示:
spring:devtools:restart:trigger-file: ".reloadtrigger"
现在,只有更新 src/main/resources/.reloadtrigger
时,才会重启。
::: tip 提示
您可能希望将 spring.devtools.restart.trigger-file
设置成 全局设置,这样所有项目的行为方式都是一样的。
:::
有些 IDE 具有不需要手动修改触发器文件的功能。 Spring Tools for Eclipse 和 IntelliJ IDEA (Ultimate Edition) 都支持这种功能,你可以在控制台使用 “reload” 按钮(只要您的 trigger-file
命名为 .reloadtrigger
)。对于 IntelliJ IDEA,您可以按照 文档中的说明进行使用。
自定义重启类加载器(Customizing the Restart Classloader)
正如 重启 vs 重载 部分所诉,重启功能是通过两个类加载器来实现的。如果它导致了问题,你可以需要自定义类加载器需要加载哪些内容。
默认情况下,IDE中任何打开的项目都会使用 “restart” classloader,而 .jar
文件会使用“base” classloader。使用 mvn spring-boot:run
或 gradle bootRun
时也是如此:包含 @SpringBootApplication
的项目使用 “restart” classloader加载,而其它项目则使用 “base” classloader 加载。
你可以通过创建 META-INF/spring-devtools.properties
文件,来指定Spring Boot使用不同的类加载器加载项目的部分内容。spring-devtools.properties
文件可以包含以 restart.exclude
和 restart.include
为前缀的属性。include
属性配置的文件应该放到 “restart” classloader 中,而 exclude
属性配置的文件应该放到 “base” classloader。该属性值是一个 regex 格式,应用在类路径上,如下所示:
restart:exclude:companycommonlibs: "/mycorp-common-[\\w\\d-\\.]+\\.jar"include:projectcommon: "/mycorp-myproj-[\\w\\d-\\.]+\\.jar"
::: tip 备注
所有属性key都必须是唯一的。只要是 restart.include.
或 restart.exclude.
为前缀的属性都要被加载。
:::
::: tip 提示
所有类路径中的 META-INF/spring-devtools.properties
都会被加载。你可以在项目中打包文件,也可以在项目使用的库中打包文件。
:::
已知限制(Known Limitations)
对于使用标准 ObjectInputStream
进行反序列化的对象,重启功能不起作用。如果您需要反序列化数据,可能需要将 Spring 的 ConfigurableObjectInputStream
和 Thread.currentThread().getContextClassLoader()
结合使用。
遗憾的是,一些第三方库在进行反序列化时没有考虑上下文类加载器。如果发现此类问题,需要向原作者申请修复。
6.8.4 LiveReload
spring-boot-devtools
模块包含一个嵌入式 LiveReload 服务器,可以用于在资源发生变化是触发浏览器刷新。LiveReload 浏览器扩展可以免费用于 Chrome, Firefox 和 Safari。您可以在所用浏览器的市场或商店中搜索 ‘LiveReload’ ,找到这些扩展。
如果不想在应用程序运行时启动 LiveReload 服务器,可以将 spring.devtools.livereload.enabled
属性设置为 false
。
::: tip 备注
一次只能运行一个 LiveReload 服务器。启动应用程序前,请确保没有其他 LiveReload 服务器在运行。如果从集成开发环境启动多个应用程序,只有第一个支持 LiveReload。
:::
::: warning 警告
需要在更改文件时触发 LiveReload,必须启用 自动重启 。
:::
6.8.5 全局配置(Global Settings)
在$HOME/.config/spring-boot
目录中添加以下任何文件,即可配置全局devtools设置:
spring-boot-devtools.properties
spring-boot-devtools.yaml
spring-boot-devtools.yml
添加到这些文件中的任何属性都适用于机器上使用 devtools 的所有 Spring Boot 应用程序。例如,要将重启配置为使用 触发器文件,你可以在 spring-boot-devtools
文件中添加以下属性:
spring:devtools:restart:trigger-file: ".reloadtrigger"
默认情况下,$HOME
是用户的主目录。要自定义该位置,请设置环境变量 SPRING_DEVTOOLS_HOME
或系统属性 spring.devtools.home
。
::: tip 备注
如果在 $HOME/.config/spring-boot
中找不到 devtools 配置文件,则会搜索 $HOME
目录中是否存在 .spring-boot-devtools.properties
文件。这样您就可以使用不支持$HOME/.config/spring-boot
位置的旧版 Spring Boot 应用程序共享 devtools 全局配置。
:::
::: tip 备注
devtools properties/yaml 文件不支持Profiles。.spring-boot-devtools.properties
中激活的任何profiles 都不会影响 特定 profile 的配置文件 的加载。YAML 和 Properties 类型文件的特定 Profile 文件名(例如 spring-boot-devtools-.properties
)和 spring.config.activate.on-profile
文件均不支持。
:::
配置文件系统监视器(Configuring File System Watcher)
FileSystemWatcher 的工作原理是以一定时间间隔轮询观察类的修改,然后等待预定义的静默期,以确保不再有修改。由于 Spring Boot 完全依赖 IDE 来编译文件并将其复制到 Spring Boot 可以读取到的位置,因此您可能会发现当 devtools 重启应用程序是,有时某些修改不会被反映出来。如果您经常遇见此类问题,请尝试将 spring.devtools.restart.poll-interval
和 spring.devtools.restart.quiet-period
属性参数设置为您需要的值:
spring:devtools:restart:poll-interval: "2s"quiet-period: "1s"
现在,每2秒钟就会轮询一次,观察受监控的类路径目录是否有变化,并保持1秒钟的静默期,以确保没有其他类变化。
6.8.6 远程应用程序(Remote Applications)
Spring Boot 开发工具不但可以本地开发。您还可以在运行远程应用程序时使用多项功能。远程支持是可选,因为它可能存在安全风险。只有在受信任的网络上运行或者使用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
属性后自动启用。客户端组件必须手动启动。
::: tip 备注
Spring WebFlux 应用程序不支持远程 devtools。
:::
运行远程客户端程序(Running the Remote Client Application)
远程客户端程序可以在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)。
正在远程的远程客户端可能如下所示:
. _______ _ _ /\\ / ___'_ __ _ _(_)_ ____ ____ _\ \ \ \( ( )\___ | '_ | '_| | '_ \/ _` || _ \___ _ _____| |_ ___ \ \ \ \ \\/___)| |_)| | | | | || (_| []::::::[] / -_) '\/ _ \_/ -_) ) ) ) )'|____| .__|_| |_|_| |_\__, ||_|_\___|_|_|_\___/\__\___|/ / / / =========|_|==============|___/===================================/_/_/_/ :: Spring Boot Remote ::(v2.7.18-SNAPSHOT)2023-11-22 15:38:10.397INFO 916 --- [ main] o.s.b.devtools.RemoteSpringApplication : Starting RemoteSpringApplication v2.7.18-SNAPSHOT using Java 1.8.0_392 on myhost with PID 916 (/Users/myuser/.m2/repository/org/springframework/boot/spring-boot-devtools/2.7.18-SNAPSHOT/spring-boot-devtools-2.7.18-SNAPSHOT.jar started by myuser in /opt/apps/)2023-11-22 15:38:10.401INFO 916 --- [ main] o.s.b.devtools.RemoteSpringApplication : No active profile set, falling back to 1 default profile: "default"2023-11-22 15:38:10.702INFO 916 --- [ main] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 357292023-11-22 15:38:10.724INFO 916 --- [ main] o.s.b.devtools.RemoteSpringApplication : Started RemoteSpringApplication in 0.736 seconds (JVM running for 1.14)
::: tip 备注
因为远程客户端与真正的应用程序使用相同的类路径,所有它可以直接读取应用程序属性。这就是读取 spring.devtools.remote.secret
属性并将其传递给服务器进行身份验证的方式。
:::
::: tip 提示
始终建议使用 https://
作为连接协议,以便加密通信信息并且密码无法被截获。
:::
::: tip 提示
如果需要使用代理访问远程应用程序,请配置 spring.devtools.remote.proxy.host
和 spring.devtools.remote.proxy.port
属性。
:::
远程升级(Remote Update)
远程客户端会以与本地重启相同的方式监控应用程序类路径的变化。任何更新的资源都会被推送到远程应用程序,并且(如果需要)会触发重启。如果您迭代的功能使用的是本地没有的与服务,这将会非常有用。通常,远程更新和重启比完全重新构建和部署要快得多。
在速度较慢的开发环境中,可能会出现静默期不够的情况,这时类中的更改可能会被分批进行。第一批更改上传后,服务器将重新启动。由于服务器正在重启,下一批更改无法发送到应用程序。
这种情况通常会在 “RemoteSpringApplication “日志中出现警告,提示无法上传某些类,并随之重试。但它也可能导致应用程序代码不一致,以及在上传第一批更改后无法重启。如果经常出现此类问题,请尝试将 spring.devtools.restart.poll-interval
和 spring.devtools.restart.quiet-period
属性参数设置为您需要的值。请参阅 配置文件系统监视器 来配置这些属性。
::: tip 备注
只有在远程客户端运行时,文件才会受到监控。如果在启动远程客户端之前更改文件,则不会将其推送到远程服务器。
:::
6.9 打包应用程序(Packaging Your Application for Production)
可执行 jar 可用于生产部署。由于它们是独立的,因此也非常适合基于云的部署。
对于其它的 “production ready” 功能,例如运行状况,审计和度量标准REST或JMX端点,请考虑添加 spring-boot-actuator
。 详情参阅 Production-ready Features。
6.10 接下来要阅读的内容(What to Read Next)
您现在应该了解如何使用Spring Boot和一些您应该遵循的最佳实践。现在,您可以继续深入了解特定的 Spring Boot 功能 ,也可以跳到前面阅读Spring Boot的 “production ready” 部分。