Spring Boot 参考指南3(1.5.2.RELEASE)

此篇翻译的是Spring Boot官方指南 Part III. 使用 Spring Boot (Using Spring Boot)。查看前面章节移步这里

第三部分 使用Spring Boot

本节将更详细介绍你应该如何使用Spring Boot。 它涵盖诸如构建系统,自动配置以及如何运行应用程序等主题。 我们也涵盖了一些Spring Boot的最佳实践。虽然Spring Boot没有什么尤其特别的特点(它只是另一个你可以利用的库),这有一些建议当你按照它做时,可以让您的开发过程更容易一些。

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

13. 构建系统

强烈建议您选择一个支持依赖管理的构建系统,和一个可以消耗工件发布到“Maven Central”仓库。 我们建议您选择Maven或Gradle。 可以让Spring Boot与其他构建系统(例如Ant)配合使用,但是它们不会得到很好的支持。

13.1 依赖管理

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

| 如果您觉得有必要,您仍然可以指定一个版本并覆盖Spring Boot建议。

策划的列表包含可以使用Spring Boot的所有 spring 模块以及第三方库的精简列表。 该列表可作为标准的物料清单spring-boot-dependencies)使用,并且还额外提供了对MavenGradle的专用支持。

| Spring Boot的每个版本与Spring Framework的一个基本版本相关联,因此我们强烈建议您不要自己指定其版本。

13.2 Maven

Maven用户可以从 spring-boot-starter-parent-parent 项目中继承,以获得合理的默认值。父项目提供以下功能:

最后一点:由于默认的配置文件接受Spring样式占位符($ {...}),所以Maven过滤被更改为使用 @..@ 占位符(您可以使用Maven的 resource.delimiter 属性覆盖它)。

13.2.1 继承 starter parent

配置你的项目从 spring-boot-starter-parent 继承,只需的设置 parent (节点):

<!--从Spring Boot 继承默认值 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.2.RELEASE</version>
</parent>

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

通过该设置,您也可以在项目中通过属性的优势覆盖个别的依赖项,例如,要升级到另一个Spring Data release train,你需要添加以下内容到你的 pom.xml :

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

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

13.2.2 使用没有父POM的Spring Boot

不是所有人都喜欢从 spring-boot-starter-parent 继承,您可能需要使用你自己团队拥有的标准 parent,或者你可能只是希望明确声明你的Maven配置。

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

<dependencyManagement>
     <dependencies>
        <dependency>
            <!-- 从Spring Boot引入依赖管理 -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>1.5.2.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

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

<dependencyManagement>
    <dependencies>
        <!-- 覆盖由Spring Boot提供的Spring Data release train -->
        <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.2.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

| 在上面的例子中,我们指定了一个BOM( Bills of Materials 物料清单),但是任何依赖类型都可以被这样覆盖。

13.2.3 改变Java版本

spring-boot-starter-parent 选择相当保守的Java兼容性。 如果要遵循我们的建议并使用更高版本的Java版本,可以添加 java.version 属性:

<properties>
    <java.version>1.8</java.version>
</properties>
13.2.4 使用Spring Boot Maven 插件

Spring Boot 包含一个可以将项目打包成可执行的jar的Maven插件。如果你想用它将插件放在你的 <plugins> 节点中:

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

| 如果您使用Spring Boot启动器父pom,则只需要添加插件,除非要更改父级中定义的设置,否则不需要进行配置。

13.3 Gradle

Gradle 用户可以直接在他们的 dependencies 部分引入"starters"。不像Maven,这没有 "super parent" 去引入共享一些配置。

repositories {
    jcenter()
}

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

spring-boot-gradle-plugin 也是可用的,它提供了从源代码创建可执行jar并运行项目的任务。 它还提供依赖管理,除其他功能外,还允许您省略由Spring Boot管理的任何依赖的版本号:

