Spring Boot 官文阅读笔记(二)- Using Spring Boot

References

Spring Boot 1.5: http://docs.spring.io/spring-boot/docs/1.5.x/reference/htmlsingle/#getting-started

前言

通读 Spring Boot 官方文档,当前最新 Release 版本是 1.5;摘录其核心论点,翻译,并做重要批注;

本文为作者的原创作品,转载需注明出处;

Part III, Using Spring Boot

This section goes into more detail about how you should use Spring Boot. It covers topics such as build systems, auto-configuration and how to run your applications. We also cover some Spring Boot best practices. Although there is nothing particularly special about Spring Boot (it is just another library that you can consume), there are a few recommendations that, when followed, will make your development process just a little easier.

【13】Build systems

It is strongly recommended that you choose a build system that supports dependency management, and one that can consume artifacts published to the “Maven Central” repository. We would recommend that you choose Maven or Gradle. It is possible to get Spring Boot to work with other build systems (Ant for example), but they will not be particularly well supported.

【13.1】Dependency management

Each release of Spring Boot provides a curated list of dependencies it supports. In practice, you do not need to provide a version for any of these dependencies in your build configuration as Spring Boot is managing that for you. When you upgrade Spring Boot itself, these dependencies will be upgraded as well in a consistent way.

每一个 Spring Boot 的发布版本都包含了它所支持的依赖列表;实践过程当中,你不需要在你的配置文件中配置任何相关的依赖,因为 Spring Boot 已经帮助你做了这些配置管理;当你升级 Spring Boot 的时候,这些相关依赖将会被同时升级;

[Note]
You can still specify a version and override Spring Boot’s recommendations if you feel that’s necessary.

注意,你也可以自定义依赖版本并且覆盖 Spring Boot 的默认设置;

The curated list contains all the spring modules that you can use with Spring Boot as well as a refined list of third party libraries. The list is available as a standard Bills of Materials (spring-boot-dependencies) and additional dedicated support for Maven and Gradle are available as well.

【13.2】Maven

Maven users can inherit from the spring-boot-starter-parent project to obtain sensible defaults. The parent project provides the following features:

spring-boot-starter-parent提供了一下默认的特性;

  • Java 1.6 as the default compiler level.
  • UTF-8 source encoding.
  • A Dependency Management section, allowing you to omit <version> tags for common dependencies, inherited from the spring-boot-dependencies POM.
    提供了依赖管理;
  • Sensible resource filtering.
  • Sensible plugin configuration (exec plugin, surefire, Git commit ID, shade).
  • Sensible resource filtering for application.properties and application.yml including profile-specific files (e.g. application-foo.properties and application-foo.yml)

On the last point: since the default config files accept Spring style placeholders (${…​}) the Maven filtering is changed to use @..@ placeholders (you can override that with a Maven property resource.delimiter).

【13.2.1】 Inheriting the starter parent

To configure your project to inherit from the spring-boot-starter-parent simply set the parent:

1
2
3
4
5
6
<!-- Inherit defaults from Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
</parent>

[Note]
You should only need to specify the Spring Boot version number on this dependency. If you import additional starters, you can safely omit the version number.

你只需要指定 Spring Boot 的版本号即可,当你导入其它的 staters,不必输入版本号;

With that setup, you can also override individual dependencies by overriding a property in your own project. For instance, to upgrade to another Spring Data release train you’d add the following to your pom.xml.

