開始囉嗦的介紹
現在有很多腳本語言,大家平時使用的比較多的包括Perl,Python,Ruby,Javascript,Groovy,在這裏我要介紹的是另外一個對象腳本語言BeanShell(http://www.beanshell.org)。
BeanShell的解釋器是用Java寫的,開源並且免費的,引用open-open上面的話來說明它的運作方式“它將腳本化對象看作簡單閉包方法(simple method closure)來支持,就如同在Perl和JavaScript中的一樣。它具有以下的一些特點:使用Java反射API以提供Java語句和表達式的實時解釋執行;可以透明地訪問任何Java對象和API;可以在命令行模式、控制檯模式、小程序模式和遠程線程服務器模式等四種模式下面運行;與在應用程序中一樣,可以在小程序中(Applet)正常運行(無需編譯器或者類裝載器);非常精簡的解釋器jar文件大小爲175k ”。每一種腳本語言都有它的使用場景,而正是因爲其在某些場景的使用而使語言本身得到了發揚光大,比如Ruby正是因爲Ruby On Rails這個Web框架的流行而得到開發者的關注,Groovy也一樣;BeanShell可不能再有Web框架,Java世界的Web框架已經太多了,夠讓人頭痛的了;
BeanShell是Java語法,所以對Java開發者來說,很快就可以上手,BeanShell不能像Ruby,Perl,Ruby一樣可以佔據一個系統的主體,而只能在一些小的地方發揮“螺絲釘”的作用。
使用BeanShell可以處理現實中不規則的業務,舉個很典型的例子,我們知道,一個保險公司有很多險種,每個險種的投入和收益的算法是很複雜的,無法用規則的關係數據庫模型來描述,所以很多保險系統在處理險種的算法都是硬編碼,如果要在系統中新加一個險種,是非常麻煩的,重新修改代碼,重新發布,這對開發\維護人員和客戶都是很痛苦的,有了BeanShell,我們可以從這種痛苦中解脫出來,對每個險種使用不同的腳本,新加的險種我們新配一個腳本,這樣既可以滿足業務多變的要求,又可以減少工作量,節約成本。BeanShell的一個特點是動態執行Java代碼,腳本文件改變不會影響當前腳本的調用,新腳本將在腳本的下一次調用生效,這不同於配置文件,配置文件改變一般都需要應用重啓。
配置BeanShell
1、將 bsh-xx.jar 文件放在 $JAVA_HOME/jre/lib/ext 的文件夾下作爲一個擴展來安裝它。(OSX 用戶:將 bsh.jar 文件放置在 /Library/Java/Extensions 或者 ~/Library/Java/Extensions 供個別用戶使用)
2、add BeanShell to your classpath like this:
unix:export CLASSPATH=$CLASSPATH:bsh-xx.jar
windows:set classpath %classpath%;bsh-xx.jar
運行BeanShell在GUI或命令行模式
1、java bsh.Console //運行圖形化桌面窗口(以jdk1.6.0_23爲例,需要將bsh-bsf-xx.jar放置到E:\Program Files\Java\jdk1.6.0_23\jre\lib\ext下否則圖形化界面將無法開啓)
2、java bsh.Interpreter //在命令行上僅作爲文本來運行
3、java bsh.Interpreter filename [ args ] //運行腳本文件
4、遠程調用:
import bsh.Interpreter;
Interpreter i = new Interpreter();
i.eval("server(1234)"); // 指定連接端口:1234
遠程客戶端訪問
瀏覽器:http://<yourserver>:<port>/remote/jconsole.html
telnet:telnet <myhost> <port+1>
常用的BeanShell命令
內建在BeanShell中的一個方便的命令print(),來顯示變量的值。print()跟ava的System.out.println()非常的相像,除非它能保證輸出總是命令行。print()也可以顯示一些對象的類型(如數組),但比Java的更詳細。另一個相關的命令是show(),用來開啓與關閉顯示你輸入的每一行的結果。
常用命令:
source(), run() - 將一個bsh腳本讀到解釋器或運行在另一個解釋器
frame() - 顯示一個Frame或JFrame的GUI組件
load(), save() - 載入和保存一個序列化的對象到一個文件
cd(), cat(), dir(), pwd(), etc. - 類unix的shell命令
exec() - 運行一個本地的程序
javap() - 打印一個對象的方法和字段,類似於Java的javap命令
setAccessibility() - 開啓無限制的存取private 和protected的組件
要獲得更多的信息請查看BeanShell命令的詳細清單
在你的應用程序中通過創建 BeanShell 的解釋器以及使用 eval() 和 source() 命令來爲文本賦值或者運行腳本。你可以通過 set() 方法將變量的引用傳遞給你想在腳本中使用的對象而後通過 get() 方法取得結果。
語句和表達式
BeaShell理解標準的Java語句,表達式和方法聲明。語句和表達式是Java方法中最基本的東西,例如:變量的聲明和賦值,方法調用,循環,條件語句。你可以像在Java中一樣用他們,當然,在BeanShell中,你有更多的機會使用"loosely typed(松類型)"變量(松類型的作用域是被定義爲全局的)。也就是說,你可以省略掉變量類型,包括元類型和對象類型。如果你濫用了變量類型,那麼BeanShell會拋出一個異常。
foo = "Foo";
four = (2 + 2) * 2 / 2;
print( foo + " = " + four );
for (i=0; i<5; i++)
print(i);
button = new JButton( "My Button" );
frame = new JFrame( "My Frame" );
frame.getContentPane().add( button, "Center" );
frame.pack();
frame.setVisible(true);
腳本方法
可以聲明和使用方法就像在Java的class中一樣。
int addTwoNumbers( int a, int b ) {
return a + b;
}
sum = addTwoNumbers( 5, 7 ); // 返回:12
// Bsh方法也允許動態的(松類型的)參數和返回類型
add( a, b ) {
return a + b;
}
foo = add(1, 2); // 返回:3
foo = add("Oh", " baby"); // 返回:"Oh baby"
腳本對象
在BeanShell中,就像在JavaScript和Perl中,方法“閉包”允許你創建腳本對象。你可以讓一個方法返回特殊值this從而讓這個方法調用的返回值成爲一個對象引用。在方法調用過程中,你可以使用這個引用指向任意的變量集。有用的對象當然包括了方法,所以在BeanShell腳本方法中可以在任意水平包含方法。
foo() {
print("foo");
x=5;
bar() {
print("bar");
}
return this;
}
myfoo = foo(); // prints "foo"
print( myfoo.x ); // prints "5"
myfoo.bar(); // prints "bar"
實現接口
BeanShell 最強大的功能之一就是具有編寫 Java 接口腳本的能力。這個功能允許你編寫腳本用作事件處理、監聽以及其他 Java API 的組件。它也可以從你的應用中更簡單得調用腳本化的組件,因爲它們可以被看作任何其他 Java 對象。
獲得腳本的組件來實現一個 Java 接口的一種方法是使用標準的 Java 匿名內部類構建腳本的對象實現的接口類型的語法
buttonHandler = new ActionListener() { // 也可寫成 ActionListener buttonHandler = new ActionListener()
actionPerformed( event ) {
print(event);
}
invoke( name, args ) { print("Method: "+name+" invoked!"); // 如果調用ActionListener的actionAftered()方法,因爲該方法不存在,就會調用invoke()方法來處理
};
button = new JButton();
button.addActionListener( buttonHandler );
frame(button);
invoke(name,args) { print("Command: "+name+" invoked!"); }
noSuchMethod(); // 打印 "Command: noSuchMethod() invoked!"
因爲未定義noSuchMethod方法就由invoke方法來統一處理。java調用BeanShell
實例一:
import bsh.Interpreter;
Interpreter i = new Interpreter(); // 構造 interpreter
i.set("foo", 5); // 設置變量
i.set("date", new Date() );
Date date = (Date)i.get("date"); // 重獲變量
// 表達式求值並得到結果
i.eval("bar = foo*10");
System.out.println( i.get("bar") );
// 從外部腳本文件獲得源碼
i.source("somefile.bsh");
運行:
說明:
類 Interpreter 是 BeanShell 的腳本解釋器。一個Interpreter 實例可以被用來獲得腳本源碼以及給語句或者表達式進行評估。API見 http://www.beanshell.org/javadoc/index.html。
實例二:
寫一個腳本文件 myscript.txt ,內容如下:
a = 2;b = 3;c = a + b;print(c);
運行該腳本
c:\beanshell>java bsh.Interpreter myscript.txt
OK,輸出結果5
寫一個bat文件 bsh.bat放到系統目錄下,如:winnt 文件內容如下:
java bsh.Interpreter %1
就可以使用如下方法運行腳本文件了
c:\beanshell>bsh myscript.txt
實例三:
在 JEdit 中編輯一段 BeanShell 腳本,文件名爲“somefile.bsh”。使用 Interpreter.source(bsh文件) 方法可以調用到 BeanShell 的資源。
使用 BeanShell 工作空間調用“somefile.bsh”的腳本文件。注意調用路徑,當前的實例兩者位於同目錄
運行結果:
實例四:
BeanShell 支持 Java 1.5 中增強的 for 循環來迭代集合和數組類型。