热加载不是一个新的概念。我们在Spring开发过程中,会不断的重启服务来观察项目开发效果,而热加载可以帮助我们很快的加载有修改行为的文件,从而免除了整个系统的重启工作,使我们开发效率大幅提升。
我的当前环境是Mac + IDEA + Maven,引入热加载的方式也很简单,分为3步:
- 引入devtool依赖,看着名字“开发工具”就是帮助我们进行日常开发的依赖包:
org.springframework.boot
spring-boot-devtools
true
- Preference --> Compiler --> Build project automatically
- 第三步需要用户先确定自己环境下maintenance的快捷键,然后设置Registry
确定maintenance快捷键:Preference --> keymap --> Maintenance
设置Registry:在IDEA主操作面板上执行快捷键,选择Registry,将compiler.automake.allow.when.app.running设置为true
完成配置之后,我们可以看一下具体的热加载的规则和自定义配置方式,这些内容我建议可以先通过官方文档的阅读再进行实操,这样会更加深刻。官方文档在Hot Swapping中有讲解,我们看一下原文:
https://docs.spring.io/spring-boot/docs/2.1.4.RELEASE/reference/htmlsingle/#howto-hotswapping
There are several options for hot reloading. The recommended approach is to use
spring-boot-devtools
, as it provides additional development-time features, such as support for fast application restarts and LiveReload as well as sensible development-time configuration (such as template caching). Devtools works by monitoring the classpath for changes. This means that static resource changes must be "built" for the change to take effect. By default, this happens automatically in Eclipse when you save your changes. In IntelliJ IDEA, the Make Project command triggers the necessary build. Due to the default restart exclusions, changes to static resources do not trigger a restart of your application. They do, however, trigger a live reload.
文章解释了SpringBoot官方推荐使用spring-boot-devtools,它对于我们的开发提供了这样两种有利的帮助功能:快速重启(fast application restarts)和重新渲染(LiveReload)。 default restart exclusions 中定义了不会因为文件修改而触发快速重启的目录
Certain resources do not necessarily need to trigger a restart when they are changed. For example, Thymeleaf templates can be edited in-place. By default, changing resources in
/META-INF/maven
,/META-INF/resources
,/resources
,/static
,/public
, or/templates
does not trigger a restart but does trigger a live reload.
可见springboot框架本身而言不希望这些静态文件的变动,导致应用重启,但是这些资源文件跟web开发是直接相关的,所以,这些文件的变动虽然不会导致应用重启,但是会触发live reload的,其效果打个比方:在做web开发的时候,我修改了上述目录中的css文件,一旦保存,浏览器不需要手动刷新,直接就可以看到我的样式修改效果!
当然如果你希望能够更自由的定义不触发快速重启的文件目录,可以在application.properties文件中通过配置复写devtool的排除目录列表:
spring.devtools.restart.exclude=static/**,public/**
如此一来只有这两个目录中的文件变更不会触发应用重启了!还有一种情况,如果除了官方默认的exclude目录外,你还希望增加其他的目录,一种方法是复写restart.exclude配置项,另一种方式是:
spring.devtools.restart.additional-exclude=otherdir/**
所有的使用介绍就到这,根据上述操作,已经可以实现自己项目的热加载,接下来用一个来更立体的展示devtool的热加载,同时还会提到,热加载的best practice。
该代码表示暴露一个get请求
@GetMapping(path = "mode_1/{name}/{age}")
public Map getUrlPathParam(@PathVariable("name") String name, @PathVariable String age) {
return new HashMap(){{
put("name", name);
put("age", age);
}};
}
此时当我们在return上面加入System.out.println("test fast application restart")后,会发现一个问题,intellij这款IDE它不需要手动保存文件(与eclipse不同,在eclipse中,当用户手动保存一个文件后会自动触发restart),那么intellij触发机制是什么呢?
IDE(无论Intellij还是Eclipse)触发热加载的方式有两种:手动与自动
手动:Eclipse(保存)/Intellij(Build --> Build Project 快捷键为commond + F9)
自动:在SpringBoot官方文档的Appendix A. Common application properties中,关于Spring.devtools其中有这样一个属性:
spring.devtools.restart.poll-interval=1s 它表示devtools.restart会每隔1s进行一次轮询检测是否在classpath下有文件更改,如果有,则自动restart。
说到这难免有一个问题,我们在不断的开发过程中,不断的restart是不是非常消耗计算资源,感觉上也怪怪的,主观上来说,我们也不需要任何修改都restart,而是在我需要它重新启动的时候,能够快速重启,减少我等待时间。针对这一点我们就得说到SpringBoot推荐的最佳实践:设置触发文件Using a Trigger File,其使用方式为,在application.properties中加入配置项:
spring.devtools.restart.trigger-file=restart_trigger.txt
同时,在application.properties同一级目录下创建restart_trigger.txt,不妨在里面写入“1”,当需要触发快速重启时,变换“1”-->“2”,此时可以看到restart发生。
说到这里我们不妨看看官方文档对热加载原理的解释:
The restart technology provided by Spring Boot works by using two classloaders. Classes that do not change (for example, those from third-party jars) are loaded into a base classloader. Classes that you are 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.
两句话概括:引入restart功能后(引入devtools)Spring Boot使用两个类加载器,一个用来加载用户开发的工程代码(restart classloader),一个用来管理第三方类库(base classloader)。当用户修改代码后,会新建一个restart classloader以替换之前的,而base classloader不变,这样项目启动速度会比冷启动要快。