plugins {
    id 'org.springframework.boot' version '1.5.2.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

有可能需要使用Apache Ant+Ivy创建Spring Boot项目。spring-boot-antlib “AntLib”模块也可用于帮助Ant创建可执行jars

要声明依赖,一个典型的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="1.3.0.BUILD-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>

| 如果你不想使用 spring-boot-antlib 模块。请参见第84.10节, “不使用spring-boot-antlib从Ant创建一个可执行的存档” ”怎么做“

13.5 启动器

启动器是一组可以包含在应用程序中的,方便的依赖关系描述符。 您可以获得所需的所有Spring和相关技术的一站式服务,无需通过搜寻示例代码和复制粘贴依赖描述符的加载。 例如,如果要开始使用Spring和JPA进行数据库访问,那么只需在项目中包含 spring-boot-starter-data-jpa 依赖,即可准备好去做。

启动器包含许多您需要使项目启动并快速运行的依赖,并具有托管传递依赖一致的、受支持的集合。

名字的含义

所有官方的启动器都遵循类似的命名方式;spring-boot-starter-*,其中 * 是一个特定类型的应用。这个命名结构旨在帮助你找到一个启动器。这个命名结构旨在帮助你找到一个启动器。 许多IDE中的Maven集成允许您按名称搜索依赖项。 例如,安装适当的Eclipse或STS插件后,您可以简单地在POM编辑器中点击 ctrl-space,并输入“spring-boot-starter”来获取完整的列表。

创建自己的启动器部分所述,第三方启动程序不应该以 Spring-boot 开头,因为它是为正式的Spring Boot工件保留的。 acme 的第三方启动器通常被命名为 acme-spring-boot-starter

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

表 13.1 Spring Boot 应用启动器

|名称|描述|Pom|
|---|---|
|spring-boot-starter-thymeleaf|使用Thymeleaf 视图构建MVC web应用的启动器|Pom|
|spring-boot-starter-data-couchbase|使用Couchbase面向文档的数据库和Spring Data Couchbase|Pom|
|spring-boot-starter-artemis|使用Apache Artemis实现JMS消息|Pom|
|spring-boot-starter-web-services|用于Spring Web服务的启动器|Pom|
|spring-boot-starter-mail|用于Java邮件和Spring 框架的邮件发送支持的启动器|Pom|
|spring-boot-starter-data-redis|用于Redis 的key-value数据存储同Spring Data Redis和Jedis 客户端的启动器|Pom|
|spring-boot-starter-web|为构建使用Spring MVC包括RESTful、web的应用的启动器,使用Tomcat作为默认的内嵌容器|Pom|
|spring-boot-starter-data-gemfire|用于GemFire分布式数据存储和Spring Data GemFire的启动器|Pom|
|spring-boot-starter-activemq|使用Apache ActiveMQ实现JMS消息|Pom|
|spring-boot-starter-data-elasticsearch|用于Elasticsearch搜索和分析引擎以及Spring Data Elasticsearch|Pom|
|spring-boot-starter-integration|用于Spring集成|Pom|
|spring-boot-starter-test|用于测试Spring Boot应用包含的库:JUnit、Hamcrest 、Mockito|Pom|
|spring-boot-starter-jdbc|用于JDBC支持,使用Tomcat JDBC 连接池|Pom|
|spring-boot-starter-mobile|使用Spring Mobile构建web应用的启动器|Pom|
|spring-boot-starter-validation|用于使用Hibernate Validator的Java Bean验证启动器|Pom|
|spring-boot-starter-hateoas|使用Spring MVC和Spring HATEOAS构建基于超媒体的RESTful web应用的启动器|Pom|
|spring-boot-starter-jersey|使用 JAX-RS 和 Jersey构建RESTful web应用, spring-boot-starter-web 的替代方法|Pom|
|spring-boot-starter-data-neo4j|用于Neo4j 图形数据库和Spring Data Neo4j 的启动器|Pom|
|spring-boot-starter-data-ldap|用于Spring Data LDAP的启动器|Pom|
|spring-boot-starter-websocket|用于构建WebSocket 应用(使用spring 框架的WebSocket 支持)的启动器|Pom|
|spring-boot-starter-aop|用于基于Spring Aop和AspectJ的面向切面(aspect-oriented)编程的启动器|Pom|
|spring-boot-starter-amqp|使用Spring AMQP和Rabbit MQ|Pom|
|spring-boot-starter-data-cassandra|使用Spring Cassandra 分布式数据库和Spring Data Cassandra|Pom|
|spring-boot-starter-social-facebook|使用Spring 社交的 facebook|Pom|
|spring-boot-starter-jta-atomikos|用于基于Atomikos实现的JTA事务|Pom|
|spring-boot-starter-security|用于Spring Security的启动器|Pom|
|spring-boot-starter-mustache|用于构建Mustache 视图实现的MVC web应用|Pom|
|spring-boot-starter-data-jpa|用于Hibernate实现的Spring Data JPA的启动器|Pom|
|spring-boot-starter|核心启动器,包括自动配置支持、日志以及YAML|Pom|
|spring-boot-starter-groovy-templates|使用Groovy 模版视图实现构建MVC web应用|Pom|
|spring-boot-starter-freemarker|使用FreeMarker 视图构建MVC web 应用的启动器|Pom|
|spring-boot-starter-batch|对Spring Batch的支持|Pom|
|spring-boot-starter-social-linkedin|用于为Spring Social LinkedIn的启动器|Pom|
|spring-boot-starter-cache|用于对Spring 框架的缓存支持的启动器|Pom|
|spring-boot-starter-data-solr|用于Spring Data Solr实现的 Apache Solr搜索平台的启动器|Pom|
|spring-boot-starter-data-mongodb|用于MongoDB面向文档数据库和Spring Data MongoDB的启动器|Pom|
|spring-boot-starter-jooq|使用jOOQ SQL关系数据库,替代 spring-boot-starter-data-jpaspring-boot-starter-jdbc|Pom|
|spring-boot-starter-jta-narayana|Spring Boot Narayana JTA启动器|Pom|
|spring-boot-starter-cloud-connectors|用于Spring Cloud 连接器的支持,可简化在Cloud Foundry 和 Heroku一样的云平台上服务连接。|Pom|
|spring-boot-starter-jta-bitronix|使用Bitronix的JTA事务的启动器|Pom|
|spring-boot-starter-social-twitter|用于Spring Social Twitter的启动器|Pom|
|spring-boot-starter-data-rest|用于使用Spring Data REST暴露Spring Data 仓库到REST之外|Pom|
除了应用启动器,以下启动器可用于添加 production ready 功能:

表 13.2 Spring Boot 生产启动器
名称 描述 Pom
spring-boot-starter-actuator 使用Spring Boot Actuator提供生产就绪功能,去帮助您监控和管理应用的启动器 Pom
spring-boot-starter-remote-shell 使用CRaSH远程shell通过SSH监控和管理您的应用程序。 自1.5以来已弃用 Pom

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

表13.3 Spring Boot 特定启动器
名称 描述 Pom
spring-boot-starter-undertow 使用Undertow 作为内嵌的servlet容器,spring-boot-starter-tomcat 的替代方案 Pom
spring-boot-starter-jetty 使用jetty作为内嵌的servlet容器,spring-boot-starter-tomcat 的替代方案 Pom
spring-boot-starter-logging 日志使用Logback,默认的日志启动器 Pom
spring-boot-starter-tomcat 使用tomcat作为内嵌的servlet容器。spring-boot-starter-web 使用的默认servlet容器启动器 Pom
spring-boot-starter-log4j2 使用Log4j2记录日志。spring-boot-starter-logging 的替代方案 Pom

| 额外的社区贡献的启动器的列表,请参阅GitHub上的spring-boot-startters模块中的README文件。

14. 构建你的代码

Spring Boot 不要求任何特定代码布局去工作,然而,有一些最佳的做法可以帮助到你。

14.1 使用“默认的”包

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

| 我们建议您遵循Java推荐的包命名约定,使用反向域名方式命名(例如:com.example.project

14.2 放置应用的main类

我们通常建议您放置您应用的main类在其他类之上的根目录包下。@EnableAutoConfiguration注解经常放在您的main上,它隐式地定义了某些项目的基本“搜索包”。例如:如果您正在编写一个JPA应用,则@EnableAutoConfiguration 注解的类所在的包将会被用来搜索 @Entity 实体。

使用根目录包还允许不需要指定 basePackage属性,来使用 @ComponentScan 注解。如果你的main类在根目录包下,你也可以使用 @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. 配置类

Sring Boot 提倡基于Java的配置。尽管可以使用XML源调用 SpringApplication.run(),但我们通常建议您的主要源是 @Configuration 类。通常,定义main方法的类是一个很好的候选人,作为主要的 @Configuration

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

15.1 导入其他配置类

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

15.2 导入XML配置

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

16. 自动配置

Spring Boot 自动配置(auto-configuration)尝试基于您添加的jar依赖自动配置您的Spring应用程序。例如,如果 HSQLDB 在您的类路径上,并且您没有手动配置任何数据库连接bean,那么我们将自动配置一个内存数据库。

您需要通过添加 @EnableAutoConfiguration@SpringBootApplication 注解到一个你 @Configuration 的类来选择加入自动配置。

| 您应该只要添加一个 @EnableAutoConfiguration 注解。我们通常建议您将它添加到你的主要 @Configuration 类上。

16.1 逐渐替换自动配置

自动配置是非侵入性的,你可以在任何时候开始定义自己的配置去替换自动配置的特定的部分。例如,如果你添加自己的 DataSource bean,则默认的内嵌数据库支持将会退回。

如果你想了解什么自动配置在当前存在应用,以及为什么,请使用 --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 属性控制要排除的自动配置类列表。

|在 注解级别和使用属性您都可以定义排除项。

17. Spring Beans 和依赖注入

您可以自由使用任何标准的Spring 框架技术来定义您的beans以及其注入的依赖。 为了简单起见,我们经常发现使用 @ComponentScan 找到你的bean,结合 @Autowired 构造函数注入效果很好。

如果您按照上述建议(将应用程序类放在根包中)构建代码,则可以添加 @ComponentScan 而不使用任何参数。 所有应用程序组件(@Component@Service@Repository@Controller等)将自动注册为Spring Bean。

以下是一个使用构造函数注入获取必需的 RiskAssessor bean的 @Service Bean的例子。

package com.example.service;

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

@Service
public class DatabaseAccountService implements AccountService {

    private final RiskAssessor riskAssessor;

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

    // ...

}

并且如果一个bean有一个构造函数,你可以省略 @Autowired

@Service
public class DatabaseAccountService implements AccountService {

    private final RiskAssessor riskAssessor;

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

    // ...

}

| 请注意,使用构造函数注入允许将RiskAssessor字段标记为final,表示随后不能更改。

18. 使用 @SpringBootApplication注解

许多Spring Boot开发人员总是使用@Configuration@EnableAutoConfiguration@ComponentScan来标注它们的main类。 由于这些注释经常一起使用(特别是如果您遵循上述最佳实践),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运行

您可以从IDE运行一个Spring Boot应用如同一个简单的Java应用。然而,第一步你将需要导入你的项目。导入步骤取决于您的IDE和构建系统将有所变化。 大多数IDE可以直接导入Maven项目,例如Eclipse用户可以从 File 菜单中选择 Import…​Existing Maven Projects

如果您无法将项目直接导入到IDE中,则可以使用构建插件生成IDE元数据。 Maven包括 EclipseIDEA 的插件; Gradle为各种IDE提供插件。

| 如果你偶然运行了一个web 应用两次,将会看到一个“端口已在使用”的错误。STS用户可以使用 Relaunch(重新启动)按钮而不是运行,以确保任何现有实例已关闭。

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中一样,运行在一个exploded 形式中:

$ mvn spring-boot:run

您可能还需要使用有用的操作系统环境变量:

$ export MAVEN_OPTS=-Xmx1024m -XX:MaxPermSize=128M

19.4 使用Gradle插件

Spring Boot Gradle 插件也包含一个 bootRun 任务,用于将你的应用运行在一个 exploded 形式中。当你导入 spring-boot-gradle-plugin 后,这个 bootRun任务都会被添加:

$ gradle bootRun

您可能还需要使用有用的操作系统环境变量:

$ export JAVA_OPTS=-Xmx1024m -XX:MaxPermSize=128M

19.5 热插拔

由于Spring Boot应用只是普通的Java应用,所以JVM热插拔应该开箱即用。JVM热插拔可替的节码有些限制,为了更完整的解决方案,JRebel 或 Spring Loaded 可以被使用。spring-boot-devtools 模块也包含快速重新启动应用的支持。

有关详细信息,请参阅下面第20章 开发者工具部分,以及Hot swapping “How-to”的内容。

20. 开发者工具

Spring Boot 包含一个额外的工具集,可以使应用开发体验更加愉快。spring-boot-devtools 模块可以包含在任何模块中,以提供额外的development-time特性。要包含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 启动的,或者是使用特殊的类加载器启动,那么它被认为是“生产应用程序”。将依赖标记为可选的(optional)是一种最佳做法,防止devtools 通过传递性应用到项目中的其他模块。Gradle不支持开箱即用的可选依赖,因此在此期间您可能想要看一看propdeps-plugin

| 默认情况下重新打包档案不包含devtools。如果你想使用某些远程devtools特性,你需要禁用 excludeDevtools 构建属性去包含它。Maven 和 Gradle插件都支持该属性。

20.1 默认属性

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

虽然缓存在生产中是非常有利的,但它在开发过程中可能会产生反效果,阻止您看到刚刚在应用程序中进行的更改。 由于这个原因,spring-boot-devtools将默认禁用这些缓存选项。

缓存项通常通过设置 application.properties 文件进行配置。例如,Thymeleaf 提供了 spring.thymeleaf.cache 属性。spring-boot-devtools 模块将自动应用合理的 development-time 配置,而不是需要手动设置这些属性。

| 有关被应用属性的完整列表,请参阅DevToolsPropertyDefaultsPostProcessor

20.2 自动重启

使用 spring-boot-devtools 的应用,每当类路径下的文件改变时,将会自动重新启动。这在一个IDE中工作可能是一个有用的特性,因为它为代码更改提供了非常快的反馈循环。默认情况下,任何在类路径下指向一个文件夹的实体,将会被监控其改变。注意,某些资源比如静态资源和视图模版不需要重启应用。

触发重启

由于DevTools 监控类路径资源,所以触发重启的唯一方式是更新classpath。引起classpath被更新的方式取决于你正在使用的IDE。
在Eclipse中,保存修改的文件将导致类路径被更新并触发重新启动。在IntelliJ IDEA中,构建项目(`Build→Make Project`)将具有相同的效果。

| 你也可以通过受支持的构建插件(即Maven和Gradle)启动你的应用,只要fork被启用,因为Devtools需要一个隔离的应用类加载器执行正确的操作。当Gradle 和 Maven检测到Devtools在classpath下,会默认执行这些。【译者注:未懂作者原意,以后再补充】

| 当和LiveReload一起使用时,自动重启功能非常好。详见下文,如果你使用JRebel,自动重启将被禁用以有利于动态重新加载类。其他devtools 特性(例如LiveReload 和 属性重写)仍然可以被使用。

| DevTools 依靠应用上下文的关闭钩子,关闭在重新启动过程中的应用。如果你禁用关闭钩子,它将不会正确的工作(SpringApplication.setRegisterShutdownHook(false))。

| 在决定classpath下的一个实体改变后,是否应该触发重新启动时,DevTools 自动忽略名为spring-boot, spring-boot-devtools, spring-boot-autoconfigure, spring-boot-actuator, spring-boot-starter的项目。

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

如果发现重新启动对于你的应用来说不够快,或遇到类加载问题,您可以考虑重新加载技术例如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 监视其他路径

当您对不在类路径中的文件进行更改时,可能需要重新启动或重新加载应用程序。 为此,请使用 spring.devtools.restart.additional-paths 属性来配置其他路径以监视更改。 您可以使用上述spring.devtools.restart.exclude 属性来控制附加路径下的更改是否会触发完全重新启动或只是实时重新加载

20.2.3 禁用重新启动

如果不想使用重新启动特性,可以使用 spring.devtools.restart.enabled 属性来禁用它。 在大多数情况下,您可以在 application.properties 中设置此项(这仍将初始化重新启动类加载器,但不会监视文件更改)。

如果您需要完全禁用重新启动支持,例如, 因为它不适用于特定库,则需要在调用 SpringApplication.run(...) 之前设置System属性。 例如:

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

如果您使用的是不断编译已更改文件的IDE,那可能更喜欢仅在特定时间触发重新启动。 为此,您可以使用“触发文件”,这是一个特殊文件,当您要实际触发重新启动检查时,必须修改它。 更改文件只会触发检查,只有在Devtools检测到它必须执行某些操作时才会重新启动。 触发文件可以手动更新,也可以通过IDE插件更新。

要使用触发器文件,请使用 spring.devtools.restart.trigger-file 属性。

| 您可能希望将 spring.devtools.restart.trigger-file 设置为全局设置,以使所有项目以相同的方式表现。

20.2.5 自定义重新启动类加载器

如上面的 Restart vs Reload 部分所述,重新启动功能是通过使用两个类加载器实现的。 对于大多数应用程序,此方法运行良好,但有时可能会导致类加载问题。

默认情况下,IDE中的任何打开的项目将使用“重新启动”类加载器加载,任何常规 .jar 文件将使用“base”类加载器加载。 如果您在多模块项目上工作,并且不是每个模块都导入到IDE中,则可能需要自定义一些东西。 为此,您可以创建一个 META-INF/spring-devtools.properties 文件。

spring-devtools.properties 文件可以包含前缀是 restart.exclude.restart.include.的属性。include 元素是应该被拉入“restart”类加载器的项目,而且“exclude”元素是应该向下推入“base”类加载器的项目。 属性的值是将应用于类路径的正则表达式模式。

例如:

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

| 所有属性键必须是唯一的。 只要一个属性以 restart.include.restart.exclude.开头都将会考虑。

| 所有的 META-INF/spring-devtools.properties 将从classpath 被加载。你可以把文件打包到你的项目,或项目消耗的库中。

20.2.6 已知限制

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

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

20.3 实时重新加载

spring-boot-devtools模块包含一个内嵌的LiveReload服务器,可以在资源更改时用于触发浏览器刷新。 LiveReload浏览器扩展程序可以从livereload.com免费提供给Chrome,Firefox和Safari。

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

| 你只能一次运行一个LiveReload服务器。 应用启动之前,请确保没有其他LiveReload服务器正在运行。 如果从IDE启动多个应用程序,则只有第一个应用程序将有LiveReload的支持。

20.4 全局设置

您可以通过向 $HOME 文件夹添加名为 .spring-boot-devtools.properties 的文件来配置全局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>
                <!-- 译者注:排除属性设置为false,即把devtools在打包插件中-->
                <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 。 传递给应用程序的非选项参数应该是您要连接到的远程URL。

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

  • Run 菜单选择 Run Configurations…​
  • 创建一个新的 Java Application "启动配置"
  • 浏览 my - app 项目
  • 使用 org.springframework.boot.devtools.RemoteSpringApplication 作为主类
  • 添加 https://myapp.cfapps.io(或任何您的远程URL) 到 Program arguments

一个运行中的远程客户端将看起来像:

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

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

| 由于远程客户端正在使用与实际应用程序相同的类路径,因此可以直接读取应用属性。 这是 spring.devtools.remote.secret 属性如何被读取并传递到服务器进行认证的原因。

| 始终建议使用https://作为连接协议,以便传输被加密,并且密码不能被拦截。

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

20.5.2 远程更新

远程客户端将以与 本地重新启动 相同的方式监控你的应用类路径的更改。 任何更新的资源将被推送到远程应用,并且(如果需要)触发重新启动。 如果您正在使用您本地没有的云服务迭代功能,这可能会是相当有用的。 通常,远程更新和重新启动比完全重建和部署周期要快得多。

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

20.5.3 远程调试通道

在一个远程应用诊断问题时,Java远程调试非常有用。 不幸的是,当您的应用程序部署在数据中心之外时,并不总是可以启用远程调试。 如果您正在使用基于容器的技术(如Docker),远程调试也可能难以设置。

为了帮助解决这些限制,devtools 支持基于HTTP的远程调试通道 ,远程客户端提供一个在端口8000的本地server,您可以连接远程调试器。 一旦建立连接后,调试信息通过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中,您可以从 Preferences…​ 选择 JavaDebug,将 Debugger timeout (ms) 更改为更合适的值(大多数情况下,60000可以正常工作)。

| 当使用IntelliJ IDEA的远程调试通道时,必须将所有断点配置为挂起线程而不是VM。 默认情况下,IntelliJ IDEA中的断点会挂起整个VM,而不是仅暂停触发断点的线程。 正在暂停的管理远程调试通道的线程有不想要的副作用,会导致调试会话冻结。 当使用IntelliJ IDEA的远程调试通道时,应将所有断点配置为挂起线程而不是VM。 有关详细信息,请参阅IDEA-165769

21. 为生产打包您的应用

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

对于其他“生产就绪”功能,如健康,审计和测量REST或JMX端点; 考虑添加 spring-boot-actuator 。 有关详细信息,请参见 第五部分. Spring Boot 执行器: Production-ready 功能

22. 接下来阅读什么

随着你应该遵循的一些最佳实践,现在应该对如何使用Spring Boot 有一个很好的理解。您现在可以继续深入学习关于Spring Boot 特性具体内容,或者您可以跳过,去阅读关于Spring Boot“生产就绪”方面的内容。

第三部分翻译完毕,继续阅读请移步到这里

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容