你可以通过如下的方式去覆盖某一个 property,(特别指明,这里是在使用了spring-boot-starter-parent的情况下,可以通过这样的方式进行扩展定义某个属性;

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

[Tip]
Check the spring-boot-dependencies pom for a list of supported properties.

【13.2.2】 Using Spring Boot without the parent POM

Not everyone likes inheriting from the spring-boot-starter-parent POM. You may have your own corporate standard parent that you need to use, or you may just prefer to explicitly declare all your Maven configuration.

If you don’t want to use the spring-boot-starter-parent, you can still keep the benefit of the dependency management (but not the plugin management) by using a scope=import dependency:

如果你想使用spring-boot-starter-parent,通过使用scope=import的方式导入依赖你将会继续从 dependency management 中获益但不能从 plugin management 中获益;

1
2
3
4
5
6
7
8
9
10
11
12
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from 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>

That setup does not allow you to override individual dependencies using a property as explained above. To achieve the same result, you’d need to add an entry in the dependencyManagement of your project before the spring-boot-dependencies entry. For instance, to upgrade to another Spring Data release train you’d add the following to your pom.xml.

上面的配置不允许你直接使用 property 的方式对某个依赖进行覆盖;为了达到相同的目的,你需要在spring-boot-dependencies entry 之前添加一个dependencyManagement entry 来实现;所以,你需要在pom.xml中添加如下的信息,如下所述,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<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.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

[Note]
In the example above, we specify a BOM but any dependency type can be overridden that way.

【13.2.3】 Changing the Java version

The spring-boot-starter-parent chooses fairly conservative Java compatibility. If you want to follow our recommendation and use a later Java version you can add a java.version property:

1
2
3
<properties>
<java.version>1.8</java.version>
</properties>

【13.2.4】 Using the Spring Boot Maven plugin

Spring Boot includes a Maven plugin that can package the project as an executable jar. Add the plugin to your section if you want to use it:

下面演示了如何将 Spring Boot Maven plugin 加入 pom 中;

1
2
3
4
5
6
7
8
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

[Note]
If you use the Spring Boot starter parent pom, you only need to add the plugin, there is no need for to configure it unless you want to change the settings defined in the parent.

注意,你如果使用了 Spring Boot stater parent pom,你只需要像上面这样添加 plugin 即可,而无需进行额外的配置,除非你想改变默认的配置;

【13.3】Gradle

【13.4】Ant

【13.5】Starters

Starters are a set of convenient dependency descriptors that you can include in your application. You get a one-stop-shop for all the Spring and related technology that you need, without having to hunt through sample code and copy paste loads of dependency descriptors. For example, if you want to get started using Spring and JPA for database access, just include the spring-boot-starter-data-jpa dependency in your project, and you are good to go.

Starter 是有关一系列依赖的描述;你可以一站式的获得与 Spring 相关的所有技术而再无需 copy and paste;比如,你如果需要使用 Spring 和其相关的 JPA 技术,那么你只需要添加spring-boot-starter-data-jpa的依赖配置即可;

The starters contain a lot of the dependencies that you need to get a project up and running quickly and with a consistent, supported set of managed transitive dependencies.

starters 包含了大量的依赖可以帮助你快速的搭建和运行你的项目,并且支持管理过度的依赖;

What’s in a name

All official starters follow a similar naming pattern; spring-boot-starter-*, where * is a particular type of application. This naming structure is intended to help when you need to find a starter. The Maven integration in many IDEs allow you to search dependencies by name. For example, with the appropriate Eclipse or STS plugin installed, you can simply hit ctrl-space in the POM editor and type “spring-boot-starter” for a complete list.

所有的”官方的” starters 都遵循这样一种命名规则;spring-boot-starter-**表示一个特殊类型的应用;这样的命名机制可以有效的帮助你寻找 starter;….

As explained in the Creating your own starter section, third party starters should not start with spring-boot as it is reserved for official Spring Boot artifacts. A third-party starter for acme will be typically named acme-spring-boot-starter.

Creating your own starter 章节中有提到,自定义的或者是第三方的 starters 就不应该以 spring-boot-starter-* 的方式进行命名,因为这种方式是官方所保留的;如果是为acme创建的第三方的 starter,使用acme-spring-boot-starter

The following application starters are provided by Spring Boot under the org.springframework.boot group:

还有很多,见官网的描述

In addition to the application starters, the following starters can be used to add production ready features:

Finally, Spring Boot also includes some starters that can be used if you want to exclude or swap specific technical facets:

Spring Boot 包含一些可以被排除或者被替换的 starters,如下,

【14】 Structuring your code

Spring Boot does not require any specific code layout to work, however, there are some best practices that help.

【14.1】 Using the “default” package

When a class doesn’t include a package declaration it is considered to be in the “default package”. The use of the “default package” is generally discouraged, and should be avoided. It can cause particular problems for Spring Boot applications that use @ComponentScan, @EntityScan or @SpringBootApplication annotations, since every class from every jar, will be read.

如果一个 class 不包含任何的package声明,那么它就是在 “default package” 中;不推荐使用“default package”,甚至应该避免;它会导致使用@ComponnetScan@EntityScan或者@SpringBootApplication等 annotations 的 Spring Boot 应用程序产生一系列的问题,因为每一个 jar 文件中的 class 都会被读取;

[Note] We recommend that you follow Java’s recommended package naming conventions and use a reversed domain name (for example, com.example.project).

【14.2】Locating the main application class

We generally recommend that you locate your main application class in a root package above other classes. The @EnableAutoConfiguration annotation is often placed on your main class, and it implicitly defines a base “search package” for certain items. For example, if you are writing a JPA application, the package of the @EnableAutoConfiguration annotated class will be used to search for @Entity items.

@EnableAutoConfiguration注解通常使用在你的 main class 中,它隐含的为一些元素定义了一个基本的 “search package”,比如,你当前编写的是 JPA 的应用程序,那么有@EnableAutoConfiguration注解的类所在的当前包package,将会被用来搜寻 JPA 所需要的@Entity items;

Using a root package also allows the @ComponentScan annotation to be used without needing to specify a basePackage attribute. You can also use the @SpringBootApplication annotation if your main class is in the root package.

在一个 root package 中使用@ComponentScan的时候无需使用basePackage属性;同样的,你也可以在 root package 中同样使用@SpringBootApplication注解

Here is a typical layout:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
com
+- example
+- myproject
+- Application.java
|
+- domain
| +- Customer.java
| +- CustomerRepository.java
|
+- service
| +- CustomerService.java
|
+- web
+- CustomerController.java

The Application.java file would declare the main method, along with the basic @Configuration.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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】Configuration classes

Spring Boot favors Java-based configuration. Although it is possible to call SpringApplication.run() with an XML source, we generally recommend that your primary source is a @Configuration class. Usually the class that defines the main method is also a good candidate as the primary @Configuration.

Spring Boot 偏向于使用 Java-based 配置;当然你也可以使用 XML source 通过SpringApplicaiton.run()的方式来启动 Spring Boot 应用程序;我们通常推荐你优先使用 @Configuration 类的方式;通常的,main class 是一个非常好的、被强烈推荐用来定义@Configuration配置的候选者;

[Note] Many Spring configuration examples have been published on the Internet that use XML configuration. Always try to use the equivalent Java-based configuration if possible. Searching for enable* annotations can be a good starting point.

【15.1】Importing additional configuration classes

You don’t need to put all your @Configuration into a single class. The @Import annotation can be used to import additional configuration classes. Alternatively, you can use @ComponentScan to automatically pick up all Spring components, including @Configuration classes.

你无需将所有的@Configuration全部配置到一个单独的 class 中,可以使用@Import注解去注入额外的配置类;另外,你也可以使用@ComponentScan的方式自动的去检索和加载所有相关的@Configuration类;

【15.2】Importing XML configuration

If you absolutely must use XML based configuration, we recommend that you still start with a @Configuration class. You can then use an additional @ImportResource annotation to load XML configuration files.

如果种种原因,你必须使用基于 XML 配置的方式,我们依然推荐你从@Configuration class 开始,然后你可以通过使用@ImportResource注解的方式去加载 XML 配置文件;

【16】Auto-configuration

Spring Boot auto-configuration attempts to automatically configure your Spring application based on the jar dependencies that you have added. For example, If HSQLDB is on your classpath, and you have not manually configured any database connection beans, then we will auto-configure an in-memory database.

Spring Boot auto-configuration 将会试图通过 jar 的依赖关系去自动的配置你的 Spring 应用;比如,HSQLDB在你的 classpath 当中,然而,你有没有手动的去配置其它的数据库连接信息,那么这个时候,Spring Boot 将会为你自动的 (auto-configure) 一个内存数据库;

You need to opt-in to auto-configuration by adding the @EnableAutoConfiguration or @SpringBootApplication annotations to one of your @Configuration classes.

通过在你的其中一个Configuration class 文件中添加 @EnableAutoConfiguration 或者 @SpringBootApplication 注解启动 auto-configuration;

[Tip]
You should only ever add one @EnableAutoConfiguration annotation. We generally recommend that you add it to your primary @Configuration class.

你应该只添加一个@EnableAutoConfiguration注解配置,所以这个注解配置最好是添加在你的 primary @Configuration class 上;

【16.1】 Gradually replacing auto-configuration

Auto-configuration is noninvasive, at any point you can start to define your own configuration to replace specific parts of the auto-configuration. For example, if you add your own DataSource bean, the default embedded database support will back away.

自动化配置是无侵入性的,在任何时刻,任何地点,你都可以定义并使用你自己的配置去替换由 auto-configuration 生成的配置;比如,你可以添加自己的DataSource bean,默认的嵌入式数据库支持将会被替换;

If you need to find out what auto-configuration is currently being applied, and why, start your application with the --debug switch. This will enable debug logs for a selection of core loggers and log an auto-configuration report to the console.

如果你想知道 auto-configuration 使用了哪些组件,使用 --debug 的方式启动你的应用;它将会在日志中输出 auto-configuration 的报告;

【16.2】 Disabling specific auto-configuration

If you find that specific auto-configure classes are being applied that you don’t want, you can use the exclude attribute of @EnableAutoConfiguration to disable them.

如果你发现某些 auto-configure 的 classes 不是你想要的,那么你可以通过@EnableAutoConfigurationexclude属性去排除它;

1
2
3
4
5
6
7
8
import org.springframework.boot.autoconfigure.*;
import org.springframework.boot.autoconfigure.jdbc.*;
import org.springframework.context.annotation.*;

@Configuration
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class MyConfiguration {
}

If the class is not on the classpath, you can use the excludeName attribute of the annotation and specify the fully qualified name instead. Finally, you can also control the list of auto-configuration classes to exclude via the spring.autoconfigure.exclude property.

如果你想要排除的 class (比如 DataSourceAutoConfiguration.class ) 并不在你的 classpath 中,你可以使用excludeName属性并通过指定全限定名的方式来排除它;同样,你可以通过使用spring.autoconfigure.exclude 元素来排除一系列的 auto-configuration classes (备注,这是不是需要使用 XML-based 的方式?);

[Tip]
You can define exclusions both at the annotation level and using the property.

你可以同时使用 annotation 和 property 的方式来定义排除;

17. Spring Beans and dependency injection

You are free to use any of the standard Spring Framework techniques to define your beans and their injected dependencies. For simplicity, we often find that using @ComponentScan to find your beans, in combination with @Autowired constructor injection works well.

在使用 Spring Boot 的情况之下,你同样可以使用标准的 Spring Framework 的技术来定义你的 beans 和相关注入的技术;简而言之,我们通常使用@ComponentScan注解的方式去寻找你的所有 beans,通过@Autowired注入 beans;

If you structure your code as suggested above (locating your application class in a root package), you can add @ComponentScan without any arguments. All of your application components (@Component, @Service, @Repository, @Controller etc.) will be automatically registered as Spring Beans.

Here is an example @Service Bean that uses constructor injection to obtain a required RiskAssessor bean.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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;
}

