抱歉!工作太忙了,更新的穩定性很難維持,不過我會儘可能在餘暇 跟大家作一些分享。這次我想來討論一些Bean Scripting Framework這個技術, 這剛好也是我工作上偶爾會用到的技術,所以把我使用的一些心得跟大家報告 一下。 首先,甚麼是Bean Scripting Framework (BSF)呢?我們先這樣想, 現在很多軟體都講究要有plugin或是extension的機制,比如像是最近很紅的 FireFox瀏覽器。有些plugin或是extension是定義一些固定的interface讓programmer 實做,然後利用ClassLoader或類似的技術來載入user寫好的元件。這個作法很 傳統,事實上也沒甚麼不好,不過有時候對於開發plugin和extension的人來說, 門檻比較高一點,加上有compile的需求,不是那麼方便。於是,就有人會想, 如果plugin和extension可以用一些scripting language來寫,比如說javascript、 vbscript,這樣是不是方便很多了?這也不算是新東西,以前M$的office系列的VBA、 現在流行的線上遊戲魔獸世界,事實上都有用到類似的機制。 Ok,問題又來了,提供透過撰寫scripting language來擴充的機制並不困難, 我們只要找個scripting language的interpreter就可以了,問題是,一旦這樣做了, 那我們的程式就會在某種程度上和這個interpreter綁住,如果說我們一開始用的是 javascript,改天想用Ruby這類新玩意,那我們就得換interpreter,如果程式寫的 不夠抽象化,那連API都會受到影響,總之得花一點力氣。 BSF就是在這種情況下誕生的,他事實上提供的是一個 "可以套用各種interpreter 的框架",我們把各種interpreter裝到BSF裡面,然後用一個通用的API去要求這些interpreter 解析程式,而且呼叫我們寫好的script,然後把一些型態轉換的問題給處理好。有一點像JDBC。 BSF預設支援很多種interpreter,比如說javascript、Ruby、甚至XSLT的interpreter都可以 裝到BSF裡面,不過當然前提是我們得去把這些interpreter先裝進BSF裡面。底下的範例, 我們使用mozilla的javascript interpreter, "rhino",這是BSF預設可以支援的interpreter 之一,把rhino和BSF一起裝到classpath上面,然後就可以來看看下面這個範例程式。 BSF裡面最重要的兩個類別是BSFManager和BSFEngine,前者用來載入寫好的script, 後者則用來執行這些script。在實作上第一步先利用BSFManager把script載入,從BSFManager 產生對應的BSFEngine,然後透過BSFEngine來呼叫那些script。 ======================================================================= //載入script和取得BSFEngine BSFManager mgr=new BSFManager(); mgr.exec("javascript","sample1",0,0,"function add(x,y){return x+y;}"); BSFEngine engine=mgr.loadScriptingEngine("javascript"); //透過BSFEngine執行載入的script Integer ret=(Integer)(engine.call("","add",new Object[]{new Integer(1),new Integer(2)})); ======================================================================= 看起來並不困難,而且彈性很大。不過各位會不會覺得有點奇怪,雖然號稱是 "Bean Scripting Framework",那個 "Bean" 到底在哪裡呢?事實上,透過engine.call 呼叫script的時候,第三個參數代表傳入script function的參數,裡面可不是只能放 原生型別的資料,可以放JavaBean!!所以程式也可能這樣寫: ======================================================================= BSFManager mgr=new BSFManager(); mgr.exec("javascript","sample1",0,0,"function addComponent(container,component){container.add(component);}"); BSFEngine engine=mgr.loadScriptingEngine("javascript"); engine.call("","add",new Object[]{ new JPanel(),new JLable("Hello BSF!!") } ); ======================================================================= 當然囉,彈性雖然很大,一些小細節還是要注意一下,比如說,在傳出和傳入的 參數中,最好不要用到陣列,因為每個scripting language對於陣列的定義可能差異很大, 而且和java的定義往往會有很大的不同,所以還是避免讓自己掉入陷阱比較好!