我們知道對於一個java文件,如Test.java,首先需要通過javac命令(javac Test.java)進行編譯,生成class文件,再將class文件在jvm上進行加載運行,也就是java命令(java Test)。
但是對於以下應用場景:正在運行的java程序,即class文件已經在jvm中運行加載,如果原來的java程序有所改動,重新生成了class文件,但是又不希望kill掉原先的java程序,該怎么做呢?springloaded提供了一個思路。
我是在eclipse下實驗的,先建立一個SpringloadedTest的工程,在工程下面創建一個Test的java文件,代碼如下:
1 import java.util.concurrent.TimeUnit; 2 public class Test { 3 4 public static void main(String[] args) throws Exception{ 5 Reload reload = new Reload(); 6 7 while (true) { 8 reload.load(); 9 TimeUnit.SECONDS.sleep(3); 10 } 11 } 12 13 public static class Reload { 14 15 public void load() { 16 System.out.println("load!"); 17 } 18 } 19 }
然后,在項目上右鍵,Run As->Run Configurations->Arguments->VM arguments,配置如下的參數,也可以在后面加上-Dspringloaded=verbose用來顯示詳細的重新加載信息(推薦!)
springloaded-1.2.5.RELEASE.jar可以到官網進行下載:https://github.com/spring-projects/spring-loaded
為方便起見,我直接把springloaded-1.2.5.RELEASE.jar放在項目src目錄下,你也可以放在電腦硬盤的任意位置,配置成相應的路徑就行了。
運行結果如下:
一開始是load!程序一直在運行當中,在eclipse中更改代碼,保存,不用停止程序,運行結果變成reload!
看起來非常簡單!
但是還是有一些問題:
1.不利用eclipse,用傳統的javac和java命令,行不行?答案是不行,為此我做了一個實驗,我先創建了兩個文件夾,分別是test和test_replace,test目錄下的java文件中是load,test_replace目錄下的java文件是reload,然后在test目錄下,運行程序java -javaagent:springloaded-1.2.5.RELEASE.jar -noverify Test,輸出的是load,再用test_replace目錄下的class文件替換test中的class文件,結果還是load,並沒有任何改變!
我懷疑是因為eclipse創建的是一個完整的項目,擁有完整的資源,它的class文件都在bin文件夾下,所以替換之后,項目會自動檢測,然后替換jvm中的class。
2.還要說明的是,class文件時間上也有要求!即替換的class文件要比原先的class文件要晚!如果比原先的class文件早,那么即使替換了,運行結果也不會變化!
3.注意觀察代碼,定義了一個靜態類Reload,然后main函數中調用,假設如果沒有這個類,直接在main函數中進行輸出,然后修改輸出的內容,行不行?答案是不行,我試過,輸出的結果沒有變化。為什么?這個問題,我暫時也無法回答,大家有知道的,可以告訴我哈。后來我又試了一下,把輸出的內容用一個單獨的static函數,這種方式也是可行的。就比如,在main函數中調用這個printHello函數,然后再函數中進行改變,也可以重新加載。
所以要想動態替換,還需要按照項目的格式要求,在bin目錄下進行操作,並且需要注意class的時間問題。
以上就是關於springloaded的使用介紹,該方法同樣適用於jar,但是我還沒有試過,后面有機會再試。