beanshell腳本

開始囉嗦的介紹

現在有很多腳本語言,大家平時使用的比較多的包括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);
在上面的例子中我們創建了一個對象,實現了“ActionListener”接口並賦予一個名叫“buttonHandler”的變量。“buttonHandler”對象包含腳本方法“actionPerformed()”,它將被調用來處理該接口上的方法調用。實現接口必要把一個接口中的所有方法都實現,可以選擇性得把你想要調用的方法寫成腳本。如果試圖請求一個沒有被定義的方法那麼調用的代碼將很容易得拋出異常。可以在腳本對象上實現一個特定的方法簽名:invoke(name, args)。調用 invoke() 方法來處理任何未定義的方法調用。
總結:
腳本接口是通過查找腳本方法來實現接口方法的方式來工作的。一個 Java 方法調用一個腳本來實現一個接口導致 BeanShell 通過匹配簽名(名稱和變量類型)來尋找一個對應的腳本方法。BeanShell 然後調用方法,傳遞參數以及傳遞任何返回值。當 BeanShell 作爲其他的代碼運行在同一個 Java 虛擬機上,你可以自由地傳遞“存活着的” Java 對象作爲參數和返回值,在你的腳本中動態地同他們進行運作;是無縫集成。
 
invoke() 元方法
BeanShell 爲帶有大量方法的腳本接口提供一個非常簡單的速記機制。你可以在任何腳本上下文中實現特殊方法 invoke(name, args)。invoke() 方法被調用來處理未被定義的接口的任何方法的調用。
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 循環來迭代集合和數組類型。


 

發佈了41 篇原創文章 · 獲贊 0 · 訪問量 2154
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章