加速Java應(yīng)用開(kāi)發(fā)2—加速項(xiàng)目調(diào)試啟動(dòng)速度
上一篇Spring/Hibernate提升速度的文章《加速spring/hibernate應(yīng)用調(diào)試時(shí)啟動(dòng)速度》,主要是通過(guò)一些技巧來(lái)提升啟動(dòng)速度,還是做不到如類的熱部署/熱替換。因此再寫一篇關(guān)于熱部署/熱替換的文章。之前也有很多人介紹過(guò)這些知識(shí),不過(guò)比較分散,我寫此篇的目的是聚合它們。本文以HotSpot虛擬機(jī)為例。
首先讓我們來(lái)看兩個(gè)概念:熱部署、熱替換
熱部署
即在容器運(yùn)行過(guò)程中,重新加載類或重新加載整個(gè)項(xiàng)目。常見(jiàn)的解決方案就是使用自定義ClassLoader;
部分加載的示例:如JSP、Play框架;
重新加載整個(gè)項(xiàng)目的示例:如Tomcat、Jetty;默認(rèn)都是定期檢測(cè)class文件是否有修改,如果有,先卸載當(dāng)前容器,再重新加載整個(gè)項(xiàng)目(reload)。
這種情況缺點(diǎn)很明顯:只能重新裝載整個(gè)類/整個(gè)項(xiàng)目,不能只替換類中的部分。
JSP熱部署的介紹:
http://www.linuxidc.com/Linux/2013-05/83816.htm
Tomcat熱部署的介紹:
http://www.94it.cn/a/jingxuanboke/2013/0501/4578.html
Play!框架:
http://mingj.iteye.com/blog/307238
熱替換
熱替換相對(duì)于之前的熱部署的優(yōu)勢(shì)就是可以替換如方法體、增刪方法/字段等類內(nèi)部局部替換,而不是整個(gè)類。常見(jiàn)的實(shí)現(xiàn)方式:HotSpot虛擬機(jī)的HotSwap、HotSwap補(bǔ)丁、
HotSwap
只能熱替換方法體。只要在eclipse或idea等開(kāi)發(fā)工具中開(kāi)啟debug模式即可使用。
HotSwap補(bǔ)丁 DCEVM
該補(bǔ)丁增強(qiáng)了HotSwap,可以增加、刪除類字段、方法和改變類的父類。也必須在debug模式下調(diào)試。具體使用可以參考如下文章,在此就不重復(fù)了
我測(cè)試時(shí)使用的是jdk1.6.0_25,沒(méi)有問(wèn)題,不支持jdk1.6.0_26,且我測(cè)試jdk7_13和jdk7_21沒(méi)成功。官網(wǎng)介紹說(shuō)其是基于JDK7-b102編譯的。估計(jì)我下的這兩個(gè)版本不對(duì)。
java agent + Instrumentation
1、Spring-Loaded
SpringSource官網(wǎng)發(fā)布的,用在Grails 2中,允許:添加/修改/刪除 方法/字段/構(gòu)造器。類型/方法/字段/構(gòu)造器上的注解也允許修改,且也可以新增/刪除/修改enum類型的值。
使用方式:
- -javaagent:<pathTo>/springloaded-{VERSION}.jar -noverify
如在執(zhí)行tomcat/jetty時(shí)的VM參數(shù)中指定如上配置即可。無(wú)需在debug模式下執(zhí)行。如果使用的是如idea可以按Ctrl+Shift+F9編譯當(dāng)前類/Ctrl+F9編譯所有更改的類。
2、Fakereplace
類似于Spring-Loaded,具體可參考其官網(wǎng):
https://github.com/fakereplace/fakereplace
https://github.com/fakereplace/fakereplace/wiki/How-It-Works
它的好處是,支持一些框架:
- Seam 2
- Weld (基本集成)
- JSF
- Metawidget
- Hibernate (實(shí)際是如果實(shí)體修改了,重啟整個(gè)EMF,也不是很快)
- Resteasy
具體使用也是在VM參數(shù)中指定:
- -javaagent:/path/to/fakereplace.jar
可以到如下地址下載jar包,或自己編譯
http://repo.grails.org/grails/plugins-releases/org/fakereplace/fakereplace-dist/1.0.0.Alpha2/
其提供了一些配置,如:
- -javaagent:/path/to/fakereplace.jar=packages=com.mycompany.myclasses,log=trace
- packages 需要熱替換的包
- log 可選,支持trace,debug,info,error
- index-file fakereplace索引為的路徑。Fakereplace在第一次運(yùn)行后存儲(chǔ)這個(gè)文件以加速啟動(dòng)
- dump-dir 當(dāng)熱替換時(shí),Dump類到這個(gè)目錄,僅當(dāng)開(kāi)發(fā)Fakereplace時(shí)有用
- port Fakereplace監(jiān)聽(tīng)的端口
它倆的實(shí)現(xiàn)很類似,Spring-Loaded使用了CGLIB來(lái)實(shí)現(xiàn)代理,F(xiàn)akeReplace使用了Javassist來(lái)實(shí)現(xiàn)的。
還有如Agent Smith,不過(guò)N久沒(méi)維護(hù)了。 其實(shí)Play框架也是使用了Instrumentation,但是它是整個(gè)替換,所以沒(méi)有歸類過(guò)來(lái)。
以上的都有個(gè)缺點(diǎn):如我在寫spring項(xiàng)目時(shí),無(wú)法動(dòng)態(tài)加載如@RequestMapping配置,或動(dòng)態(tài)加載配置文件。這些在強(qiáng)大的JRebel中都是支持的。
JRebel
JRebel是我目前簡(jiǎn)單的最強(qiáng)大的熱替換/熱部署工具。但缺點(diǎn)是收費(fèi)的,而且不便宜。之前介紹的都是免費(fèi)的。首先大家可以看一下它支持的特性與JVM Hot Swap對(duì)比列表:
#p#
JavaEE支持 | JRebel | JVM Hot Swap |
裝載時(shí)間 | <1s | <1s |
內(nèi)存泄漏 | 無(wú) | 無(wú) |
改變類結(jié)構(gòu) | ||
改變方法體 | |
|
添加/刪除方法 | ||
添加/刪除構(gòu)造器 | ||
添加/刪除字段 | ||
添加/刪除類 | ||
添加/刪除注解 | ||
改變靜態(tài)字段值 | ||
添加/刪除enum值 | ||
改變接口 | ||
替換父類 | ||
添加/刪除實(shí)現(xiàn)的接口 | ||
即時(shí)構(gòu)建 | ||
跳過(guò)WAR目錄的構(gòu)建 | ||
跳過(guò).WAR/.EAR類更新構(gòu)建 | ||
跳過(guò).WAR/.EAR資源更新構(gòu)建 | ||
映射多個(gè)source目錄到一個(gè).WAR/.EAR目標(biāo)目錄 | ||
使用include/exclude模式映射類和資源 | ||
使用Ant風(fēng)格模式映射多個(gè)sourcde目錄 | ||
使用系統(tǒng)屬性使映射機(jī)器無(wú)關(guān) | ||
Maven插件 | ||
遠(yuǎn)程/云 | ||
通過(guò)HTTP進(jìn)行應(yīng)用更新 |
JavaEE支持
JSP EL changes |
JSP Scriptlet changes |
EJB 1.x session bean interface changes |
EJB 2.x session bean interface changes |
EJB 3.x session bean interface changes |
EJB 3.x: adding new EJB |
EJB 3.x: adding new EJB reference |
JSF changes (Mojarra) |
Bean Validation support (Hibernate Validator) |
JAXB annotation changes |
JAX-RS changes (RESTEasy, Jersey, CXF) |
JAX-WS support (Metro, CXF) |
JPA changes (Hibernate, EclipseLink, TopLink, OpenJPA) |
CDI changes (Weld) |
框架支持 |
Spring Framework 2.x or later |
Hibernate |
JBoss Seam 2.x or later |
Google Guice |
Struts 1.x, 2.x |
Wicket |
Stripes 1.5 or later |
查看完整的框架支持列表 |
代理支持 |
CgLib |
Javassist |
OSGi支持 |
Apache Felix |
Eclipse Equinox |
從如上列表看到其不是一般的強(qiáng)大。
接下來(lái)看看如何使用(以IDEA為例):
#p#
1、首先點(diǎn)擊如下圖所示的運(yùn)行,然后點(diǎn)擊Edit Configuration...
2、在彈出的窗口中輸入如下圖所示的jrebel.jar位置
類似于之前的javaagent配置。
3、啟動(dòng)后,當(dāng)修改類后,請(qǐng)按Ctrl+F9重新編譯。然后再執(zhí)行程序即可看到變化。
4、Eclipse內(nèi)嵌tomcat的配置:
使用起來(lái)是非常簡(jiǎn)單的。注意:如果使用web容器如tomcat、jetty,請(qǐng)禁用其reload,如jetty,可以配置
<scanIntervalSeconds>0</scanIntervalSeconds> 或者 <reload>manual</reload>。
JRebel也提供如Eclipse、IDEA、Maven插件,其實(shí)沒(méi)必要上插件,直接配javaagent就很簡(jiǎn)單。還可以配置
如果有朋友想開(kāi)啟/禁用某些框架/JavaEE的支持,可以通過(guò)添加VM參數(shù),如下所示開(kāi)啟/關(guān)閉:
-Drebel.spring_plugin=true
-Drebel.aspectj_plugin=true
-Drebel.struts2_plugin=true
-Drebel.hibernate_plugin=true
-Drebel.jackson_plugin=true
-Drebel.log4j-plugin=true
還可以通過(guò)配置一個(gè)rebel.xml來(lái)進(jìn)行選擇性構(gòu)建:
http://zeroturnaround.com/software/jrebel/how-to-configure-rebel-xml/
更多配置請(qǐng)參考其官方的JRebel手冊(cè)。
到此就介紹完了我見(jiàn)到的所有熱部署/熱替換實(shí)現(xiàn)方式,大家還有什么好的方式歡迎補(bǔ)充。