IDEA/JRebel实现内部/外部/远程Tomcat热部署Spring Boot
1 概述
所谓热部署,对于Java
来说,就是在运行时更新Java
类文件。IDEA
可以使用自带的Spring Boot
热部署的方式进行本地/远程热部署,或者使用JRebel
进行本地/远程热部署,不过需要安装JRebel and XRebel for IntelliJ
这个插件。
本文将会介绍这两种方式来进行热部署,相信在看完之后,开发效率会大大提升。
2 环境
IntelliJ IDEA 2019.3.1
- 本地
Tomcat 9.0.30
JRebel and XRebel for IntelliJ 2020.2.0
- 服务器:
CentOS 8.1.1911
+Tomcat:9.0.33
3 IDEA热部署
3.1 工程部分
3.1.1 新建工程
这里新建一个Spring Boot
工程来进行热部署的测试。
打包方式改为war
,因为后面要使用外部Tomcat
。
勾上热部署工具Spring Boot DevTools
与使用内嵌Tomcat
的Spring Web
。
3.1.2 测试文件
新建一个响应Get
请求的Controller
:
这里添加了一个控制台信息方便查看。
3.2 内部Tomcat
热部署
Spring Boot
内嵌了一个Tomcat
,可以直接使用其进行热部署。
3.2.1 IDEA
设置
首先需要开启Compiler
中的Build project automatically
:
然后按两下shift
,切换到Action
,搜索Registry
:
把compiler.automake.allow.when.app.running
开启:
最后编辑运行设置:
以下两项选择Update classed and resources
:
3.2.2 测试
IDEA
自带了一个HTTP client
,可以发送HTTP
请求,新建一个HTTP Request
:
名字随便:
添加一个GET
请求:
修改路径与端口,注意路径对应:
切换回Spring Boot
的运行设置,shift+F10
运行:
然后就可以发送HTTP
请求了,点击一下绿色的小三角:
返回了对应信息,控制台也有对应输出:
然后修改Controller
里面的test
,改为test1
:
不用重新运行项目,切换一下窗口让IDEA
进行Update
操作:
控制台会重新打印Spring
字样,Messages
中会看到Build completed successfully
的信息,表示Update
操作成功。
重新发送原来的HTTP
请求,报错:
因为此时已经没有响应localhost:8080/test
的方法了,改为test1
后:
3.3 外部Tomcat
热部署
由于已经配置好了IDEA
的相关设置,这里就不重复了,没配置的按上面的方式配置,然后需要增加一个外部的Tomcat
配置。
3.3.1 外部Tomcat
配置
需要增加一个外部Tomcat
的运行配置:
添加Tomcat
,选择local
:
没有显示Tomcat
的话在more items
这里。
改个名字,Configure
选择本地Tomcat
的路径,同时把下面的Build
去掉。
部署这里要选择exploded
的:
改回根路径:
回到Server
选项卡,修改以下两项为Update classed and resources
:
3.3.2 测试
注意外部的Tomcat
热部署不能使用Run
运行,不能像内部的一样直接Shift+F10
,要使用Debug
运行,Shift+F9
:
需要确保默认的8080
端口不被占用,先把刚才的Spring Boot
应用暂停,在run
这里,Tomcat
在services
这里。
测试文件还是刚才的test1
,发送请求:
然后修改test1
的方法体:
切换窗口后会提示class reloaded
:
再次发送刚才的HTTP
请求:
成功!
不过,这种热部署只能修改方法体,如果增加了一个方法或者修改了原来的方法名等,会提示热交换失败,虚拟机不支持该操作:
去万能的百度查了一下:
说是Java HotSwap
的限制,HotSwap
是一个JVM
补丁,这里就略过了。同时后面提到一些类似JRebel
的第三方工具可以支持这种类型的修改,当然,下面会有详细介绍。
3.4 远程Tomcat热部署
远程Tomcat
热部署比较麻烦,细节很多,一个端口错误就一堆异常,所以请耐心细看,需要三个步骤:
- 设置服务器的
Tomcat
- 设置
IDEA
的服务器配置 - 设置
IDEA
的Tomcat
运行配置
最后进行测试。
3.4.1 服务器的Tomcat
设置
需要处理四个端口:
Tomcat
的HTTP
端口JMX
端口RMI
端口- 调试端口
其中HTTP
端口就是常说的Tomcat
端口,浏览器输入http://ip:port
就可以访问到Tomcat
的默认首页,在server.xml
中设置,这里的是在69行的位置,使用默认的8080
。
在Tomcat
的bin
目录下新建一个setenv.sh
:
CATALINA_OPTS="-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=8888
-Dcom.sun.management.jmxremote.rmi.port=8888
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Djava.rmi.server.hostname=ip
-agentlib:jdwp=transport=dt_socket,address=0.0.0.0:12345,suspend=n,server=y"
其中JMX
与RMI
端口设为一致,只要没有占用随便取即可,address
后面的12345
是调试端口,根据需要设置即可。ip
是服务器的地址。
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
这两行表示不使用SSL
连接与使用JMX
客户端连接到Tomcat
时不需要认证。
注意要加上
-Dcom.sun.management.jmxremote.rmi.port=8888
这个RMI
端口,很多文章都没有加上这个导致部署失败。
最后修改执行权限并启动Tomcat
:
chmod 750 setenv.sh
./startup.sh
可以查看一下端口监听:
netstart -ano | grep -E "8080|8888|12345"
三个端口都监听到了,表示配置成功,若没有监听到这三个端口,请检查Tomcat
日志。
同时注意防火墙与安全组的问题,如果开启了防火墙请允许这三个端口通过,安全组也要开启对应端口规则。
3.4.2 IDEA
中的服务器设置
新建一个SFTP
部署:
IP
为服务器IP
,port
为SSH
端口,认证方式可以密码或者密钥,按需要选择,Root path
设为Tomcat
的webapps
路径,如果有乱码问题把下面的高级选项的编码改为utf-8
。
设置好了以后测试一下。
映射的话,下面有完整的说明,Local path
是本地的项目路径,Deployment path
是相对与webapps
的路径(上面设置了Root path
为webapps
),Web path
是相对于url
的路径。
3.4.3 IDEA
中的Tomcat
设置
新建一个Tomcat Remote
:
这里是最重要的设置,设置JMX
端口(这里是上面设置的8888
),Host
选择上一步创建的服务器,Path from root
为根路径, Mapped as
为webapps
路径,Host
下面的端口为Tomcat HTTP
端口(这里使用默认的8080
)。
部署这里选择exploded
的war
包,Application context
选择根路径。
Debug
这里修改上面设置的端口:
3.4.4 测试
需要以Debug
模式(Shift+F9
)运行,不能直接Run
(Shift+F10
):
首先会提示连接到服务器和虚拟机:
然后提示成功部署:
这时候应该会自动打开浏览器,因为这里设置了运行后打开该URL
:
修改方法体后按Ctrl+F9
,提示重新加载类:
Debug
信息提示已重新加载类:
这样就热部署成功了。
当然,像上面的使用外部Tomcat
一样,如果修改方法名或者增加方法,会提示虚拟机不支持操作(解决方法是使用下面的JRebel
):
4 JRebel
热部署
4.1 JRebel
简介
JRebel
是一个集成了应用服务器的JVM
代理,可以使用现有的类加载器重新加载类。只有修改后的类会在运行中的应用程序被重新编译和即时重新加载。
4.2 安装
从设置中的Plugins
安装,搜索即可:
如果速度慢的话可以从官网去下载,然后从本地安装:
4.3 内部Tomcat
热部署
内部Tocmat
热部署非常简单,选中Spring Boot
的运行配置以后,直接点击Rebel Run
即可:
控制台提示重新加载类并且重新配置bean
,表示成功。
当然这样做的前提是默认的Spring Boot
配置已经像上面一样配置好,比如如果修改为:
这样JRebel
就会没有效果。
4.4 外部Tomcat
热部署
像上面配置好外部Tomcat
后,也是直接一键Rebel Run
即可。
注意保证端口不被占用。
这里与默认的热部署相比,最大的不同是允许增加与改变方法,而不仅仅是修改方法体。
下面是原来的Controller
中的方法:
添加一个方法后:
提示已重新加载,表示成功,而不是提示Operation not supported by VM
。
4.5 远程Tomcat热部署
使用JRebel
进行的远程Tomcat
热部署需要先打包上传,然后才能热部署。
4.5.1 打包上传
热部署之前,需要先手动打包:
上传到服务器的Tomcat
的webapps
下。
4.5.2 新建脚本
选择运行在远程服务器或虚拟机,然后选择Tomcat
:
按提示新建脚本:
实测还需要修改脚本权限,750
:
启动之后可以看到JRebel
的输出:JRebel started in remote server mode
。
这样就能成功监控到变化了。
4.5.3 添加远程服务器
服务器名字随便面,URL
为IP
+端口(注意服务器的防火墙还有安全组规则开放端口),如果设置了服务器认证(通过java -jar xxx.jar -set-remote-password PASSWORD
设置),则需要勾选Server authentication
并填上密码。
如果Tomcat
设置了访问密码(设置方法此处查看),则需要勾选HTTP Basic authentication
,并填上用户名与密码:
测试一下连接:
没问题就下一步。
4.5.4 测试
然后,打开JRebel
,选择部署的项目:
下面是打包时的Controller
方法,只有一个test
:
测试(注意test
前的路径为打包的名字,要对应):
然后加上test1
方法,ctrl+F9
,构建:
服务器端提示重新加载类:
再次输入test1
:
这样就远程热部署成功了!
5 附录:JAR
打包
由于Spring Boot
内嵌了Tomcat
,可以打成JAR
包的形式使用内嵌的Tomcat
,这样,可以避免一系列的包括目录映射,端口等繁琐的Tomcat
配置。在原来的WAR
打包形式的基础上,修改pom.xml
中的<packing>
:
加上maven
插件(默认已加上):
可以把原来的ServletInitializer
删去:
使用Maven
打包:
可以先在本地测试一下:
java -jar demo.jar
没问题的话就可以上传到服务器了,或者直接使用热部署,注意Tomcat
与JRebel
需要修改相应的配置,具体就不详细说了。