// ...

}

And if a bean has one constructor, you can omit the @Autowired.

1
2
3
4
5
6
7
8
9
10
11
12
@Service
public class DatabaseAccountService implements AccountService {

private final RiskAssessor riskAssessor;

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

// ...

}

[Tip]
Notice how using constructor injection allows the riskAssessor field to be marked as final, indicating that it cannot be subsequently changed.

18. Using the @SpringBootApplication annotation

Many Spring Boot developers always have their main class annotated with @Configuration, @EnableAutoConfiguration and @ComponentScan. Since these annotations are so frequently used together (especially if you follow the best practices above), Spring Boot provides a convenient @SpringBootApplication alternative.

通常,我们会在 main class 上同时使用注解@Configuration, @EnableAutoConfiguration@ComponentScan;因为这样的组合使用得实在是非常的频繁,Spring Boot 提供了一种更为简便的方式@SpringBootApplication来替换;

The @SpringBootApplication annotation is equivalent to using @Configuration, @EnableAutoConfiguration and @ComponentScan with their default attributes:

@SpringBootApplication注解等价于使用同时使用了@Configuration, @EnableAutoConfiguration and @ComponentScan注解;

1
2
3
4
5
6
7
8
9
10
11
12
13
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);
}

}

[Note]
@SpringBootApplication also provides aliases to customize the attributes of @EnableAutoConfiguration and @ComponentScan.

