1. 程式人生 > >hotswapagent——熱更新程式碼而無需重啟生產環境

hotswapagent——熱更新程式碼而無需重啟生產環境

coding階段,我們習慣於以debug模式執行程式,享受即時更新程式碼而無需重啟服務的高效開發速度。

遺憾的是,無論是ide的debug模式,還是jdk1.4+的instrument機制,都只能做到修改方法體的熱更新。如果你新增或刪除了某些method或field,馬上就會報熱更失敗的提示。

那麼有沒有什麼高大上的工具能夠支援動態修改類結構呢?答案是肯定的。

JRebel——一個jvm外掛,允許開發者隨時修改程式碼、資源而無需重啟服務。在eclipse商店裡就有一個JRebel的外掛。但JRebel是收費軟體,當然,網上也有破解版。

本文將介紹另外一個免費工具——HotswapAgent+DCEVM組合。

The Dynamic Code Evolution Virtual Machine (DCEVM) 是一個jvm級別的補丁,安裝過程會替換jvm自身的檔案。DCEVM的官網最後一次更新是為了相容jdk1.7,對於最新的jdk1.8則無能為力。

HotswapAgent是一個git開源專案,github地址-->HotswapAgent。專案上最新的DCEVM是支援jdk1.8的。

在官網上下載DCEVM-light.jarhotswap-agent.jar 兩個jar包並安裝DCEVM後,就可以開始我們的探索之旅了。

1.編寫實體類

public class Person  {

	public String toString(){
		return "from person,hello";
	}
}
2.編寫測試入口
public class Entry {

     public static void main(String[] args) throws Exception {
		final Person p = new Person();  //記憶體只有一個例項物件
		new Thread(
				new Runnable(){
					@Override
					public void run() {
						while(true){
							try{
								Thread.sleep(1000);
								System.err.println(p);
							}catch(Exception e){

							}
						}
					}
				}
				).start();

	}
}
3.以Eclipse開發工具為例,配置vm引數,然後以debug模式啟動程式

vm引數(-XXaltjvm=dcevm -javaagent:E:\workspace\jar_libs\hotswap-agent.jar),如下所示

啟動後,看到終端輸出如下提示,就說明環境配置成功


4.程式啟動後,修改實體類並儲存程式碼(ide要開啟自動編譯)

public class Person  {

	private final int age = 3; 	  //動態加欄位,這裡要加final修飾
	public String toString(){
		testAddMethod();
		return "from person,hello,age="+age; //動態修改方法體
	}
	
	public void testAddMethod(){  //動態加方法
		System.err.println("hot update ,add method succ.......");
	}
	
}
5.執行結果如下,可以看到,熱更成功了!!!!!!

6.雖然以debug模式熱更新成功,但在生產環境一般都不是debug模式,那麼在生產環境應如果部署呢?

其實也是相當簡單,只需要稍微修改一下vm引數,命令列執行引數為

java -XXaltjvm=dcevm -javaagent:E:\workspace\jar_libs\hotswap-agent.jar=autoHotswap=true Entry

在執行過程中,使用已編譯後的新class檔案去替換舊class檔案,即可看到熱更效果。

7.若專案是以可執行jar包的方式部署,只需在編譯後的class根目錄裡面新建一個檔案hotswap-agent.properties,然後設定extraClasspath為指定的更新路徑,同時設定autoHotswap=true,將需要更新的檔案放到extraClasspath目錄下,即可更新指定檔案。

8.最後說一下使用hotswapagent的一些限制。

官網上說Hotswap除了無法修改類的層次關係(例如改變父類或移除介面),其他熱更操作均可實現。但從我個人的測試方法來看,官網的說法還是有些誇大成分。如果真的是要在生產環境上使用此方法進行熱部署,強烈推薦一定要先在本地環境試驗一番,確保有效才能放到生產環境。

自己隨便測試了一番,發現以下操作無法熱更成功,也有可能是我使用方法有誤(^_^)

1.增加例項屬性並賦值,列印後發現賦值無效,輸出的是型別的預設值,使用final常量則能生效。應該是由於例項初始化過程已經結束,不再走例項的屬性初始化邏輯。

2.修改匿名類方法體裡用到的例項引用,程式直接宕機停止執行抓狂發火,示例程式碼如下


報錯異常為

<span style="font-family:SimHei;">HOTSWAP AGENT: 15:19:8.283 RELOAD (org.hotswap.agent.config.PluginManager) - Reloading classes [Entry, Entry$1] (autoHotswap)
HOTSWAP AGENT: 15:19:8.316 RELOAD (org.hotswap.agent.plugin.jvm.AnonymousClassPatchPlugin) - Class '/Entry' has been enhanced with anonymous classes for hotswap.
Exception in thread "Thread-3" java.lang.NoSuchFieldError: val$p
	at .Entry$1.run(Entry.java:18)
	at java.lang.Thread.run(Thread.java:745)</span>

使用反編譯工具檢視匿名類的程式碼發現,報錯的引用"val$p"指向的是原匿名類的引用,報錯原因暫不詳害羞

估計是因為匿名類的緣故。匿名類,內部類一直是熱更的軟肋。我所接觸的熱更方式都要求程式碼儘量不要出現內部類,匿名類。



總結:

hotswapagent給我們的開發過程帶來了無與倫比的快感,想象一下,在開發執行過程就可以隨意增減方法,隨時隨地進行程式碼重構,這該有多爽啊。但由於該工具仍處於alpha版本,穩定性無法考量,我曾發郵件諮詢過作者,作者也建議不要輕易放到生產環境!!Anyway,在生產環境能夠修改方法體,已足矣。。。