- 查看本文英文文档,请点击 me!
- 本文将在对原英文文档进行翻译的基础上,结合作者动手实践一步步图文并茂展示给大家!
- 小弟学识尚浅,若文章有不对的地方,请在评论区帮小弟指出,非常感谢!
第三部分 使用 Spring Boot
- 本节将更详细地介绍如何使用Spring Boot。它涵盖了系统构建,自动配置以及如何运行应用程序等主题。我们还介绍了一些Spring Boot的最佳实践。虽然Spring Boot没有特别的特殊之处,(Spring Boot只是你可以使用的另一个Java库(jar)),但其中有一些建议,当你遵循时,会使你的开发过程变得更加容易一些。如果您刚刚开始使用Spring Boot,则可能需要先阅读入门指南,然后再深入本节。
13、系统构建
- 强烈建议您选择支持依赖管理的构建系统,并且可以使用发布到“Maven Central”存储库的
artifacts
。我们建议您选择Maven
或Gradle
。Spring Boot可以与其他构建系统(例如Ant)一起工作,但是它们之间的兼容性并不是特别好。
13.1、依赖管理
- Spring Boot的每个发行版都提供了一个支持的依赖列表。在实践中,您不需要为构建配置中(即在
Pom.xml
文件中)的任何这些依赖项提供一个版本(也就是可以省略version
标签),因为Spring Boot正在为您进行管理(也就是Spring Boot 已经帮我们配置了)。当您升级Spring Boot本身(也就是切换到更高版本的Spring Boot)时,这些依赖关系也将以一致的方式进行升级。如果你觉得这是必要的,你仍然可以指定一个版本并覆盖Spring Boot的建议。
- 该列表包含了你能使用 Spring Boot 的所有 Spring 模块和一系列第三方类库。该列表可以作为标准物料清单
spring-boot-dependencies
)提供,也可以为Maven和Gradle提供额外的专用支持。Spring Boot的每个版本都与一个Spring Framework的基础版本相关联,因此我们强烈建议您不要自行指定其版本。
13.2、Maven
- Maven用户可以从
spring-boot-starter-parent
项目中继承,以获得相应的默认值。 父项目提供以下功能:- Java 1.6作为默认的编译器级别。
- UTF-8源码编码。
- 一个依赖管理系统,因此你可以针对公共的依赖省略
<version>
标签,进而从spring-boot-dependencies POM
中继承。 - 优雅的资源过滤。
- Sensible plugin configuration (exec plugin, surefire, Git commit ID, shade).
- 对
application.properties
和application.yml
中的配置进行资源过滤(其实就是maven
打包时指定哪些文件要过滤,不参与打包),包括特定于配置文件的文件(例如application-foo.properties
和application-foo.yml
)
- 最后一点:由于默认配置文件接受Spring样式占位符($ {...}),Maven过滤被改为使用@ .. @占位符(您可以用Maven属性resource.delimiter覆盖)。
13.2.1、继承父starter工程来创建 Spring Boot
- 要将项目配置为从
spring-boot-starter-parent
中继承,只需设置<parent>
:<!-- Inherit defaults from Spring Boot --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> </parent> 复制代码
您只需要在上面
parent
依赖项上指定Spring Boot版本号。 如果您导入更多的starter
,则可以安全地省略版本号(即<version>
)。 - 通过该设置,您还可以通过在自己的项目中重写属性来覆盖各个依赖项。 例如,要升级到另一个Spring Data发行版,您需要将以下内容添加到您的
pom.xml
中。<properties> <spring-data-releasetrain.version>Fowler-SR2</spring-data-releasetrain.version> </properties> 复制代码
检查
spring-boot-dependencies pom
以获取支持的属性列表。
13.2.2、不继承父starter工程来创建 Spring Boot
- 并不是所有人都喜欢使用继承自
spring-boot-starter-parent POM
的方式来使用 Spring Boot,可能你有自己的标准(也就是自定义配置)或者你单单就喜欢显式地声明所有的maven
配置。 - 如果您不想使用
spring-boot-starter-parent
,你仍然可以通过使用scope = import dependency
来保留依赖关系管理(但不是插件管理):<dependencyManagement> <dependencies> <dependency> <!-- Import dependency management from Spring Boot --> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>1.5.9.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> 复制代码
- 如上所述,该设置不允许您使用属性覆盖单个依赖项。 为了达到同样的结果,你需要在
spring-boot-dependencies
标签(也就是pom
文件的dependencies
标签)之前在项目的dependencyManagement
中添加一个条目。 例如,要升级到另一个Spring Data
发行版,您需要将以下内容添加到您的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> <scope>import</scope> <type>pom</type> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>1.5.9.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> 复制代码
在上面的例子中,我们指定了一个BOM(物料清单,这里指的是
pom.xml
),但是任何依赖类型都可以被覆盖。
13.2.3、改变 Java 版本
spring-boot-starter-parent
选择相当保守的Java
兼容性(指的是上面说的Java 6
)。 如果您想遵循我们的建议并使用较新的Java版本,则可以添加一个java.version属性:<properties> <java.version>1.8</java.version> </properties> 复制代码
13.2.4、使用 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的起始
parent POM
,你只需要添加插件,除非你想改变在父代中定义的配置,否则不需要进行配置。
13.3、Gradle
- Gradle用户可以直接在他们的
dependencies
部分导入starters
。 与Maven
不同的是,没有super parent
可以导入来共享某些配置。repositories { jcenter() } dependencies { compile("org.springframework.boot:spring-boot-starter-web:1.5.9.RELEASE") } 复制代码
spring-boot-gradle-plugin
也是可用的,并提供了创建可执行jar
和从源项目运行项目的任务。 它还提供依赖管理,除其他功能外,还允许您省略由Spring Boot
管理的任何依赖项的版本号:plugins { id 'org.springframework.boot' version '1.5.9.RELEASE' id 'java' } repositories { jcenter() } dependencies { compile("org.springframework.boot:spring-boot-starter-web") testCompile("org.springframework.boot:spring-boot-starter-test") } 复制代码
13.4、Ant
- 主要讲如何使用Ant进行构建,由于前面说到Spring Boot兼容不太好,所以兴趣的可以点击此处。
13.5、Starters
starters
是一系列可以引进你项目的依赖描述符(dependency descriptors我觉得其实就是一些jar
包,里边的pom.xml
文件帮我们做了某些配置而已)。您可以得到所需要的所有关于Spring
及其相关技术的一站式服务,无需搜索示例代码,也不需要粘贴大量依赖描述符(传统我们pom.xml
都要引入很多的<dependency/>
)。例如,如果你想开始使用Spring
和JPA
来访问数据库,只需在你的项目中加入spring-boot-starter-data-jpa
依赖项,你就可以开始编码了哟~starters
包含了许多你需要快速运行一个项目并传递依赖项的依赖。(即它会自动传递依赖)。为什么叫
starters
这个名字呢?所有的官方
starter
都遵循这个spring-boot-starter-*
命名规范,*
代表某一具体的应用(比如web应用程序)。这种命名结构旨在帮助您找到某一具体的starter
。许多IDE中的Maven集成允许您按名称搜索依赖项。例如,安装某一具体的Eclipse``STS
插件后,只需在POM
编辑器中点击ctrl-space
,然后键入“spring-boot-starter”
获取完整列表。正如创建自己的starter中所解释的,第三方starter
不应该以spring-boot
为开始,因为它是为官方Spring Boot工件(artifacts)保留的。一个表示acme
应用的第三方starter
的命名可能就是acme-spring-boot-starter
。- 以下就是 Spring Boot 在
org.springframework.boot
包下定义的一些starter
:表格13.1 Spring Boot应用程序
starters
名称 描述 Pom spring-boot-starter
核心 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进行面向方面编程的 starter
POM
spring-boot-starter-artemis
使用 Apache Artemis
进行JMS
消息传递POM
spring-boot-starter-batch
使用 Spring Batch
POM
spring-boot-starter-cache
使用Spring框架的缓存支持 POM
spring-boot-starter-cloud-connectors
使用Spring Cloud连接器的 starter
,可简化Cloud Foundry和Heroku等云平台中的服务连接POM
spring-boot-starter-data-cassandra
使用Cassandra分布式数据库和Spring Data Cassandra POM
spring-boot-starter-data-couchbase
使用面向文档的数据库Couchbase和Spring Data Couchbase POM
spring-boot-starter-data-elasticsearch
使用搜索、分析引擎Elasticsearch和Spring Data Elasticsearch POM
spring-boot-starter-data-gemfire
使用分布式数据存储GemFire和Spring Data GemFire 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-neo4j
使用图形数据库Neo4j和Spring Data Neo4j POM
spring-boot-starter-data-redis
使用带有Spring Data Redis和Jedis客户端的Redis键值数据存储 POM
spring-boot-starter-data-rest
Starter for exposing Spring Data repositories over REST using Spring Data REST POM
spring-boot-starter-data-solr
结合Spring Data Solr使用Apache Solr 搜索平台 POM
spring-boot-starter-freemarker
使用FreeMarker视图构建MVC Web应用程序 POM
spring-boot-starter-groovy-templates
使用Groovy模板视图构建MVC Web应用程序 POM
spring-boot-starter-hateoas
使用Spring MVC和Spring HATEOAS构建基于超媒体的RESTful Web应用程序 POM
spring-boot-starter-integration
使用Spring集成 POM
spring-boot-starter-jdbc
将JDBC与Tomcat JDBC连接池配合使用 POM
spring-boot-starter-jersey
使用JAX-RS和Jersey构建RESTful Web应用程序的 starter
。是Spring-Boot-Starter-Web
的另一种选择POM
spring-boot-starter-jooq
使用jOOQ访问SQL数据库的 starter
。spring-boot-starter-data-jpa
或spring-boot-starter-jdbc
的替代方案POM
spring-boot-starter-jta-atomikos
使用Atomikos的JTA事务 POM
spring-boot-starter-jta-bitronix
使用Bitronix的JTA事务 POM
spring-boot-starter-jta-narayana
Spring Boot Narayana JTA Starter
POM
spring-boot-starter-mail
使用Java Mail和Spring Framework支持的电子邮件发送 POM
spring-boot-starter-mobile
使用Spring Mobile构建Web应用程序 POM
spring-boot-starter-mustache
使用Mustache视图构建MVC Web应用程序 POM
spring-boot-starter-security
使用Spring Security POM
spring-boot-starter-social-facebook
使用Spring社交Facebook POM
spring-boot-starter-social-linkedin
使用Spring社交LinkedIn POM
spring-boot-starter-social-twitter
使用Spring社交twitter POM
spring-boot-starter-test
Starter用于测试包含JUnit,Hamcrest和Mockito等库的Spring Boot应用程序 POM
spring-boot-starter-thymeleaf
使用Thymeleaf视图构建MVC Web应用程序 POM
spring-boot-starter-validation
通过Hibernate Validator使用Java Bean验证 POM
spring-boot-starter-web
用于构建Web的 starter
,包括使用Spring MVC的RESTful应用程序。 使用Tomcat作为默认的嵌入容器POM
spring-boot-starter-web-services
使用Spring Web Services POM
spring-boot-starter-websocket
使用Spring Framework的WebSocket支持构建WebSocket应用程序 POM
- 除了应用程序
starter
之外,还可以使用以下starter
来做好相应的生产准备:表格13.2 Spring Boot 产品
starters
名称 描述 POM spring-boot-starter-actuator
使用具有生产准备功能的Spring Boot的执行器,可以帮助您监控和管理您的应用程序 POM
spring-boot-starter-remote-shell
使用CRaSH远程shell通过SSH监视和管理您的应用程序。 自1.5以来已弃用 POM
- 最后,Spring Boot还包括一些可以用来排除或交换特定技术门面的
starters
:表格13.3 Spring Boot 技术
starters
名称 描述 POM spring-boot-starter-jetty
使用Jetty作为嵌入式servlet容器的 starter
。spring-boot-starter-tomcat
的替代方案POM
spring-boot-starter-log4j2
使用Log4j2进行日志记录的 starter
。spring-boot-starter-logging
的替代方法POM
spring-boot-starter-logging
使用Logback进行日志记录。 默认日志 starter
POM
spring-boot-starter-tomcat
使用Tomcat作为嵌入式servlet容器的 starter
。spring-boot-starter-web
使用的默认servlet容器starter
POM
spring-boot-starter-undertow
使用Undertow作为嵌入式servlet容器的 starter
。spring-boot-starter-tomcat
的替代方案POM
有关其他社区贡献者的列表,请参阅GitHub上的
spring-boot-starters
模块中的README文件。
14、结构化你的代码
- Spring Boot不需要任何特定的代码布局,但是,有一些最佳实践可以帮助。
14.1、使用“默认的”package
- 当一个类没有声明
package
时,我们一般会认为这个类位于“默认包”中。通常不鼓励使用“默认软件包”,且应该避免使用“默认软件包”。对于使用@ComponentScan
,@EntityScan
或@SpringBootApplication
注释的Spring Boot应用程序来说,使用“默认包”可能会导致特定的问题,因为每个jar的每个类都将被读取。(这里其实说的是Spring Boot会进行组件、实体、包的扫描@ComponentScan
)我们建议您遵循Java推荐的软件包命名约定,并使用反向域名(例如com.example.project)。
14.2、定位我们的主应用程序类
- 我们通常建议您将主应用程序类放在其他类的根包中。
@EnableAutoConfiguration
注释通常放在主类上,并且它隐含地为某些项目定义了一个基本的“搜索包”。例如,如果您正在编写JPA应用程序,则@EnableAutoConfiguration
注释类的包将用于搜索@Entity
条目。 - 使用根包也允许使用
@ComponentScan
注释而不需要指定basePackage
属性。如果您的主类位于根包中,也可以使用@SpringBootApplication
注释。 - 这是一个典型的项目结构:
com +- example +- myproject +- Application.java +- domain +- Customer.java +- CustomerRepository.java +- service +- CustomerService.java +- web +- CustomerController.java 复制代码
Application.java
文件将声明main
方法以及基本的@Configuration
。package com.example.myproject; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @EnableAutoConfiguration @ComponentScan public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } 复制代码
15、配置类
- Spring Boot支持基于Java的配置。尽管可以使用XML源调用
SpringApplication.run()
,我们通常建议您的主要来源是@Configuration
类。通常,定义main
方法的类也是@Configuration
的一个首选。在互联网上已经发布了许多使用XML配置的Spring配置示例。 如果可能,请始终尝试使用基于Java的等效配置。 搜索
Enable*
注释可以是一个很好的起点。
15.1、导入额外的配置类
- 你不需要把你所有的
@Configuration
放到一个类中。@Import
注解可用于导入其他配置类。或者,您可以使用@ComponentScan
自动获取所有Spring组件,包括@Configuration
类。
15.2、带入XML配置
- 如果您绝对必须使用基于XML的配置,我们建议您仍以
@Configuration
类开头。然后您可以使用额外的@ImportResource
注解来加载XML配置文件。
16、自动配置
- Spring Boot自动配置会尝试根据您添加的jar依赖项自动配置您的Spring应用程序。例如,如果HSQLDB在您的类路径中,并且您没有手动配置任何数据库连接Bean,那么我们将自动配置一个内存数据库。
- 您需要通过将
@EnableAutoConfiguration
或@SpringBootApplication
注释添加到其中一个@Configuration
类来选择自动配置。您应该只添加一个
@EnableAutoConfiguration
注释。 我们通常建议您将其添加到您的主要@Configuration
类。
16.1、逐渐取代自动配置
- 自动配置是非侵入式的,您可以随时开始定义自己的配置来替换自动配置的特定部分。如果添加自己的
DataSource
Bean,则默认的嵌入式数据库支持将失效。 - 如果您需要了解当前正在应用的自动配置,以及为什么?那么请使用
--debug
参数启动您的应用程序(也就是debug模式启动应用程序)。 这将启用选择核心记录器的调试日志,并将自动配置报告记录到控制台。
16.2、禁用特定的自动配置
- 如果您发现正在应用您不需要的特定自动配置类,则可以使用
@EnableAutoConfiguration
的exclude
属性来禁用它们。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
配置文件级别设置警用自动相应的配置。(注:一个类声明了@Configuration
注解则表示该类是一个配置类,可以被禁用)
17、Spring Bean 和 依赖注入
- 您可以自由使用任何标准的Spring框架技术来定义您的
bean
及其注入的依赖关系。 为了简单起见,我们经常发现使用@ComponentScan
来查找bean
,并结合使用@Autowired
构造函数注入效果最好。 - 如果按上面的建议构建代码(在根包中查找应用程序类),则可以添加
@ComponentScan
而不带任何参数。 所有的应用程序组件(@Component
,@Service
,@Repository
,@Controller
等)都将被自动注册为Spring Bean
。 - 这里是一个示例
@Service Bean
,它使用构造函数注入来获得必需的RiskAssessor 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; //此处省略了@Autowired public DatabaseAccountService(RiskAssessor riskAssessor) { this.riskAssessor = riskAssessor; } // ... } 复制代码
- 请注意,如何使用构造函数注入允许
riskAssessor
字段被标记为final
,表明它不能被随后更改。
18、使用@SpringBootApplication注解
- 许多Spring Boot开发人员总是使用
@Configuration
,@EnableAutoConfiguration
和@ComponentScan
注解其主类。由于这些注释经常一起使用(特别是如果您遵循以上最佳实践),Spring Boot提供了一种更方便的@SpringBootApplication
替代方法。 @SpringBootApplication
注释等价于使用@Configuration
,@EnableAutoConfiguration
和@ComponentScan
及其默认属性:package com.example.myproject; 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
的属性。
19、运行你的应用程序
- 将应用程序打包为jar并使用嵌入式HTTP服务器的最大优点之一是,您可以像运行其他应用程序一样运行应用程序。 调试Spring Boot应用程序也很容易; 你不需要任何特殊的IDE插件或扩展。
本节仅介绍基于jar的打包。如果您选择将应用程序打包为war文件,则应参考您的服务器和IDE文档。
19.1、从IDE中运行
- 你可以像普通Java应用程序一样在IDE中运行Spring Boot 应用。但是,首先你需要将项目导入IDE中,大多数IDE可以直接导入
Maven
项目,例如在Eclipse
的File -> Import -> Existing Maven Projects
。 - 如果不能直接将项目导入IDE,则可以使用构建插件生成IDE元数据。 Maven包含Eclipse和IDEA的插件; Gradle也为各种IDE提供了各种插件。
如果您不小心运行了两次Web应用程序,则会看到“端口已被使用Port already in use”错误。 STS用户可以使用
"Relaunch"
按钮而不是"Run"
来确保关闭任何现有的实例。
19.2、作为打包的应用程序运行
-
如果您使用Spring Boot Maven或Gradle插件创建可执行
jar
,则可以使用java -jar
运行应用程序。 例如:$ java -jar target/myproject-0.0.1-SNAPSHOT.jar
-
也可以运行打包的应用程序并启用远程调试支持。 这使您可以将调试器附加到打包的应用程序中:(主要用于远程调试)
$ java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n \ -jar target/myproject-0.0.1-SNAPSHOT.jar
19.3、使用Maven插件
-
Spring Boot Maven插件包含一个可用于快速编译和运行应用程序的
run
目标。 应用程序以分解形式运行,就像在IDE中一样。$ mvn spring-boot:run
-
您可能还想使用有用的操作系统环境变量:
$ export MAVEN_OPTS=-Xmx1024m -XX:MaxPermSize=128M
19.4、使用Gradle插件
-
Spring Boot Gradle插件还包含一个
bootRun
任务,可用于以分解形式运行您的应用程序。 无论何时导入spring-boot-gradle-plugin
,都会添加bootRun
任务:$ gradle bootRun
-
您可能还想使用有用的操作系统环境变量:
$ export JAVA_OPTS=-Xmx1024m -XX:MaxPermSize=128M
19.5、热插拔
- 因为Spring Boot仅仅是普通的Java应用程序,JVM热插拔应该是开箱即用的。JVM热交换在某种程度上受限于它可以替换的字节码,为了获得更完整的解决方案,可以使用JRebel或Spring Loaded项目。
20、开发者工具
-
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.
dependencies { compile("org.springframework.boot:spring-boot-devtools") } 复制代码
运行完整打包的应用程序时,开发者工具会自动禁用。 如果您的应用程序是使用
java -jar
方式启动的,或者如果它是使用特殊的类加载器启动的,那么它就被认为是“生产应用程序”。 将依赖关系标记为可选的是一种最佳实践,可以防止devtools通过项目传递到其他模块。 Gradle不支持optional
的依赖关系,因此您可能希望在此期间看看propdeps插件。重新打包的
archives
在默认情况下不包含devtools。 如果您想使用某些远程devtools功能,则需要禁用excludeDevtools
构建属性以包含它。 该属性支持Maven和Gradle插件。
19.1、属性默认值
- Spring Boot支持的一些库使用缓存来提高性能。 例如,模板引擎将缓存已编译的模板,以避免重复解析模板文件。 另外,Spring MVC可以在服务静态资源时将HTTP缓存头添加到响应中。
- 虽然缓存在生产中非常有益,但在开发过程中可能会产生反作用,使您无法看到应用程序中刚刚做出的更改。 由于这个原因,spring-boot-devtools默认会禁用这些缓存选项。
- 缓存选项通常由您的
application.properties
文件中的设置进行配置。 例如,Thymeleaf提供了spring.thymeleaf.cache
属性。 而不需要手动设置这些属性,spring-boot-devtools
模块将自动应用合理的开发配置。有关应用的属性的完整列表,请参阅DevToolsPropertyDefaultsPostProcessor。
20.2、自动重启
-
使用
spring-boot-devtools
的应用程序将在类路径上的文件发生更改时自动重启。 在IDE中工作时,这是一个非常有用的功能,因为它为代码更改提供了一个非常快速的反馈循环。 默认情况下,将监视指向文件夹的类路径中的任何条目以进行更改。 请注意,某些资源(如静态资产和视图模板)不需要重新启动应用程序。触发重启
由于DevTools监视类路径资源,触发重启的唯一方法是更新类路径。 导致类路径更新的方式取决于您使用的IDE。 在Eclipse中,保存修改后的文件将导致类路径更新并触发重启。 在IntelliJ IDEA中,构建项目(
Build - > Make Project
)将具有相同的效果。您也可以通过受支持的构建插件(即Maven和Gradle)启动您的应用程序,只要启用了分叉功能,因为DevTools需要隔离的应用程序类加载器才能正常运行。 当Gradle和Maven在类路径中检测到DevTools时,默认会这样做。
与LiveReload一起使用时,自动重新启动的效果非常好。 详情请参阅下文。 如果使用JRebel,自动重新启动将被禁用,以支持动态类重新加载。 其他devtools功能(如LiveReload和属性覆盖)仍然可以使用。
DevTools依靠应用程序上下文的关闭挂钩在重新启动期间关闭它。 如果您禁用了关闭挂钩(
SpringApplication.setRegisterShutdownHook(false)
),它将无法正常工作。当确定类路径上的条目在更改时会触发重新启动时,DevTools会自动忽略名为spring-boot,
spring-boot-devtools
,spring-boot-autoconfigure
,spring-boot-actuator
和spring-boot-starter
的项目。DevTools需要自定义
ApplicationContext
使用的ResourceLoader
:如果你的应用程序已经提供了一个,它将被打包。 不支持直接覆盖ApplicationContext
上的getResource
方法。重启(restart) vs 重新加载(reload)
Spring Boot提供的重启技术通过使用两个类加载器来工作。 不改变的类(例如来自第三方jar的类)被加载到基类加载器中。 您正在开发的类将加载到重启类加载器中。 当应用程序重新启动时,重启类加载器将被丢弃,并创建一个新的。 这种方法意味着应用程序重新启动通常比“冷启动”快得多,因为基类加载器已经可用并且已经被填充了。
如果您发现重新启动对于您的应用程序来说不够快,或者遇到类加载问题,则可以考虑从ZeroTurnaround中获取重新加载的技术,例如JRebel。 这些工作通过重写类,因为他们被加载,使他们更容易重新加载。 Spring Loaded提供了另一种选择,但是它不支持许多框架,并且没有商业支持。
20.2.1、排除某些资源(如静态资源)
-
某些资源不一定需要在更改时触发重新启动。 例如,
Thymeleaf
模板可以就地编辑。 默认情况下,更改/META-INF/maven
,/META-INF/resources
,/resources
,/static
,/public
或/templates
中的资源不会触发重新启动,但会触发实时重新加载。 如果你想自定义这些排除,你可以使用spring.devtools.restart.exclude
属性。 例如,要仅排除/static
和/public
,您可以设置以下内容:spring.devtools.restart.exclude=static/**,public/**
如果要保留这些默认值并添加其他排除项,请改为使用
spring.devtools.restart.additional-exclude
属性。
20.2.2、监视额外的其他路径(Watching additional paths)
- 您可能希望当更改不在类路径中的文件时重新启动或重新加载应用程序。 为此,请使用
spring.devtools.restart.additional-paths
属性来配置其他路径以监视更改。 您可以使用上述的spring.devtools.restart.exclude
属性来控制额外路径下的更改是否会触发完全重新启动或仅实时重新加载。
20.2.3、禁用重启
- 如果您不想使用重新启动功能,则可以使用
spring.devtools.restart.enabled
属性将其禁用。 在大多数情况下,你可以在你的application.properties
中设置它(这将仍然初始化重启类加载器,但它不会监视文件的变化,也就是只要你重新启动了Spring Boot应用程序,都会冲洗初始化一个新的重启类加载器,上文也提到了)。(注意重新启动
和关闭后启动
的区别) - 如果您需要完全禁用重新启动支持(不会有重新启动的功能,也就不会再初始化重启类加载器了哟~),例如,因为它不适用于特定的库,则需要在调用
SpringApplication.run(...)
之前设置System
属性。 例如:public static void main(String[] args) { System.setProperty("spring.devtools.restart.enabled", "false"); SpringApplication.run(MyApp.class, args); } 复制代码
20.3.4、使用触发器文件
- 如果您使用连续编译已更改文件的IDE,则可能只希望在特定时间触发重新启动。 要做到这一点,你可以使用“触发文件”,这是一个特殊的文件,当你想要实际触发重启检查时,必须修改它。 只更改文件会触发检查,只有Devtools检测到必须执行某些操作时才会重新启动。 触发文件可以手动更新,也可以通过IDE插件进行更新。
- 要使用触发器文件,请使用
spring.devtools.restart.trigger-file
属性。您可能需要将
spring.devtools.restart.trigger-file
设置为全局设置,以便所有项目的行为方式相同
20.3.5、自定义重启类加载器
-
正如上面“重新启动vs重新加载”一节所述,重新启动功能是通过使用两个类加载器(一个基类,一个重启类)来实现的。 对于大多数应用程序来说,这种方法运行良好,但有时候会导致类加载问题。
-
默认情况下,IDE中的任何打开的项目都将使用“重启”类加载器加载,任何常规的
.jar
文件都将使用“基本”类加载器加载。 如果您使用多模块项目,而不是将每个模块导入到IDE中,则可能需要自定义项目。 要做到这一点,你可以创建一个META-INF/spring-devtools.properties
文件。 -
spring-devtools.properties
文件可以包含restart.exclude
和restart.include
前缀属性。include
元素是应该被拉入到“重启”类加载器中的项目,排除元素是应该被下推到“基本”类加载器中的项目。 该属性的值是一个将应用于类路径的正则表达式模式。 -
比如:
restart.exclude.companycommonlibs=/mycorp-common-[\\w-]+\.jar restart.include.projectcommon=/mycorp-myproj-[\\w-]+\.jar 复制代码
所有的属性
key
(这里指上面的companycommonlibs
)必须是唯一的。 只要属性以restart.include
或restart.exclude
开头的都将被考虑。所有类路径中的
META-INF/spring-devtools.properties
都将被加载。 您可以将文件打包到项目中,也可以打包到项目使用的库中。
20.3.6、已知的限制
- 对于使用标准
ObjectInputStream
进行反序列化的对象,重新启动功能无法正常工作。 如果需要反序列化数据,则可能需要将Spring的ConfigurableObjectInputStream
与Thread.currentThread().getContextClassLoader()
一起使用。 - 不幸的是,有些第三方库反序列化,而不考虑上下文类加载器。 如果您发现这样的问题,您需要向原作者请求修复。
20.3、LiveReload(一个内置服务器)
spring-boot-devtools
模块包含一个嵌入式LiveReload
服务器,当资源发生变化时,可用于触发浏览器刷新。LiveReload
浏览器扩展可从livereload.com的Chrome,Firefox和Safari免费获得。- 如果您不想在应用程序运行时启动LiveReload服务器,则可以将
spring.devtools.livereload.enabled
属性设置为false
。一次只能运行一个LiveReload服务器。 在开始您的应用程序之前,请确保没有其他
LiveReload
服务器正在运行。 如果您从IDE启动多个应用程序,则只有第一个应用程序支持LiveReload
。
20.4、全局配置
-
您可以通过将一个名为
.spring-boot-devtools.properties
的文件添加到您的$HOME
文件夹来配置全局devtools设置(请注意,文件名以"."开头)。 添加到此文件的任何属性都将应用于使用devtools的计算机上的所有Spring Boot应用程序。 例如,要将重新启动配置为始终使用触发器文件,可以添加以下内容:~/.spring-boot-devtools.properties.
spring.devtools.reload.trigger-file=.reloadtrigger
20.5、远程应用程序
-
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.secret
属性时,服务器组件会自动启用。 客户端组件必须手动启动。
20.5.1、运行远程客户端应用程序
- 远程客户端应用程序旨在从您的IDE中运行。 您需要使用与您要连接的远程项目相同的类路径来运行
org.springframework.boot.devtools.RemoteSpringApplication
。 传递给应用程序的非选项(non-option
)参数应该是您要连接到的远程URL。 - 例如,如果您使用的是Eclipse或STS,并且您已经将一个名为
my-app
的项目部署到了Cloud Foundry,则可以执行以下操作:- 从
Run
菜单中选择Run Configurations…
。 - 创建一个新的
Java Application
"launch configuration
"。 - 浏览
my-app
项目。 - 使用
org.springframework.boot.devtools.RemoteSpringApplication
作为主类。 - 将
https://myapp.cfapps.io
添加到Program arguments
(或任何远程URL)。
- 从
- 正在运行的远程客户端将如下所示:
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ ___ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | | _ \___ _ __ ___| |_ ___ \ \ \ \ \\/ ___)| |_)| | | | | || (_| []::::::[] / -_) ' \/ _ \ _/ -_) ) ) ) ) ' |____| .__|_| |_|_| |_\__, | |_|_\___|_|_|_\___/\__\___|/ / / / =========|_|==============|___/===================================/_/_/_/ :: Spring Boot Remote :: 1.5.9.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.host
和spring.devtools.remote.proxy.port
属性。
20.5.2、远程更新
- 远程客户端将以与本地重启相同的方式监视您的应用程序类路径的更改。 任何更新的资源将被推送到远程应用程序,并(如果需要)触发重新启动。 如果您正在迭代使用您本地没有的云服务的功能,这可能会非常有帮助。 通常远程更新和重新启动比完整的重建和部署周期快得多。
只有远程客户端正在运行时才会监视文件。 如果在启动远程客户端之前更改文件,则更新操作不会将其推送到远程服务器。
20.5.3、远程调试隧道
-
Java远程调试在诊断远程应用程序的问题时非常有用。 不幸的是,当您的应用程序部署在数据中心之外时,并不总是可以启用远程调试。 如果您使用基于容器的技术(例如Docker),则远程调试也可能会非常棘手。
-
为了帮助解决这些限制,devtools支持通过HTTP隧道传输远程调试流量。 远程客户端在端口
8000
上提供本地服务器,您可以将其附加到远程调试器。 建立连接后,调试流量将通过HTTP发送到远程应用程序。 如果你想使用不同的端口,你可以使用spring.devtools.remote.debug.local-port
属性。 -
您需要确保您的远程应用程序在启用远程调试的情况下启动。 这通常可以通过配置
JAVA_OPTS
来实现。 例如,使用Cloud Foundry
,您可以将以下内容添加到您的manifest.yml
中:--- env: JAVA_OPTS: "-Xdebug -Xrunjdwp:server=y,transport=dt_socket,suspend=n" 复制代码
请注意,您不需要将
address=NNNN
选项传递给-Xrunjdwp
。 如果省略,Java将简单地选取一个随机空闲端口。通过Internet调试远程服务可能会很慢,您可能需要增加IDE中的超时时间。 例如,在Eclipse中,您可以选择
Java
→Preferences…``Debug
并将debug timeout(ms)
更改为更合适的值(在大多数情况下,60000
的效果很好)。在IntelliJ IDEA中使用远程调试通道时,必须将所有断点配置为挂起线程而不是VM。 默认情况下,IntelliJ IDEA中的断点会暂停整个虚拟机,而不是仅挂起遇到断点的线程。 这具有暂停管理远程调试通道的线程的不良副作用,导致您的调试会话冻结。 在IntelliJ IDEA中使用远程调试通道时,应将所有断点配置为挂起线程而不是VM。 请参阅IDEA-165769了解更多详情。
21、打包您的生产应用程序
- 可执行的
jars
可用于生产部署。 由于它们是独立的,因此它们也非常适合基于云的部署。 - 对于额外的“生产就绪”功能,如健康,审计和度量REST或JMX端点; 考虑加入
spring-boot-actuator
。 有关详细信息,请参阅第五部分“spring-boot-actuator:生产就绪功能” 。
22、接下来读什么?
- 您现在应该对如何使用Spring Boot以及您应该遵循的一些最佳实践有很好的理解。 您现在可以继续深入了解特定的Spring Boot功能,或者可以跳过并阅读Spring Boot的“生产就绪”部分。