IDEA + Spring Boot 的三种热加载方案,看完弄懂,不用加班~
- 1. 概述
- 2. spring-boot-devtools
- 3. IDEA 热部署
- 4. Jrebel
- 666. 彩蛋
“本文在提供完整代码示例,可见 https://github.com/YunaiV/SpringBoot-Labs 的 lab-48-hot-swap 目录。
原创不易,给点个 Star 嘿,一起冲鸭!
1. 概述
在日常开发中,我们需要经常修改 Java 代码,手动重启项目,查看修改后的效果。如果在项目小时,重启速度比较快,等待的时间是较短的。但是随着项目逐渐变大,重启的速度变慢,等待时间 1-2 min 是比较常见的。
这样就导致我们开发效率降低,影响我们的下班时间,哈哈哈~那么是否有方式能够实现,在我们修改完 Java 代码之后,能够不重启项目呢?
答案是有的,通过热部署的方式。并且实现的方式还是非常多,艿艿在本文就会为胖友一一展示。
“旁白君:严格来说,应该叫 HotSwap 的方式,翻译成中文会有热部署、热更新、热替换、热加载等等多种。这里,我们就采用大家可能说的比较多的翻译,热部署。
为了演示方便,胖友可以参考 lab-48-demo 项目,搭建一个简单的 Spring Boot 项目,提供了一个简单的 HTTP API。如下图所示:
“友情提示:不要直接通过克隆 https://github.com/YunaiV/SpringBoot-Labs 来使用该项目,实在太大了!
并且,我们下面我们所有的演示,都是在宇宙无敌 Java 开发工具 IDEA 中进行。
2. spring-boot-devtools
spring-boot-devtools
是 Spring Boot 提供的开发者工具,它会监控当前应用所在的 classpath 下的文件发生变化,进行自动重启。
注意,spring-boot-devtools
并没有采用热部署的方式,而是一种较快的重启方式。其官方文档解释如下:
“FROM 《Spring Boot 2.X 中文文档 —— 开发者工具》
Spring Boot 通过使用两个类加载器来提供了重启技术。
- 不改变的类(例如,第三方 jar)被加载到 base 类加载器中。
- 经常处于开发状态的类被加载到 restart 类加载器中。
当应用重启时,restart 类加载器将被丢弃,并重新创建一个新的。这种方式意味着应用重启比冷启动要快得多,因为省去 base 类加载器的处理步骤,并且可以直接使用。
如果您觉得重启还不够快,或者遇到类加载问题,您可以考虑如 ZeroTurnaround 的 JRebel 等工具。他们是通过在加载类时重写类来加快重新加载。
在项目中,我们需要在 pom.xml
中,引入 spring-boot-devtools
依赖如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional> <!-- 可选 -->
</dependency>
2.1 演示
下面,我们来演示下 spring-boot-devtools
的使用。
① Run 或者 Debug 运行 Spring Boot 应用。
使用浏览器,访问 http://127.0.0.1:8080/demo/echo 接口,返回结果为 "echo"
。
② 修改 DemoController 的 #echo()
方法,设置返回值为 "none"
。
【关键】 我们现在仅仅需要修改了 Java 代码,需要重新编译下代码。点击 IDEA 的菜单 Build
-> Build Project
,手动进行编译。如下图所示:
“友情提示:如果胖友嫌弃鼠标操作太慢,可以使用
Build Project
的快捷键:
- Mac:Command + F9
- Windows:Ctrl + F9
此时,IDEA 控制台会看到 Spring Boot 重新启动的日志如下:
2020-02-09 09:22:52.082 INFO 36495 --- [ Thread-10] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.4.RELEASE)
2020-02-09 09:22:52.195 INFO 36495 --- [ restartedMain] cn.iocoder.demo03.Demo03Application : Starting Demo03Application on MacBook-Pro-8 with PID 36495 (/Users/yunai/Downloads/demo03/target/classes started by yunai in /Users/yunai/Downloads/demo03)
2020-02-09 09:22:52.195 INFO 36495 --- [ restartedMain] cn.iocoder.demo03.Demo03Application : No active profile set, falling back to default profiles: default
2020-02-09 09:22:52.335 INFO 36495 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2020-02-09 09:22:52.336 INFO 36495 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2020-02-09 09:22:52.336 INFO 36495 --- [ restartedMain] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.30]
2020-02-09 09:22:52.342 INFO 36495 --- [ restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2020-02-09 09:22:52.342 INFO 36495 --- [ restartedMain] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 145 ms
2020-02-09 09:22:52.382 INFO 36495 --- [ restartedMain] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-02-09 09:22:52.409 INFO 36495 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2020-02-09 09:22:52.418 INFO 36495 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2020-02-09 09:22:52.419 INFO 36495 --- [ restartedMain] cn.iocoder.demo03.Demo03Application : Started Demo03Application in 0.244 seconds (JVM running for 169.162)
2020-02-09 09:22:52.420 INFO 36495 --- [ restartedMain] .ConditionEvaluationDeltaLoggingListener : Condition evaluation unchanged