對于Java游戲服務器來說,通常通過腳本運行jar執行。在開發測試環境下,需要經常打包、重新部署的需求,而往往重啟服務器通常需要花費一定時間。而有了Spring-Loaded這個利器,直接替換運行的補丁jar,即可達到熱更新功能.
2.說明
目前官網上的release版本:springloaded-1.2.3.RELEASE.jar,并不支持reload jar這個功能,這個功能在1.2.4才開放。不過你可以git clone下源代碼,用gradle build最新的jar:springloaded-1.2.4.BUILD-SNAPSHOT.jar。不過這個版本可能些許問題,即對我們的"windoze"支持不太友好,這個問題已經和其作者聯系過了,最新github上的代碼應該修復了。我是本地自己修改了一下(具體怎么修改的,可以參見我的博客中和作者的幾封郵件),然后build的。當然如果你是mac或者是linux運行,則會完美運行。
3.參數
-Dspringloaded=watchJars=foo.jar:bar.jar
即watchJars選項,監聽的多個jar之前用:分離
4.例子
有兩個jar,一個spring-load-main.jar,一個spring-load-extra.jar,前者依賴后者,后者業務可能會經常變化,有熱更新的需求。這里模擬一下線上環境,用腳本啟動進程(windows),然后修改邏輯,重新打包,替換jar,看是否可以達到reload的目的
1.啟動腳本:spring-loaded-example_launch.bat
@echo off
cd /d %~dp0
java -noverify -javaagent:springloaded-1.2.4.BUILD-SNAPSHOT.jar -cp spring-load-main.jar;spring-load-extra.jar -Dspringloaded=verbose;explain;watchJars=spring-load-extra.jar com.mavsplus.example.springloaded.SpringLoadedExample2
說明:springloaded-1.2.4.BUILD-SNAPSHOT.jar/spring-load-main.jar/spring-load-extra.jar 這三個jar是在同一個目錄."-javaagent"這個必須,指定agent為spring-loaded.通過-Dspringloaded=watchJars指定了監聽的jar為spring-load-extra.jarcd /d %~dp0
java -noverify -javaagent:springloaded-1.2.4.BUILD-SNAPSHOT.jar -cp spring-load-main.jar;spring-load-extra.jar -Dspringloaded=verbose;explain;watchJars=spring-load-extra.jar com.mavsplus.example.springloaded.SpringLoadedExample2
,main類為SpringLoadedExample2
2.spring-loaded-main.jar只有一個類SpringLoadedExample2,spring-loadex-extra.jar也只有一個類Reload
package com.mavsplus.example.springloaded;
import java.util.concurrent.TimeUnit;
/**
* <a href="https://github.com/spring-projects/spring-loaded"></a>
*
* <pre>
* Spring Loaded allows you to add/modify/delete methods/fields/constructors.
* The annotations on types/methods/fields/constructors
* can also be modified and it is possible to add/remove/change values in enum types.
* </pre>
*
* @author landon
* @since 1.8.0_25
*/
public class SpringLoadedExample2 {
public static void main(String[] args) throws Exception {
Reload reload = new Reload();
while (true) {
reload.load();
TimeUnit.SECONDS.sleep(3);
}
}
} import java.util.concurrent.TimeUnit;
/**
* <a href="https://github.com/spring-projects/spring-loaded"></a>
*
* <pre>
* Spring Loaded allows you to add/modify/delete methods/fields/constructors.
* The annotations on types/methods/fields/constructors
* can also be modified and it is possible to add/remove/change values in enum types.
* </pre>
*
* @author landon
* @since 1.8.0_25
*/
public class SpringLoadedExample2 {
public static void main(String[] args) throws Exception {
Reload reload = new Reload();
while (true) {
reload.load();
TimeUnit.SECONDS.sleep(3);
}
}
package com.mavsplus.example.springloaded;
/**
* 可reload的實現類
*
* @author landon
* @since 1.8.0_25
*/
public class Reload {
public void load() {
System.out.println("load");
}
}
/**
* 可reload的實現類
*
* @author landon
* @since 1.8.0_25
*/
public class Reload {
public void load() {
System.out.println("load");
}
}
3.運行啟動腳本:spring-loaded-example_launch.bat
E:\github\mavsplus-all\mavsplus-examples\src\main\resources>spring-loaded-exampl
e_launch.bat
SL: [verbose mode on] Full configuration is:verbose;explain;watchJars=spring-loa
d-extra.jar
SL: [explain mode on] Reporting on the decision making process within SpringLoad
ed
七月 01, 2015 8:25:16 下午 org.springsource.loaded.agent.SpringLoadedPreProcesso
r logPreProcess


r logPreProcess
信息: SpringLoaded preprocessing: classname=java/util/concurrent/TimeUnit$7 clas
sloader=null typeRegistry=null
load
load
load
load
e_launch.bat
SL: [verbose mode on] Full configuration is:verbose;explain;watchJars=spring-loa
d-extra.jar
SL: [explain mode on] Reporting on the decision making process within SpringLoad
ed
七月 01, 2015 8:25:16 下午 org.springsource.loaded.agent.SpringLoadedPreProcesso
r logPreProcess


r logPreProcess
信息: SpringLoaded preprocessing: classname=java/util/concurrent/TimeUnit$7 clas
sloader=null typeRegistry=null
load
load
load
load
4.修改Reload.java,輸出reload,然后重新打一個包并覆蓋掉spring-load-extra.jar,這時候看到命令行輸出:
load
load
七月 01, 2015 8:28:51 下午 org.springsource.loaded.agent.Watcher run
信息: Observed last modification time change for e:\github\mavsplus-all\mavsplus
-examples\src\main\resources\spring-load-extra.jar (lastScanTime=1435753730694)
七月 01, 2015 8:28:51 下午 org.springsource.loaded.agent.Watcher determineChange
sSince
信息: Firing file changed event e:\github\mavsplus-all\mavsplus-examples\src\mai
n\resources\spring-load-extra.jar
七月 01, 2015 8:28:51 下午 org.springsource.loaded.agent.SpringLoadedPreProcesso
r logPreProcess
信息: SpringLoaded preprocessing: classname=java/util/HashMap$KeyIterator classl
oader=null typeRegistry=null


信息: SpringLoaded preprocessing: classname=java/io/ObjectStreamClass$Caches cla
ssloader=null typeRegistry=null
reload
reload
reload
reload
看上面紅色部分,我們可以清楚的看到spring-loaded檢測到了jar的時間戳的改變,并將其重新加載了,從輸出我們可以看到load
七月 01, 2015 8:28:51 下午 org.springsource.loaded.agent.Watcher run
信息: Observed last modification time change for e:\github\mavsplus-all\mavsplus
-examples\src\main\resources\spring-load-extra.jar (lastScanTime=1435753730694)
七月 01, 2015 8:28:51 下午 org.springsource.loaded.agent.Watcher determineChange
sSince
信息: Firing file changed event e:\github\mavsplus-all\mavsplus-examples\src\mai
n\resources\spring-load-extra.jar
七月 01, 2015 8:28:51 下午 org.springsource.loaded.agent.SpringLoadedPreProcesso
r logPreProcess
信息: SpringLoaded preprocessing: classname=java/util/HashMap$KeyIterator classl
oader=null typeRegistry=null


信息: SpringLoaded preprocessing: classname=java/io/ObjectStreamClass$Caches cla
ssloader=null typeRegistry=null
reload
reload
reload
reload
5.總結:
通過該例子我們可以清楚的看到,用spring-loaded簡直太幸福了。。直接替換jar包。。直接更新。。完美
相對比JRebel還需要指定一個monitor jar class jar。。簡單多了。。具體對比可以參考我的上一篇隨筆: http://www.aygfsteel.com/landon/archive/2015/06/26/425909.html
后續:會深入源代碼以及更深層次的例子而不僅僅是直接替換方法body形式的熱加載。。進行深入剖析