程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 為Java應用程序加入腳本引擎

為Java應用程序加入腳本引擎

編輯:關於JAVA

前言

現代許多流行的應用程序,越來越多的使用了腳本引擎,最典型的有 Microsoft Office中的VBA等。腳本引擎能提供應用程序極大的可擴展性,也是 被許多熱忠於二次開發的使用者所樂意看到的。本文主要講解 BeanShell----這 樣一個Java應用程序腳本引擎,你會了解它的基本特性,及如何將它嵌入到你的 應用程序中。你將看到,為自己的應用程序加上腳本引擎是多麼容易的一件事情 。

常見的腳本引擎

現在網絡上流行著許多種腳本語言,如TCL,Perl, JavaScript,Python等, 並且有許多腳本語言都有基於Java的解釋器,就筆者所知道的有如下幾種:

Language Java Implementation JavaScript Rhino Python Jython (formerly JPython) Tcl/Tk Jacl Perl None Java itself BeanShell

以上幾種腳本都有各自的語法,而其中JavaScript和BeanShell的語法,對於 使用者來說更具有親切感。本文主要講解BeanShell的的特性及其如何集成到 Java應用程序中。

什麼是BeanShell?

BeanShell是一個小型的,免費的,可嵌入式的,具有面向對象腳本語言特性 的Java代碼解釋器。它是用Java語言寫的。它能執行標准的Java語句和表達式, 還自帶簡單的腳本命令和語法。它把編程對象當成一個簡單的方法,這很像Perl 和JavaScript.

你可以在寫Java測試或調試時使用BeanShell,也可以用它作為你的應用程序 的腳本引摯。簡而言之,BeanShell可以動態的解釋JAVA語言。也就是說 BeanShell在許多方面對於Java的用處就像Tcl/Tk對於C的用處一樣:BeanShell 是可嵌入式的---你可以在運行時從你的應用程序調用BeanShell去動態的執行 Java代碼或是為你的應用程序提供腳本擴展。相反,你也可以從BeanShell調用 你的應用程序及其對象,它可以讓JAVA對象和API動態運行。正因為BeanShell是 用JAVA寫的,所以它可以和你的應用程序運行在同一個JVM空間內,你也可以自 由的傳遞實時對象的引用(References)到腳本代碼中並且作為結果返回。

BeanShell腳本語言簡介

BeanShell能理解標准的JAVA語句,表達式,和方法宣告。語句和表達式的內 容可以是:變量,宣告,賦值,方法調用,循環,條件等。

在 Java程序中你必須嚴格的使用它們,但在BeanShell中,你可以用"寬松類 型"(loosely typed)的方式來使用它們。也就是說,你可以在寫腳本時偷懶,不 進行變量類型的宣告(在原始數據類型和對象都可以)。如果你試著用錯變量類型 ,BeanShell將會給出一個錯誤。總之BeanShell的腳本是很容易上手的。

這裡有一個簡單的例子:

foo = "Foo";
four = (2 + 2)*2/2;
print( foo + " = " + four ); // print() 是BeanShell的一個 腳本命令。
// 循環
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);

你也可以在Beanshell腳本中宣告和定義自己的方法:

int multiply(int a, int b)
{
   return a*b;
}
print(multiply(12,14));//打印出168

BeanShell的變量或參數的類型可以不用顯示的指定,如下:

int multiply(a, b)
{
   return a*b;
}
result = multiply(12,14);
print(result);//打印出168

在BeanShell中也可以寫對象。它與JavaScript很相似,它用一個方法,再內 嵌一些內部方法,並且在未尾返回一個this來實現對象的編程:

Employee()
{
  age = 26;
  sex = "M";
  name = "Turbo";
  int getAge()
  {
  return age;
}
String getSex()
{
  return sex;
}
String getName()
{
  return name;
}
return this;
}
turbo = Employee(); // 構造一個Employee對象。
print("Name:"+turbo.getName); //打印出employee的名字。

上面的程序片斷,相信大家已經對BeanShell的語法有了一個印象,你可以通 過參考資料中的鏈接,找到更詳細的BeanShell的腳本語法教程。

在應用程序中嵌入腳本引擎

其實在Java中調用bsh的腳本非常簡單,你需要先創建一個Interpreter類的 實例.然後就可以用它運行你的腳本代碼或者腳本文件。請看下面的一個例子, 這個例子來自於BeanShell的文檔:

Import bsh.*;
//創建一個bsh解釋器實例
Interpeter bsh = new Interpreter();

  // 表達式求值 
  bsh.eval("foo=Math.sin(0.5)");
  bsh.eval("bar=foo*5; bar=Math.cos(bar);");
  bsh.eval("for(i=0; i<10; i) { print(\"hello\"); }");
  // 運行語句。
  bsh.eval("for(int i=0; i<10; i) { System.out.println (\"hello\"); }");
  // 載入腳本文件
  bsh.source("myscript.bsh"); // or bsh.eval("source (\"myscript.bsh\")");
  // 使用set()和get()方法存取變量值。
  bsh.set( "date", new Date() );
  Date date = (Date)bsh.get( "date" );
  // This would also work: 
  Date date = (Date)bsh.eval( "date" );
  bsh.eval("year = date.getYear()");
  Integer year = (Integer)bsh.get("year"); // primitives use  wrappers
  // 也可以實現任意的Java Interface..
  // 或處理AWT事件。
  bsh.eval( "actionPerformed( e ) { print( e ); }");
  ActionListener scriptedHandler = 
      (ActionListener)bsh.eval("return (ActionListener) this");
  Use the scripted event handler normally...
  new JButton.addActionListener( script );

