SpringBoot系列教程13--SpringBoot开发利刃之热部署原理及最优实践

作者:一一哥

一.SpringBoot的热部署

1.概述

Spring Boot为开发者提供了一个名为spring-boot-devtools的额外工具模块来使得Spring Boot应用支持热部署,提高开发者的开发效率,无需手动重启Spring Boot应用,以此提升了Spring Boot应用的开发体验。

spring-boot-devtools模块可以被引入到任何模块中,以提供development-time特性。

2.自动重启

如果项目中使用了spring-boot-devtools插件,只要classpath下的java文件有了变动,我们的项目就会自动重启。这样我们就可以很快就能看到代码改变后的效果了。

默认情况下,classpath下任何指向文件夹的实体类都会被监控,但是一些资源的修改,尤其是静态的assets,视图模板不会触发重启应用。具体的,比如更改/META-INF/maven,/META-INF/resources ,/resources ,/static ,/public 或/templates下的资源不会触发重启,而是触发livereload。

排除资源

我们可以使用spring.devtools.restart.exclude属性自定义这些重启的排除规则,比如,为了只排除/static和/public,你可以这样设置:

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

注意:

如果你想保留默认属性,并添加其他的排除规则,可以使用spring.devtools.restart.additional-exclude属性作为代替。

3.livereload简介

在devtools模块中包含一个嵌入的livereload服务器,可以在资源变化时用来触发浏览器刷新。

livereload 通过引入的脚本livereload.js在 livereload 服务和浏览器之间建立了一个 WebSocket 连接。每当监测到文件的变动,livereload 服务就会向浏览器发送一个信号,浏览器收到信号后就刷新页面,实现了实时刷新的效果。每次启动时,需要点击对应的图标,如下图所示。

SpringBoot2.x系列教程13--SpringBoot开发利刃之热部署原理及最优实践_spring

我们的浏览器需要在​​http://livereload.com​​网站下载安装扩展插件。Chrome浏览器在应用商店安装livereload插件后,在要自动刷新的页面点击对应的图标,启动应用后更新页面内容或者css等都会触发页面自动刷新。

4.触发重启的条件

由于DevTools监控的是classpath下的资源,所以唯一触发重启的条件就是更新classpath。引起classpath更新的方式依赖于你使用的IDE工具,在Eclipse里,保存一个修改的文件将引起classpath更新,并触发重启。在IntelliJ IDEA中,构建工程(Build → Make Project)也会达到同样的效果。

当判定classpath下实体的改变是否会触发重启时,DevTools自动忽略以下工程:spring-boot,spring-boot-devtools,spring-boot-autoconfigure,spring-boot-actuator和spring-boot-starter。

注意:

你也可以通过支持的构建工具(比如,Maven和Gradle)来启动应用,只要开启fork功能,因为DevTools需要一个隔离的应用类加载器执行正确的操作。Gradle默认支持该行为,按照以下配置可强制Maven插件fork进程:

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork><!-- 如果没有该配置,devtools不会生效 -->
</configuration>
</plugin>
</plugins>
</build>

Restart vs Reload的原理及区别

Spring Boot提供的重启技术是通过使用两个类加载器实现的。没有发生变化的类(比如那些第三方jars)会被加载进一个基础(basic)classloader里面,正在开发的类会加载进一个重启(restart)classloader里面。当应用重启时,restart类加载器会被丢弃,并创建一个新的。这种方式意味着应用重启通常比冷启动(cold starts)快很多,因为基础类加载器已经可用,并且populated(意思是基础类加载器加载的类比较多)。

如果发现重启对于你的应用来说不够快,或遇到类加载的问题,那可以考虑reload技术,比如JRebel,这些技术是通过重写它们加载过的类来实现的。Spring Loaded提供了另一种实现方案,然而很多框架都不支持它,也得不到商业支持。

二.最佳实践

上面给大家普及了Spring Boot热部署的触发条件和实现机制,接下来还是来点干活,说一下在代码中到底该怎么配置,我们来具体实践一下。

1.项目代码配置

1.1.pom.xml配置文件

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
</configuration>
</plugin>
</plugins>
</build>

1.2.yml配置

devtools:
livereload:
enabled: true #是否支持livereload
port: 35729
restart:
enabled: true #是否支持热部署

2.IDEA配置

2.1.File-Settings-Compiler-Build project automatically

SpringBoot2.x系列教程13--SpringBoot开发利刃之热部署原理及最优实践_类加载器_02

2.2.ctrl + shift + alt + /,选择Registry,勾上 Compiler autoMake allow when app running

SpringBoot2.x系列教程13--SpringBoot开发利刃之热部署原理及最优实践_类加载器_03

3.安装livereload插件

下载livereload插件,将其安装到chrome扩展程序中,并选中允许访问文件网址。

SpringBoot2.x系列教程13--SpringBoot开发利刃之热部署原理及最优实践_类加载器_04

4.测试

一开始我们的代码如下:

SpringBoot2.x系列教程13--SpringBoot开发利刃之热部署原理及最优实践_类加载器_05

4.1 修改类

随便修改一个java代码类,应用就会自动重启。

SpringBoot2.x系列教程13--SpringBoot开发利刃之热部署原理及最优实践_spring_06

4.2 修改配置文件

应用会重启。

4.3 修改静态文件(html、css等)

应用不会重启,但是会调用livereload,浏览器会自动刷新,显示最新的修改内容。

5.禁用重启

如果我们不想使用重启特性,可以通过‘spring.devtools.restart.enabled’属性来禁用它。通常情况下可以在application.properties文件中设置(依旧会初始化重启类加载器,但它不会监控文件变化)。

如果需要彻底禁用重启支持,比如,不能跟某个特殊库一块工作,你需要在调用SpringApplication.run(…)之前设置一个系统属性,如下:

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