注意,@SpringBootApplication也提供了@EnableAutoConfiguration以及@ComponentScan的别名用来定制化;

【19】 Running your application

One of the biggest advantages of packaging your application as jar and using an embedded HTTP server is that you can run your application as you would any other. Debugging Spring Boot applications is also easy; you don’t need any special IDE plugins or extensions.

使用 executive jar 和嵌入式 HTTP server 的方式来执行你的应用有一个最大的好处就是你可以非常方便的进行 debug,而无需特别的 IDE…

[Note]
This section only covers jar based packaging, If you choose to package your application as a war file you should refer to your server and IDE documentation.

【19.1】 Running from an IDE

You can run a Spring Boot application from your IDE as a simple Java application, however, first you will need to import your project. Import steps will vary depending on your IDE and build system. Most IDEs can import Maven projects directly, for example Eclipse users can select Import…​Existing Maven Projects from the File menu.

If you can’t directly import your project into your IDE, you may be able to generate IDE metadata using a build plugin. Maven includes plugins for Eclipse and IDEA; Gradle offers plugins for various IDEs.

如果你不能直接导入 Spring Boot 工程到你的 IDE 中,你也许需要首先使用 build plugin 生成 IDE 所特定的metadata属性,然后再进行导入即可;Maven 包含了EclipseIDEA的 plugins;

[Tip]
If you accidentally run a web application twice you will see a “Port already in use” error. STS users can use the Relaunch button rather than Run to ensure that any existing instance is closed.

【19.2】 Running as a packaged application

If you use the Spring Boot Maven or Gradle plugins to create an executable jar you can run your application using java -jar. For example:

1
$ java -jar target/myproject-0.0.1-SNAPSHOT.jar

It is also possible to run a packaged application with remote debugging support enabled. This allows you to attach a debugger to your packaged application:

1
2
$ java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n \
-jar target/myproject-0.0.1-SNAPSHOT.jar

【19.3】 Using the Maven plugin

The Spring Boot Maven plugin includes a run goal which can be used to quickly compile and run your application. Applications run in an exploded form just like in your IDE.

1
$ mvn spring-boot:run

You might also want to use the useful operating system environment variable:

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

【19.4】 Using the Gradle plugin

The Spring Boot Gradle plugin also includes a bootRun task which can be used to run your application in an exploded form. The bootRun task is added whenever you import the spring-boot-gradle-plugin:

bootRun task 可以在你的应用处于 exploded form(爆破模式?) 的时候来执行你的应用;bootRun task 一旦当你 import spring-boot-gradle-plugin 之后便会被自动的加入;

【19.5】 Hot swapping

Since Spring Boot applications are just plain Java applications, JVM hot-swapping should work out of the box. JVM hot swapping is somewhat limited with the bytecode that it can replace, for a more complete solution JRebel or the Spring Loaded project can be used. The spring-boot-devtools module also includes support for quick application restarts.

因为 Spring Boot 应用仅仅是一些 plain java 应用,所以 JVM 的热替换技术也可以直接用来使用;但是 JVM 热替换技术受限于它的字节码处理的方式,更为完善的解决方案参考 JRebel 或者 Spring Loadedspring-boot-devtools模块同样支持应用的快速重启;

