開發、自測、聯調期間代碼可能會被頻繁地修改,一般即便只增長了一行代碼,都須要重啓容器以檢查執行效果。而熱部署技術可以幫助開發人員減小從新部署的等待時間。本文的目的爲調研熱部署的技術現狀及其對開發效率的幫助,並簡單梳理其技術實現的難點。html
JVM熱部署目前有多種技術實現:官方、開源、商業。其中商業的JRebel功能強大,涵蓋了平常開發中大部分熱更新場景。以團隊中一個基於Tomcat + Spring
的業務後臺爲例,修改代碼後,本地冷啓動耗時4.5min,本地熱部署的時間則小於1s,極大改善了開發效率。java
當前JVM和JVMTI(JVM Tool Interface
)規範中經過相應的agent機制支持的retransformClass
/redefineClass
操做能夠在加載前和加載後動態修改類的內容,從Java 5開始,這一功能還經過Instrumentation
API直接提供給Java應用使用,可是其適用範圍是受限的:只能修改已有方法的方法體。git
如下摘自JVM(TM) Tool Interface 1.2.3
The redefinition may change method bodies, the constant pool and attributes. The redefinition must not add, remove or rename fields or methods, change the signatures of methods, change modifiers, or change inheritance. These restrictions may be lifted in future versions. See the error return description below for information on error codes returned if an unsupported redefinition is attempted.
IDE的edit-and-continue
功能(Intellij Idea
爲Update Application
)就用到了這種被稱爲HotSwap
的熱部署技術,可是它的限制太大,徹底沒法知足實際開發中的需求。github
這是一個由JKU主導的、基於HotSpot VM的研究項目,誕生於2010年。該項目但願能動態修改類的任意元素,包括成員、方法、註解、繼承等而無需重啓JVM。目前的light版已經支持到Java 8 update 144, build 2
。mvc
基於DCEVM構建的開源項目,其完成度要高於DCEVM,目前已發佈1.0版。對於常見的IDE、IoC/ORM/Log框架、J2EE應用容器的支持比較完善。根據官方文檔,HA支持下列特性。intellij-idea
Java世界中大名鼎鼎的熱部署解決方案,熱部署特性與上面提到的HotSwapAgent相似。固然做爲一款商業軟件,它支持的框架、IDE、J2EE應用容器的種類都更多,總計100+;同時支持Hotspot VM和Oracle VM;文檔和社區支持很是完善,很容易上手。app
最重要的是,沒錢的碼農能夠經過贊助官方的Social Plan
免費激活JRebel!cors
測試環境爲團隊使用的Tomcat + Spring + SpringMvc
。
如下是實際開發中常見的改動類型的測試結果。【Pass】爲支持,【Fail】爲不支持。框架
RequestHandler
方法、方法體、方法簽名、註解<mvc:interceptors> / <mvc:cors> / <aop:aspectj-autoproxy> / <mvc:async-support>
等熱部署的本質,簡單的理解,是在運行中實時增長、替換JVM中的類文件而無需重啓JVM。less
衆所周知,JVM使用ClassLoader加載類文件,內含的雙親委派模型經過指定類文件加載的順序避免因爲類衝突而致使核心類庫加載失敗。單個ClassLoader不能加載全限定名相同的類;不能修改已加載的類的聲明;不能卸載已加載的類,除非移除整個ClassLoader,或者被GC回收。
那麼,修改原有的類(如Test.class
)的任意元素後,熱部署就會面臨不少問題。比方說:
Class
的getName()
、getMethods()
、getField()
等方法時如何獲取到新的類?熱部署問題在底層繞不開ClassLoader,當一個類被更新後,須要被從新載入到ClassLoader中,原先對類變量、實例變量、類方法、實例方法的調用都須要重定向到新類。能夠經過引入一個包含全部符號連接的中間層,當JVM加載用戶的類時進行動態加強,並記錄下涉及的符號連接。
舉幾個實現思路的小例子:
Test
,而新的類名是Test_v1
),繞開ClassLoader的限制。refresh API