本文主要介紹兩種熱部署方式:Jrebel與devtools
一、熱部署與熱加載
在應用運行的時升級軟件,無需重新啟動的方式有兩種,熱部署和熱加載。
對於Java應用程序來說,熱部署就是在服務器運行時重新部署項目,熱加載即在在運行時重新加載class,從而升級應用。
二、實現原理
熱加載的實現原理主要依賴java的類加載機制,在實現方式可以概括為在容器啟動的時候起一條后台線程,定時的檢測類文件的時間戳變化,如果類的時間戳變掉了,則將類重新載入。
對比反射機制,反射是在運行時獲取類信息,通過動態的調用來改變程序行為;
熱加載則是在運行時通過重新加載改變類信息,直接改變程序行為。
熱部署原理類似,但它是直接重新加載整個應用,這種方式會釋放內存,比熱加載更加干凈徹底,但同時也更費時間。
三、在java中應用
1.生產環境
熱部署作為一個比較靈活的機制,在實際的生產上運用還是有,但相對很少,熱加載則基本沒有應用。分析如下
- 一、安全性
熱加載這種直接修改jvm中字節碼的方式是難以監控的,不同於sql等執行可以記錄日志,直接字節碼的修改幾乎無法記錄代碼邏輯的變化,對既有代碼行為的影響難以控制,對於越注重安全的應用,熱加載帶來的風險越大,這好比給飛行中的飛機更換發動機。
- 二、適用的情景
技術大部分是跟需求掛鈎的,而需要熱部署的情景很少。
- 頻繁的部署並且啟動耗時長的應用
- 無法停止服務的應用
在生產中,並沒有需要頻繁部署的應用,即使是敏捷,再快也是一周一次的迭代,並且通過業務划分和模塊化編程,部署的代價完全可以忽略不計,對於現有的應用,啟動耗時再長,也並非長到無法忍受,如果真的這么長,那更應該考慮的是如何進行模塊拆分,分布式部署了。
對於無法停止服務的應用,比如現在的雲計算平台這樣分布式應用,采用分批上線也可以滿足需求,類似熱部署方案應該是放在最后考慮的解決方案。
四、Jrebel與devtools
1.JRebel
一個javaagent監控系統中的classes和resources文件在工作空間的變化,然后在運行的應用服務器上熱加載這些變化,支持下面的這些類型的文件改變:
- 改變Java classes文件.
- 改變框架配置文件 (e.g. Spring XML files and annotations, Struts mappings, etc).
- 任何靜態資源文件 (e.g. JSPs, HTMLs, CSSs, XMLs, .properties, etc)
JRebel使用(轉載自:https://www.cnblogs.com/Chenjiabing/p/13924849.html)
只需要在IDEA
中裝一個JRebel的插件,遠程熱部署需要在服務器上裝一個JRebel
本地如何熱部署?
JRebel
插件安裝完成之后,將IDEA
中的自動編譯
開啟,然后找到IDEA
中的JRebel
的工具面板,將所需要熱部署的項目或者模塊勾選上即可,如下圖:
勾選成功之后將會在項目或者模塊的
src/resource
下生成一個rebel.xml
文件。
此時在Spring Boot
的主啟動類上右鍵,將會出現以JRebel
啟動的選項,如下圖:
當然在IDEA
的右上角也存在啟動的按鈕,如下圖:
①
是本地啟動和DEBUG
模式啟動,②
是遠程熱部署的時候更新按鈕。
此時就已經配置成功了,如果勾選的項目或者模塊出現了改變,按CRTL+SHIFT+F9
則會自動重新編譯加載改變的部分,不用再重新啟動項目了。
遠程如何熱部署?
遠程熱部署需要在服務器上安裝並JRebel,
成功后需要設置遠程連接的密碼,在JRebel
的根目錄下執行以下命令:
java -jar jrebel.jar -set-remote-password 123456789
此處設置的
123456789
則是遠程的密碼,在IDEA
連接服務器的時候需要。
服務器配置成功后,在IDEA中JRebel的面板中設置遠程熱部署的模塊,如下圖:
勾選成功后,將會在
src/resource
下生成一個rebel-remote.xml
文件。
此時將Spring Boot
項目打包成一個Jar
,上傳到服務器,執行以下命令啟動項目:
nohup java -agentpath:/usr/local/jrebel/lib/libjrebel64.so -Drebel.remoting_plugin=true -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=9083 -jar xxx.jar &
libjrebel64.so
這個文件是JRebel
的lib
目錄下的文件。
-Xdebug
之后,-jar
之前的命令是開啟遠程調試的,如果不需要的可以去掉,不知道遠程調試的,可以看:驚呆了!Spring Boot還能開啟遠程調試~。
項目啟動成功后,服務器上的配置就完成了。
此時在IDEA中需要設置連接到剛才啟動的項目,打開File->setting->JRbel&XRebel->JRbel Remote Servers
,如下圖:
步驟如下:
- 點擊
+
號添加一個服務 - 填寫信息
server name
隨便起個服務的名字server URL
格式:http://ip:port
,這里的ip
是服務器的IP,port
是項目端口號。- 遠程密碼則是上文設置的
JRebel
的密碼123456789
。
- 點擊
OK
,即可添加成功。
以上設置成功后,點擊右上角的遠程部署按鈕,下圖中的②
號按鈕,則會自動更新服務器上已啟動項目的代碼使之本地修改在服務端自動生效:
在JRebel Console
這個面板中將會打印出遠程熱部署更新的日志信息,如下圖:
只要本地有了更改,點擊遠程熱部署按鈕,則會自動上傳代碼到服務器端並實時更新,不用重新啟動項目。
多模塊開發的坑
如果是多模塊開發,比如分為api
(最終的Jar
包),core
(核心包),service
(業務層的包),最終打包運行在服務器端的是api
這個模塊,其余兩個模塊都是屬於依賴模塊,雖然在JRebel
遠程熱部署選項中都勾選了,但是它們的代碼更改並不會在服務端生效。
這個如何解決呢?很簡單,在api
項目下的rebel-remote.xml
文件中將其余兩個模塊添加進去,默認的如下:
<?xml version="1.0" encoding="UTF-8"?> <rebel-remote xmlns="http://www.zeroturnaround.com/rebel/remote"> <id>xx.xx.xx.api</id> </rebel-remote>
添加之后的代碼如下:
<?xml version="1.0" encoding="UTF-8"?> <rebel-remote xmlns="http://www.zeroturnaround.com/rebel/remote"> <id>xx.xxx.xx.api</id> <id>xx.xx.xx.service</id> <id>xx.xx.xx.core</id> </rebel-remote>
以上的
<id>
標簽中指定的是模塊的包名(package)。
2.devtools
spring-boot-devtools 是一個為開發者服務的一個模塊,其中最重要的功能就是自動應用代碼更改到最新的App上面去。相關Blog: 點擊打開鏈接
原理是在發現代碼有更改之后,重新啟動應用,但是比速度比手動停止后再啟動還要更快,更快指的不是節省出來的手工操作的時間。
其深層原理是使用了兩個ClassLoader,一個Classloader加載那些不會改變的類(第三方Jar包),另一個ClassLoader加載會更改的類,稱為 restart ClassLoader,這樣在有代碼更改的時候,原來的restart ClassLoader 被丟棄,重新創建一個restart ClassLoader,由於需要加載的類相比較少,所以實現了較快的重啟時間(5秒以內)。
那如何使用呢,大概兩個步驟即可:
第一就是添加相應的依賴:
<!--devtools可以實現頁面熱部署(即頁面修改后會立即生效,這個可以直接在application.properties文件中配置spring.thymeleaf.cache=false來實現),
實現類文件熱部署(類文件修改后不會立即生效),實現對屬性文件的熱部署。
即devtools會監聽classpath下的文件變動,並且會立即重啟應用(發生在保存時機),注意:因為其采用的虛擬機機制,該項重啟是很快的 -->
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> <scope>true</scope> </dependency>
第二加點:僅僅加入devtools在我們的eclipse中還不起作用,這時候還需要添加的spring-boot-maven-plugin:
<build> <finalName>www.fitness.manager.com</finalName> <plugins> <!--用於將應用打成可直接運行的jar(該jar就是用於生產環境中的jar) 值得注意的是,如果沒有引用spring-boot-starter-parent做parent,且采用了上述的第二種方式,這里也要做出相應的改動 --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <!--fork: 如果沒有該項配置,devtools不會起作用,即應用不會restart --> <fork>true</fork> </configuration> </plugin> </plugins> </build>
運行App.Java ---- Run Application--- Java Application即可進行測試。
3.JRebel和devtools的區別
前輩和后輩的比較其實沒什么可比性,如果不是JRebel「收費」了,絕對是所有程序員的首選。但還是要說說他們之間的區別,如下:
JRebel
加載的速度優於devtools
- JRebel不僅僅局限於Spring Boot項目,可以用在任何的Java項目中。
devtools
方式的熱部署在功能上有限制,方法內的修改可以實現熱部署,但新增的方法或者修改方法參數之后熱部署是不生效的。
參考:
https://www.cnblogs.com/wchukai/p/5651172.html
https://blog.csdn.net/lantian0802/article/details/8870286
https://littleterry.blog.csdn.net/article/details/83146803
https://www.hollischuang.com/archives/592
https://www.cnblogs.com/gotodsp/p/9637674.html
https://www.ibm.com/developerworks/cn/java/j-lo-hotdeploy/
https://blog.csdn.net/weixin_34198453/article/details/92201473
https://www.cnblogs.com/Chenjiabing/p/13924849.html