See the Chapter 20, Developer tools section below and the Hot swapping “How-to”for details.

【20】 Developer tools

Spring Boot includes an additional set of tools that can make the application development experience a little more pleasant. The spring-boot-devtools module can be included in any project to provide additional development-time features. To include devtools support, simply add the module dependency to your build:

Spring Boot 包含了一系列额外的工具可以使得你的开发过程更愉快;spring-boot-devtools模块可以被任何的项目使用用来提供额外的 development-time 的特性;要使用 devtools,简单的通过如下的配置加入你的构建中,

MAVEN

1
2
3
4
5
6
7
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>

Gradle

1
2
3
dependencies {
compile("org.springframework.boot:spring-boot-devtools")
}

[Note] Developer tools are automatically disabled when running a fully packaged application. If your application is launched using java -jar or if it’s started using a special classloader, then it is considered a “production application”. Flagging the dependency as optional is a best practice that prevents devtools from being transitively applied to other modules using your project. Gradle does not support optional dependencies out-of-the-box so you may want to have a look to the propdeps-plugin in the meantime.

注意,挡在执行 fully packaged application 的时候,developer tools 将会被自动的 disabled;当你的应用通过java -jar或者通过一个特殊的 classloader 启动的时候,将会被认为该应用是”production application”;这个时候,将 devtools 设置为可选的是最优方案,这样可以避免 devtools 通过你的应用而被部署到其它的模块之中;Gradle 不支持 optional dependencies,所以,你需要使用propdeps-plugin.

[note] repackaged archives do not contain devtools by default. If you want to use certain remote devtools feature, you’ll need to disable the excludeDevtools build property to include it. The property is supported with both the Maven and Gradle plugins.

注意,repackaged 归档文件默认不包含 devtools;如果你想使用特定的 remote devtools feature,你需要将excludeDevtools构建属性 disable;

【20.1】Property defaults