示例程序

為了讓讀者更好的理解,我們在這裡以jdk1.4中的一個演示程序,Notepad程 序作為基礎,向讀者講解BeanShell是如何嵌入到Notepad程序中的。如果你安裝 了JDK1.4的話,Notepad源程序可以在<JAVA_HOME>\demo\jfc\Notepad目 錄中找到.

筆者寫的一個BeanShell類,用來運行用戶的腳本,下面的該程序的完整清單 :

import javax.swing.text.*;
import javax.swing.*;
import java.io.*;
import bsh.*;
public class BeanShell
{
  private static NameSpace namespace;
  private static boolean running;
  private static Notepad notepad;
  //初始化引擎
  public static void initBeanShell(Notepad pad)
  {
  notepad = pad;
  namespace = new NameSpace("Notepad embedded scripting  engine.");
  }
  //運行一段腳本代碼
   public static void runScript(String script)
   {
  try
  {
   StringReader reader = new StringReader(script);
       runScript( "New script", reader);
     }
     catch(Exception ex)
     {
   ex.printStackTrace();
   System.out.println(ex);
       return;
     }
   }
   public static void runScript(String scriptInfo, Reader  reader)
   {
     Interpreter interpreter = new Interpreter (reader,System.out,System.out,true,namespace);
     try
     {
       if(notepad != null)
       {
         JTextComponent editor = notepad.getEditor();
interpreter.set("application",notepad); //將應用程序的變量傳入解釋 器,
interpreter.set("editor", editor);   //這樣就可在腳本中使用這個 變量參照 
       running = true;
       interpreter.eval(reader, namespace, scriptInfo);
   }
     }
     catch(Throwable throwable)
     {
   throwable.printStackTrace();
   JOptionPane.showMessageDialog(notepad,
     new Object[]
     {"Script 錯誤!",
     throwable.getMessage()},
     "錯誤",JOptionPane.ERROR_MESSAGE);
     }
     finally
     {
       running = false;
     }
   }
  public static boolean isMacroRunning()
  {
  return running;
  }
}

這個BeanShell提供了三個方法, void initBeanShell(Notepad),這個方法進行初始化。

void runScript(String script),這個方法可直接運行腳本代碼。

void runScript(String scriptInfo, Reader reader),這個方法可從一個 Reader流中運行腳本。

而真正核心的執行腳本的代碼在void runScript(String scriptInfo, Reader reader)方法中,大家注意,代碼中先創建了一個BeanShell的解釋器實例,

Interpreter interpreter = new Interpreter (reader,System.out,System.out,true,namespace);

然後將Notepad程序的實例變量傳入解釋器,這樣就可直接在腳本中引用 Notedpad的實例了,

JTextComponent editor = notepad.getEditor();
interpreter.set("application",notepad); //將應用程序的變量傳入解釋 器,
interpreter.set("editor", editor);   //這樣就可在腳本中使用這個 變量參照

接下來看看如何把BeanShell嵌入到Notepad程序中,筆者寫了幾個類, Main ,用來初始化,並在Notepad程序中加入一個"Script Editor"的菜單 ScriptEditor,簡單的腳本編輯器,用來編輯或載入腳本,運行腳本程序。 ScriptEditorAction,啟動Script Editor的Action.

下面是Main.class的主要代碼,

 Notepad notepad = new Notepad();
  JMenu editMenu = new JMenu("Script Editor");
  JMenuItem editItem = new JMenuItem();
  editMenu.add(editItem);
  editItem.setAction(new ScriptEditorAction(notepad));
  notepad.getMenubar().add(editMenu);

以上程序取得Notepad程序的Menu Bar,並添加一個Script Editor菜單到其中 ,這樣,就可不用修改Notepad程序,並在其中加入啟動Script Editor的菜單。

下圖是程序運行中的畫面:

寫一個簡單的腳本

現在我們寫一個簡單的腳本代碼,用來統計某個單詞在Notepad文章中的出現 次數,下面列出這個腳本的代碼:

/** 
  * 字串統計程序。
  * @author: turbo chen
  */
//字串統計函數
counter(s)
{
  str = editor.getText();
  str = str.toLowerCase();
  slen = s.length();
  s = s.toLowerCase();
  count = 0;
  from = 0;
  while ( (from=str.indexOf(s,from))>-1 )
  {
  count = count + 1;
  from = from + slen;
  }
  return count;
}
// application 是經由BeanShell傳入的應用程序對象。
target = JOptionPane.showInputDialog(application,"Please input  the count target:");
if ( target != null )
{
  count = counter(target);
  JOptionPane.showMessageDialog(application,"Found "+count+"  targets.");
}

將上面的腳本輸入到"Script Editor"視窗中,運行它。看看程序運行的畫面 :

(查找"of"這個單詞在文章中出現的次數,)

(找到13個目標。)

總結

本文講解了BeanShell腳本引擎如何在現有的應用程序中應用,也讓讀者了解 到BeanShell腳本的基本特性與腳本語法,讓大家看到嵌入腳本引擎到Java應用 程序中是多麼的容易。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved