讀古今文學網 > 編寫高質量代碼:改善Java程序的151個建議 > 建議16:易變業務使用腳本語言編寫 >

建議16:易變業務使用腳本語言編寫

Java世界一直在遭受著異種語言的入侵,比如PHP、Ruby、Groovy、JavaScript等,這些「入侵者」都有一個共同特徵:全是同一類語言——腳本語言,它們都是在運行期解釋執行的。為什麼Java這種強編譯型語言會需要這些腳本語言呢?那是因為腳本語言的三大特徵,如下所示:

靈活。腳本語言一般都是動態類型,可以不用聲明變量類型而直接使用,也可以在運行期改變類型。

便捷。腳本語言是一種解釋型語言,不需要編譯成二進制代碼,也不需要像Java一樣生成字節碼。它的執行是依靠解釋器解釋的,因此在運行期變更代碼非常容易,而且不用停止應用。

簡單。只能說部分腳本語言簡單,比如Groovy, Java程序員若轉到Groovy程序語言上,只需要兩個小時,看完語法說明,看完Demo即可使用了,沒有太多的技術門檻。

腳本語言的這些特性是Java所缺少的,引入腳本語言可以使Java更強大,於是Java 6開始正式支持腳本語言。但是因為腳本語言比較多,Java的開發者也很難確定該支持哪種語言,於是JCP(Java Community Process)很聰明地提出了JSR223規範,只要符合該規範的語言都可以在Java平台上運行(它對JavaScript是默認支持的),諸位讀者有興趣的話可以自己寫個腳本語言,然後再實現ScriptEngine,即可在Java平台上運行。

我們來分析一個案例,展現一下腳本語言是如何實現「擁抱變化」的。咱們編寫一套模型計算公式,預測下一個工作日的股票走勢(如果真有,那巴菲特就羞愧死了),即把國家政策、匯率、利率、地域係數等參數輸入到公式中,然後計算出明天這支股票是漲還是跌,該公式是依靠歷史數據推斷而來的,會根據市場環境逐漸優化調整,也就是逐漸趨向「真理」的過程,在此過程中,公式經常需要修改(這裡的修改不僅僅是參數修改,還涉及公式的算法修改),如果把這個公式寫到一個類中(或者幾個類中),就需要經常發佈重啟等操作(比如業務中斷,需要冒煙測試(Smoke Testing)等),使用腳本語言則可以很好地簡化這一過程,我們寫一個簡單公式來模擬一下,代碼如下:


function formula(var1,var2){

return var1+var2*factor;

}


這就是一個簡單的腳本語言函數,可能你會很疑惑:factor(因子)這個變量是從哪兒來的?它是從上下文來的,類似於一個運行的環境變量。該JavaScript保存在C:/model.js中。下一步Java需要調用JavaScript公式,代碼如下:


public static void main(Stringargs)throws Exception{

//獲得一個JavaScript的執行引擎

ScriptEngine engine=new ScriptEngineManager().getEngineByName(\"javascript\");

//建立上下文變量

Bindings bind=engine.createBindings();

bind.put(\"factor\",1);

//綁定上下文,作用域是當前引擎範圍

engine.setBindings(bind, ScriptContext.ENGINE_SCOPE);

Scanner input=new Scanner(System.in);

while(input.hasNextInt()){

int first=input.nextInt();

int sec=input.nextInt();

System.out.println(\"輸入參數是:\"+first+\",\"+sec);

//執行js代碼

engine.eval(new FileReader(\"c:/model.js\"));

//是否可調用方法

if(engine instanceof Invocable){

Invocable in=(Invocable)engine;

//執行js中的函數

Double result=(Double)in.invokeFunction(\"formula\",frst, sec);

System.out.println(\"運算結果:\"+result.intValue());

}

}

}


上段代碼使用Scanner類接受鍵盤輸入的兩個數字,然後調用JavaScript腳本的formula函數計算其結果,注意,除非輸入了一個非int數字,否則當前JVM會一直運行,這也是模擬生產系統的在線變更狀況。運行結果如下:


輸入參數是:1,2

運算結果:3


此時,保持JVM的運行狀態,我們修改一下formula函數,代碼如下:


function formula(var1,var2){

return var1+var2-factor;

}


其中,乘號變成了減號,計算公式發生了重大改變。回到JVM中繼續輸入,運行結果如下。


輸入參數是:1,2

運算結果:2


修改Java代碼,JVM沒有重啟,輸入參數也沒有任何改變,僅僅改變腳本函數即可產生不同的結果。這就是腳本語言對系統設計最有利的地方:可以隨時發佈而不用重新部署;這也是我們Javaer最喜愛它的地方——即使進行變更,也能提供不間斷的業務服務。

Java 6不僅僅提供了代碼級的腳本內置,還提供了一個jrunscript命令工具,它可以在批處理中發揮最大效能,而且不需要通過JVM解釋腳本語言,可以直接通過該工具運行腳本。想想看,這是多麼大的誘惑力呀!而且這個工具是可以跨操作系統的,腳本移植就更容易了。但是有一點需要注意:該工具是實驗性的,在以後的JDK中會不會繼續提供就很難說了。