Several of the libraries supported by Spring Boot use caches to improve performance. For example, [template engines](http://docs.spring.io/spring-boot/docs/1.5.x/reference/htmlsingle/#boot-features-spring-mvc-template-engines will cache compiled templates to avoid repeatedly parsing template files. Also, Spring MVC can add HTTP caching headers to responses when serving static resources.

一系列的由 Spring Boot 所支持的 libraries 使用缓存来提高性能;比如 template engines 将会缓存编译好的模板以避免重复的解析;同样的,当 Spring MVC 处理静态资源的时候可以通过添加 HTTP 缓存头来加速响应;

Whilst caching is very beneficial in production, it can be counter productive during development, preventing you from seeing the changes you just made in your application. For this reason, spring-boot-devtools will disable those caching options by default.

虽然缓存在生产环境下非常有益,但是在开发环境中,缓存往往会阻止你看到应用中新的变化;也因此,spring-boot-devtools 将会是默认被禁止的;言外之意,需要手动的将其开启;

Cache options are usually configured by settings in your application.properties file. For example, Thymeleaf offers the spring.thymeleaf.cache property. Rather than needing to set these properties manually, the spring-boot-devtools module will automatically apply sensible development-time configuration.

缓存选项通常是通过 application.properties 配置文件进行设置;比如,Thymeleaf 提供了 spring.thymeleaf.cache 属性;不想其它属性需要手动配置,spring-boot-devtools将会自动的启动 development-time configuration

[Tip]
For a complete list of the properties that are applied see DevToolsPropertyDefaultsPostProcessor.

完整的属性列表参考 DevToolsPropertyDefaultsPostProcessor.

【20.2】 Automatic restart

Applications that use spring-boot-devtools will automatically restart whenever files on the classpath change. This can be a useful feature when working in an IDE as it gives a very fast feedback loop for code changes. By default, any entry on the classpath that points to a folder will be monitored for changes. Note that certain resources such as static assets and view templates do not need to restart the application.

应用中使用到了spring-boot-devtools的情况下,当 classpath 中的文件有变更的时候,应用将会被自动的重启;当你需要尽快的看到应用的变化和响应,这将会是一个有用的特性;默认的,任何在 classpath 发生改变的 entry 将会被监视;但是,注意,某些资源比如静态资源和 view templates 的改变无需重启应用;

Triggering a restart

As DevTools monitors classpath resources, the only way to trigger a restart is to update the classpath. The way in which you cause the classpath to be updated depends on the IDE that you are using. In Eclipse, saving a modified file will cause the classpath to be updated and trigger a restart. In IntelliJ IDEA, building the project (Build → Make Project) will have the same effect.

使得应用重启的唯一办法就是 classpath 有更新,当 Eclipse 修改并保存一个 classpath 的文件,会引起 devTools 重启;

[Tip]You can also start your application via the supported build plugins (i.e. Maven and Gradle) as long as forking is enabled since DevTools need an isolated application classloader to operate properly. Gradle and Maven do that by default when they detect DevTools on the classpath.

[Tip]
Automatic restart works very well when used with LiveReload. See below for details. If you use JRebel automatic restarts will be disabled in favor of dynamic class reloading. Other devtools features (such as LiveReload and property overrides) can still be used.

[Note]
DevTools relies on the application context’s shutdown hook to close it during a restart. It will not work correctly if you have disabled the shutdown hook ( SpringApplication.setRegisterShutdownHook(false)).

注意,这里提及了 DevTools 是如何关闭 Spring 应用的,是通过 shutdown hook 实现的;

[Note]
When deciding if an entry on the classpath should trigger a restart when it changes, DevTools automatically ignores projects named spring-boot, spring-boot-devtools, spring-boot-autoconfigure, spring-boot-actuator, and spring-boot-starter.

DevTools 将会自动忽略spring-boot, spring-boot-devtools, spring-boot-autoconfigure, spring-boot-actuator, and spring-boot-starter中的 classpath 文件改动了;

Restart vs Reload

The restart technology provided by Spring Boot works by using two classloaders. Classes that don’t change (for example, those from third-party jars) are loaded into a base classloader. Classes that you’re actively developing are loaded into a restart classloader. When the application is restarted, the restart classloader is thrown away and a new one is created. This approach means that application restarts are typically much faster than “cold starts” since the base classloader is already available and populated.

重点:上面这段描述了 Spring Boot 的 restart 技术是如何实现的,通过两个不同的 Class Loader,一个是base classloader,另外一个是restart classloaderbase classloader是用来加载第三方不变的 classes,而自己开发的应用 class 将会由restart classloader进行加载,当你的当前应用重启,只是简单的将restart classloader丢弃,然后生成一个新的restart classloader加载当前的应用,所以,通过这种方式,restart 重启的性能会比冷启动快很多;

If you find that restarts aren’t quick enough for your applications, or you encounter classloading issues, you could consider reloading technologies such as JRebel from ZeroTurnaround. These work by rewriting classes as they are loaded to make them more amenable to reloading. Spring Loaded provides another option, however it doesn’t support as many frameworks and it isn’t commercially supported.

如果你发现你的应用的重启的性能并不是太好,建议使用JRebel,一种通过修改 class 字节码的方式进行重载,当然也可以使用Spring Loaded,不过它并不被多数框架所支持并且它也不是用于商用的;

【20.2.1】Excluding resources

Certain resources don’t necessarily need to trigger a restart when they are changed. For example, Thymeleaf templates can just be edited in-place. By default changing resources in /META-INF/maven, /META-INF/resources ,/resources ,/static ,/public or /templates will not trigger a restart but will trigger a live reload. If you want to customize these exclusions you can use the spring.devtools.restart.exclude property. For example, to exclude only /static and /public you would set the following:

上面这段通过使用 Thymeleaf 举列表示,某些不是 classpath 的文件不会触发 restart 但是可能会触发 live reload,也就是说明 live reload 和 restart 是两个不同的东西;如果你需要自定义哪些 classpath 中的文件被修改以后并不被重启,设置 spring.devtools.restart.exclude 属性值;

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

【20.2.2】Watching additional paths

You may want your application to be restarted or reloaded when you make changes to files that are not on the classpath. To do so, use the spring.devtools.restart.additional-paths property to configure additional paths to watch for changes. You can use the spring.devtools.restart.exclude property described above to control whether changes beneath the additional paths will trigger a full restart or just a live reload.

通过设置 spring.devtools.restart.additional-paths 属性将不是 classpath 中的文件也纳入监视,一旦发生变动,restart

【20.2.3】Disabling restart

If you don’t want to use the restart feature you can disable it using the spring.devtools.restart.enabled property. In most cases you can set this in your application.properties (this will still initialize the restart classloader but it won’t watch for file changes).

可以通过在application.properties配置文件中设置spring.devtools.restart.enabled属性来禁止 restart;

If you need to completely disable restart support, for example, because it doesn’t work with a specific library, you need to set a System property before calling SpringApplication.run(…​). For example:

因为某些特殊的 library 并不会因为设置了spring.devtools.restart.enabled属性而生效,所以,需要在调用SpringApplication.run(…​)之前设置一个System属性来对 restart 进行完全的禁止;如下 ,

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

我的思考,

在一个有着完整的单元测试的项目中,保证代码的健全和健壮性往往是依赖于单元测试;所以,我不太赞同使用 restart 的方式在应用中去查看变动;

【20.2.4】Using a trigger file

If you work with an IDE that continuously compiles changed files, you might prefer to trigger restarts only at specific times. To do this you can use a “trigger file”, which is a special file that must be modified when you want to actually trigger a restart check. Changing the file only triggers the check and the restart will only occur if Devtools has detected it has to do something. The trigger file could be updated manually, or via an IDE plugin.

To use a trigger file use the spring.devtools.restart.trigger-file property.

[Tip]
You might want to set spring.devtools.restart.trigger-file as a global setting so that all your projects behave in the same way.

【20.2.5】 Customizing the restart classloader

As described in the Restart vs Reload section above, restart functionality is implemented by using two classloaders. For most applications this approach works well, however, sometimes it can cause classloading issues.

By default, any open project in your IDE will be loaded using the “restart” classloader, and any regular .jar file will be loaded using the “base” classloader. If you work on a multi-module project, and not each module is imported into your IDE, you may need to customize things. To do this you can create a META-INF/spring-devtools.properties file.

如果你的项目是多模块项目,而不是每一个模块都需要导入你的 IDE 中,因此,你也许需要自定义一些东西;可以通过META-INF/spring-devtools.properties文件来进行自定义;

The spring-devtools.properties file can contain restart.exclude. and restart.include. prefixed properties. The include elements are items that should be pulled up into the “restart” classloader, and the exclude elements are items that should be pushed down into the “base” classloader. The value of the property is a regex pattern that will be applied to the classpath.

spring-devtools.properties文件可以包含restart.exclude.restart.include.前缀属性,restart.include.所表示的 classes 将会使用“restart” classloader进行架子啊,而通过restart.exclude.所表示的 classes 将会使用“base” classloader进行加载;比如,

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

【20.2.6】 Known limitations

Restart functionality does not work well with objects that are deserialized using a standard ObjectInputStream. If you need to deserialize data, you may need to use Spring’s ConfigurableObjectInputStream in combination with Thread.currentThread().getContextClassLoader().

使用了标准的ObjectInputStream的对象,在 restart 反序列化的过程当中,并不能很好的工作;取而代之,你需要结合Thread.currentThread().getContextClassLoader()并使用 Spring 的ConfigurableObjectInputStream

Unfortunately, several third-party libraries deserialize without considering the context classloader. If you find such a problem, you will need to request a fix with the original authors.

不幸的是,许多第三方类库,在反序列化的过程当中并没有考虑 context classloader,所以,如果你发现了上述的问题,只能求助于作者了;

【20.3】 LiveReload

The spring-boot-devtools module includes an embedded LiveReload server that can be used to trigger a browser refresh when a resource is changed. LiveReload browser extensions are freely available for Chrome, Firefox and Safari from livereload.com.

spring-boot-devtools模块包含了一个嵌入式的LiveReloader server,可以帮助我们,当资源文件发生变化以后自动刷新浏览器;这个和 javascript 的 Grunt Live Reload 很类似,不过,我认为,当使用 javascript 进行前端开发的时候,这个特性非常有用,但是针对服务器端,对这个特性我持保留意见,并且并不太看好..

If you don’t want to start the LiveReload server when your application runs you can set the spring.devtools.livereload.enabled property to false.

通过设置spring.devtools.livereload.enabled属性禁用Live Reload

【20.4】 Global settings

You can configure global devtools settings by adding a file named .spring-boot-devtools.properties to your $HOME folder (note that the filename starts with “.”). Any properties added to this file will apply to all Spring Boot applications on your machine that use devtools. For example, to configure restart to always use a trigger file, you would add the following:

通过在$HOME目录中添加配置文件.spring-boot-devtools.properties来设置全局配置,当你使用了 devtools 的情况下,该文件中的任何配置将会被应用到所有的 Spring Boot 应用程序当中;比如,重启的策略一贯使用的是一个 trigger 文件,可以添加如下的全局配置,比如,

~/.spring-boot-devtools.properties.

1
spring.devtools.reload.trigger-file=.reloadtrigger

上面的配置表示,通过 reloadtrigger 文件的变动来触发重启动作;

【20.5】Remote applications

The Spring Boot developer tools are not just limited to local development. You can also use several features when running applications remotely. Remote support is opt-in, to enable it you need to make sure that devtools is included in the repackaged archive:

要启动远程开发和使用远程的特性,要确保 devtools 在归档文件中被启用

1
2
3
4
5
6
7
8
9
10
11
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludeDevtools>false</excludeDevtools>
</configuration>
</plugin>
</plugins>
</build>

Then you need to set a spring.devtools.remote.secret property, for example:

1
spring.devtools.remote.secret=mysecret

Remote devtools support is provided in two parts; there is a server side endpoint that accepts connections, and a client application that you run in your IDE. The server component is automatically enabled when the spring.devtools.remote.secret property is set. The client component must be launched manually.

devtools 的远程功能由两部分提供,一个是服务器端接收连接,一个是客户端发起连接;当你设置了spring.devtools.remote.secret属性服务器端将会自动启动 devtools 的远程功能,然而,客户端必须手动启动;

【20.5.1】Running the remote client application

The remote client application is designed to be run from within your IDE. You need to run org.springframework.boot.devtools.RemoteSpringApplication using the same classpath as the remote project that you’re connecting to. The non-option argument passed to the application should be the remote URL that you are connecting to.

客户端程序需要在与远程服务器相同的 classpath 中运行org.springframework.boot.devtools.RemoteSpringApplication,一些必须的参数必须通过远程 URL 提供;

For example, if you are using Eclipse or STS, and you have a project named my-app that you’ve deployed to Cloud Foundry, you would do the following:

  • Select Run Configurations…​ from the Run menu.
  • Create a new Java Application “launch configuration”.
  • Browse for the my-app project.
  • Use org.springframework.boot.devtools.RemoteSpringApplication as the main class.
  • Add https://myapp.cfapps.io to the Program arguments (or whatever your remote URL is).

上面描述了如何建立一个本地应用连接远程应用的过程,这种方式在调试过程中非常方便;

[Tip]
Because the remote client is using the same classpath as the real application it can directly read application properties. This is how the spring.devtools.remote.secret property is read and passed to the server for authentication.

因为本地和远程的 classpath 相同,所以 devtools 可以从本地获取对应的 spring.devtools.remote.secret 属性用来和服务器进行比对和验证;

[Tip]
It’s always advisable to use https:// as the connection protocol so that traffic is encrypted and passwords cannot be intercepted.

[Tip]
If you need to use a proxy to access the remote application, configure the spring.devtools.remote.proxy.host and spring.devtools.remote.proxy.port properties.

【20.5.2】 Remote update

The remote client will monitor your application classpath for changes in the same way as the local restart. Any updated resource will be pushed to the remote application and (if required) trigger a restart. This can be quite helpful if you are iterating on a feature that uses a cloud service that you don’t have locally. Generally remote updates and restarts are much quicker than a full rebuild and deploy cycle.

🚩 靠,这里强大了.. 远程应用可以监视你的本地修改,本地的修改将会被推送到远程应用,如果是 classpath 的修改并且启动了 restart,远程服务器将会同时被更改;这时一个非常有用的功能,就是,如果你的本地没有云端的应用环境,那么可以通过修改本地的方式,直接对云端进行调试.. 这个功能的确强大,特别是基于云端开发的时候;

[Note]
Files are only monitored when the remote client is running. If you change a file before starting the remote client, it won’t be pushed to the remote server.

注意,只有当远程应用处于运行的状态,文件才会被监控;如果你在启动远程应用之前修改了本地的应用,该更改并不会被推送到远程应用上;(是否可以考虑实现这样一个扩展,比对本地和远程文件的改动,进行 push … )

【20.5.3】 Remote debug tunnel

Java remote debugging is useful when diagnosing issues on a remote application. Unfortunately, it’s not always possible to enable remote debugging when your application is deployed outside of your data center. Remote debugging can also be tricky to setup if you are using a container based technology such as Docker.

Java 的远程调试在调试和定位问题的时候非常有用,但是,它的功能往往受限于异构的网络,不同的数据中心,或者是 Docker 容器环境,往往在这样一系列的环境中,Java 的远程调试就会失效;

To help work around these limitations, devtools supports tunneling of remote debug traffic over HTTP. The remote client provides a local server on port 8000 that you can attach a remote debugger to. Once a connection is established, debug traffic is sent over HTTP to the remote application. You can use the spring.devtools.remote.debug.local-port property if you want to use a different port.

为了解决这些限制,devtools 支持使用 HTTP 隧道的方式;远程应用提供一个基于 8000 端口本地 server 服务,然后你可以使用该端口服务进行远程调试;通过 spring.devtools.remote.debug.local-port 属性配置可以改变 server 端口;

You’ll need to ensure that your remote application is started with remote debugging enabled. Often this can be achieved by configuring JAVA_OPTS. For example, with Cloud Foundry you can add the following to your manifest.yml:

你必须确保你的远程应用开启了对远程调试的支持,通过我们使用JAVA_OPTS配置做到这一点;比如,在使用 Cloud Foundry 的环境下,通过配置manifest.yml,

1
2
3
---
env:
JAVA_OPTS: "-Xdebug -Xrunjdwp:server=y,transport=dt_socket,suspend=n"

[Tip]
Notice that you don’t need to pass an address=NNNN option to -Xrunjdwp. If omitted Java will simply pick a random free port.

[Note]
Debugging a remote service over the Internet can be slow and you might need to increase timeouts in your IDE. For example, in Eclipse you can select JavaDebug from Preferences…​ and change the Debugger timeout (ms) to a more suitable value (60000 works well in most situations).

[Warning]
When using the remote debug tunnel with IntelliJ IDEA, all breakpoints must be configured to suspend the thread rather than the VM. By default, breakpoints in IntelliJ IDEA suspend the entire VM rather than only suspending the thread that hit the breakpoint. This has the unwanted side-effect of suspending the thread that manages the remote debug tunnel, causing your debugging session to freeze. When using the remote debug tunnel with IntelliJ IDEA, all breakpoints should be configured to suspend the thread rather than the VM. Please see IDEA-165769 for further details.

【21】Packaging your application for production

Executable jars can be used for production deployment. As they are self-contained, they are also ideally suited for cloud-based deployment.

For additional “production ready” features, such as health, auditing and metric REST or JMX end-points; consider adding spring-boot-actuator. See Part V, “Spring Boot Actuator: Production-ready features” for details.

Executable jars 可以用途生产环境;但是要作为一个 “production ready” 的应用,必须包含一些额外的特性,health, auditing and metric REST or JMX end-points;这些特性通过spring-boot-actuator提供;