2013年9月25日 星期三

BeanShell快速入门—Java应用程序脚本引擎

http://www.xymyeah.com/423.html

快速入门
欢迎使用BeanShell.这是一个速成课程。我们将省去一些重要的选项和细节。要学习更多的内容请看本User’s Guide的其它部分。
下载和运行BeanShell
请到http://www.beanshell.org下载最新的JAR文件。你可以用图形桌面模式和命令行模式起动BeanShell。
如果你只是要玩一玩BeanShell,你可以在BeanShell的jar文件上双击来起动BeanShell的桌面。但不管怎样,如果你要让BeanShell与你的类与应用程序一起工作就必须将BeanShell的jar文件加到classpath中。
你可以将BeanShell的jar文件拖到JAVA_HOME的ext目录也可以直接加到classpath中。
  • windows用户请将bsh.jar放在JAVA_HOME/jre/lib/ext文件夹,OSX用户可以放在/Library/Java/Extensions.
    或者增加BeanShell到你的classpath目录,如:
    unix: export CLASSPATH=$CLASSPATH:bsh-xx.jar
    windows:set classpath %classpath%;bsh-xx.jar
然后你就可以运行BeanShell在GUI或命令行模式:
  •  java bsh.Console       // run the graphical desktop
    or
    java bsh.Interpreter   // run as text-only on the command line
    or
    java bsh.Interpreter filename [ args ] // run script file
可以在你的应用程序内部来运行,也可以作为debug及servlet的远程服务器模式,或一个Applet内部来运行BeanShell。请参考”BeanShell Modes of Operation”获得更多详情。
BeanShell GUI
用GUI模式启动BeanShell后,将打开一个桌面视窗。用鼠标右击在桌面的背景上,你可以打开另一个控制台视窗及其它的工具如一个简单的类游览器。
每一个控制台视窗运行一个独立的BeanShell解释器。这个图形化的控制台支持基本的历史命令,行编辑,剪切和粘贴,甚至类和变量名的自动完成功能。从控制台你能开启一个简单的编辑视窗。在它里面,你可以编写脚本和使用‘eval’选项求表达式的值。
Java语句和表达式
BeanShell能理解标准的JAVA语句,表达式,和方法宣告。语句和表达式的内容可以是:变量,宣告,赋值,方法调用,循环,条件等。
在Java程序中你必须严格的使用它们,但在BeanShell中,你可以用“宽松类型”(loosely typed)的方式来使用它们。也就是说,你可以在写脚本时偷懒,不进行变量类型的宣告(在原始数据类型和对象都可以)。如果你试着用错变量类型,BeanShell将会给出一个错误。
这里有一些例子:
  • foo = “Foo”;
    four = (2 + 2)*2/2;
    print( foo + ” = ” + four );  // print() is a BeanShell command
    // Do a loop
    for (i=0; i<5; i++)
    print(i);
    // Pop up a frame with a button in it
    button = new JButton( “My Button” );
    frame = new JFrame( “My Frame” );
    frame.getContentPane().add( button, “Center” );
    frame.pack();
    frame.setVisible(true);
有用的BeanShell命令
在刚才那个例子中我们用了一个内建在BeanShell中的一个方便的命令print(),来显示变量的值。print()跟ava的System.out.println()非常的相像,除非它能保证输出总是命令行。print()也可以显示一些对象的类型(如数组),但比Java的更详细。另一个相关的命令是show(),用来开启与关闭显示你输入的每一行的结果。
这儿是一些其它的BeanShell的命令:
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命令并不是真的”内建”其中的,而是作为脚本方法自动从classpath载入的. 你可以扩展基本命令集并加到classpath中作为自订义的脚本来使用。
脚本方法
你可以在bsh中宣告和使用方法,就像在java的类中一样。
  • 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”
实现Interface
注意:如果要BeanShell能实现任意的Interface,必须有jdk1.3及以上支持。
你可以在脚本中用标准的Java内部类的语法来实现Interface.例如:
  • ActionListener scriptedListener = new ActionListener() {
    actionPerformed( event ) { … }
    }
你可以不用实现Interface的所有方法,而只用实现你需要的方法。如果代码中调用了未被实现的方法,将丢出异常。如果你想重载大量的方法的行为–例如为日志生成一个”哑”适配器–你可以在脚本对象中实现一个特殊的方法:invoke(name,args)。invoke()方法用来处理任何未被定义的方法的调用:
  • ml = new MouseListener() {
    mousePressed( event ) { … }
    // handle the rest
    invoke( name, args ) { print(“Method: “+name+” invoked!”);
    }
脚本对象
在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脚本对象(也就是先前例子中的”this”参照)能自动实现任何JAVA介面类型。当JAVA代码调用相应与之通讯的脚本方法内的方法。当你试着将脚本对象作为参数传给Java方法时,BeanShell会自动将它造型(cast)为相应的类型。如要传递BeanShell外部的对象时,你可以在需要时显式的进行造型(cast).请看用户手册中的详细内容。
从你的应用程序调用BeanShell
通过建立一个BeanShell解释器,使用eval()或source()命令,你可以在你的应用程序中求文本表达式的值和运行脚本。如果你希望在你的脚本内部使用一个对象,可以用set()方法传递对象的变量参照给BeanShell,并通过get()方法取得结果。
  • import bsh.Interpreter;
    Interpreter i = new Interpreter();  // Construct an interpreter
    i.set(“foo”, 5);                    // Set variables
    i.set(“date”, new Date() );
    Date date = (Date)i.get(“date”);    // retrieve a variable
    // Eval a statement and get the result
    i.eval(“bar = foo*10″);
    System.out.println( i.get(“bar”) );
    // Source an external script file
    i.source(“somefile.bsh”);

BeanShell将成为Java平台上的第三种编程语言

2005-06-08  点击:8  来源:CSDN  作者:CSDN
JCP接纳了一个新的技术规范进入标准化进程,这个编号为JSR-274的技术规范将把BeanShell引入为Java平台上支持的又一种编程语言。
JSR-274(http://jcp.org/en/jsr/detail?id=274)是由 Patrick Niemeyer提交的技术规范,其目标是将BeanShell脚本语言(http://www.beanshell.org/)规范化为Java虚拟机平台上支持的第三种编程语言。除了Java之外,Java虚拟机还支持Groovy脚本语言。Doug Lea、Apache和Google三个JCP执委会成员对此规范表示了支持。
按照Java最初的设计思路,有很多语言都可以在JVM上运行(详细列表参见http://en.wikipedia.org/wiki/List_of_Java_scripting_languages),但这些语言大多没有流行起来。直到2004年为止,Java平台事实上只有一种编程语言,也就是Java。2004年3月,Groovy(JSR-241)成为了Java平台上的第二种编程语言。
简介:
BeanShell是一种脚本语言,一种完全符合java语法的java脚本语言,并且又拥有自己的一些语法和方法,beanShell是一种松散类型的脚本语言(这点和JS类似)。
下载地址:http://www.beanshell.org
设置环境
l 把;bsh-xx.jar放到$JAVA_HOME/jre/lib/ext文件夹下
l unix: export CLASSPATH=$CLASSPATH:bsh-xx.jar
l windows: set classpath %classpath%;bsh-xx.jar
运行方式:
l 界面UI方式 :java bsh.Console
l 命令行方式 :java bsh.Interpreter
l 运行脚本文件:java bsh.Interpreter filename [ args ]
简单举例:
在classpath中设置好环境变量,打开dos窗口,键入:java bsh.Console命令
出现BeanShell图片代表设置成功,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);
完整代码:
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);
在窗口中输入上面的代码
敲回车执行,运行结果如图
说明:
因为beanshell是松散类型的脚本语言因此可以直接写
foo = “Foo”;
four = (2 + 2)*2/2;
print是beanshell提供一种简单的打印命令相当于java中的System.out.println()
其他的beanshell脚本命令
· source(), run() – 读取,或者运行一个脚本文件
· frame() – 显示一个窗口
· load(), save() – 读取或者保存一个脚本对象到文件
· cd(), cat(), dir(), pwd(), etc. 使用Unix下面的命令
· exec() – 运行一个本地的方法
· javap() –使用javap命令.
· setAccessibility() – 设置可以接收private和protected类型的变量
BeanShell命令不一定都是内置的脚本命令,脚本方法会自动从classpath中取方法使用,因此你可以添加你自己的脚本到classpath中来扩充基本的命令
脚本方法
一般的方法:
int addTwoNumbers( int a, int b ) {
return a + b;
}
sum = addTwoNumbers( 5, 7 ); // 12
也可以使用动态的变量类型(无状态)方法
add( a, b ) {
return a + b;
}
foo = add(1, 2); // 3
foo = add(1, “2”); //”12” 只要有一个为字符串全部按照字符串处理,系统不会根据1是数字在前把“2”转换成数字处理(特别注意)
foo = add(“Oh”, ” baby”); // “Oh baby”
实现接口
实现任何接口需要java1.3或者更高
可以使用缺省的java匿名类的语法实现一个接口类,例如:
ActionListener scriptedListener = new ActionListener() {
actionPerformed( event ) { … }
}
不需要实现接口的所有的方法,只需要实现你使用的方法即可,如果使用你没有实现的方法,beanshell将抛出一个错误,
ml = new MouseListener() {
mousePressed( event ) { … }
// handle the rest
invoke( name, args ) { print(“Method: “+name+” invoked!”);
}
脚本对象
使用特殊的关键字this可以创建一个对象(根JS类似)
foo() {
print(“foo”);
x=5;
bar() {
print(“bar”);
}
return this;
}
myfoo = foo(); // prints “foo”
print( myfoo.x ); // prints “5″
myfoo.bar(); // prints “bar”
从应用程序中调用BeanShell
创建一个BeanShell的解释器(interpreter)用eval()和source()命令可以对一个字符串求值和运行一个脚本文件
使用set()方法可以给一个对象传入一个变量的参考
使用get()方法可以重新得到一个变量的结果
完整代码:
package cn.com.sparknet.util;
import bsh.*;
import java.util.*;
public class BeanShell {
public static void main(String[] args) {
try {
Interpreter interpreter = new Interpreter(); // 构造一个解释器
interpreter.set(“foo”, 5); // 设置变量
interpreter.set(“date”, new Date()); //设置一个时间对象
Date date = (Date) interpreter.get(“date”); // 重新得到时间变量
interpreter.println(date.toString()); //打印时间变量
interpreter.eval(“bar = foo*10″); // 对一段脚本求值,并得到结果
System.out.println(interpreter.get(“bar”)); //打印变量
interpreter.source(“d://helloWorld.bsh”); // 导入并执行一个脚本文件
}
catch (Exception e) {
//如果发生异常,写入日志文件
Log.error(new BeanShell(), “main”, FormatDate.getCurrDate(), e.getMessage());
}
}
}
BeanShell语法
BeanShell是一种最原始的java解释器。
标准的java语法
/*
Standard Java syntax
*/
// Use a hashtable
Hashtable hashtable = new Hashtable();
Date date = new Date();
hashtable.put( “today”, date );
// Print the current clock value
print( System.currentTimeMillis() );
// Loop
for (int i=0; i<5; i++)
print(i);
// Pop up a frame with a button in it
JButton button = new JButton( “My Button” );
JFrame frame = new JFrame( “My Frame” );
frame.getContentPane().add( button, “Center” );
frame.pack();
frame.setVisible(true);
松散类型的java语法
/*
Loosely Typed Java syntax
*/
// Use a hashtable
hashtable = new Hashtable();
date = new Date();
hashtable.put( “today”, date );
// Print the current clock value
print( System.currentTimeMillis() );
// Loop
for (i=0; i<5; i++)
print(i);
// Pop up a frame with a button in it
button = new JButton( “My Button” );
frame = new JFrame( “My Frame” );
frame.getContentPane().add( button, “Center” );
frame.pack();
frame.setVisible(true);
异常处理
标准的java异常
try {
int i = 1/0;
} catch ( ArithmeticException e ) {
print( e );
}
松散的异常处理(类似JS)
try {

} catch ( e ) {

}
松散类型变量的作用范围
标准的java程序的变量作用范围是在一个模块中的(在模块中声明的变量),而在松散类型的语言中如果在一个模块中没有指定一个变量的类型,则认为是一个全局变量(只有它以后的代码可以使用该变量,系统在调用该变量的时候自动生成一个全局变量,也就为什么在调用模块之前不能使用该变量的原因)
// Arbitrary code block
{
y = 2; // Untyped variable assigned
int x = 1; // Typed variable assigned
}
print( y ); // 2
print( x ); // Error! x is undefined.
// Same with any block statement: if, while, try/catch, etc.
if ( true ) {
y = 2; // Untyped variable assigned
int x = 1; // Typed variable assigned
}
print( y ); // 2
print( x ); // Error! x is undefined.
同样也使用于for-loop, if-else等循环语句
for( int i=0; i<10; i++ ) { // typed for-init variable
j=42;
}
print( i ); // Error! ‘i’ is undefined.
print( j ); // 42
for( z=0; z<10; z++ ) { } // untyped for-init variable
print( z ); // 10
方便灵活的语法
标准的java语法
java.awt.Button button = new java.awt.Button();
button.setLabel(“javaButton”);
松散的语法
button = new java.awt.Button();
button.label = “my button”;
你也可以使用{}来对一个对象设置属性
b = new java.awt.Button();
b{“label”} = “my button”; // Equivalent to: b.setLabel(“my button”);
h = new Hashtable();
h{“foo”} = “bar”; // Equivalent to: h.put(“foo”, “bar”);
包装和未包装(box和unbox)
BeanShell自动转为简单类型
i=5;
iw=new Integer(5);
print( i * iw ); // 25
导入类和包
import javax.xml.parsers.*;
import mypackage.MyClass;
超级导入法:
import *;
BeanShell默认导入下面的包
· java.lang
· java.io
· java.util
· java.net
· java.awt
· java.awt.event
· javax.swing
· javax.swing.event
友好文档实体
BeanShell支持特殊的文档操作类型内容
@gt > @lt <
@lteq <= @gteq >=
@or || @and &&
@bitwise_and & @bitwise_or |
@left_shift << @right_shift >>
@right_unsigned_shift >>> @and_assign &=
@or_assign |= @left_shift_assign <<=
@right_shift_assign >>= @right_unsigned_shift_assign >>>=
脚本方法
你可以定义方法象java中的定义方法一样
int addTwoNumbers( int a, int b ) {
return a + b;
}
你可以使用内馅的BeanShell方法使用他们
sum = addTwoNumbers( 5, 7 );
只有BeanShell变量可以被动态定义为动态类型,方法可以有动态的参数以及返回类型
add( a, b ) {
return a + b;
}
在这个方法中,BeanShell将动态的决定类型当这个方法被调用时并且能够准确的计算出你想要的结果
foo = add(1, 2);
print( foo ); // 3
foo = add(“Oh”, ” baby”);
print( foo ); // Oh baby
在第一个例子中BeanShell将把参数定义为数字型,并返回数字型
在第二个例子中BeanShell将把参数定义为字符型,并返回字符对象
变量和方法的可见范围
就像您所预期的那样,在方法内您可以参考到上下文中上面的变量和方法
a = 42;
someMethod() { … }
foo() {
print( a );
someMethod(); // invoke someMethod()
}
// invoke foo()
foo(); // prints 42
如果一个变量只有在方法内使用请定义成局部变量,即加上类型,如果是全局变量请在方法外定义
var = “global”;
foo() {
print(var);
String var = “local”;
print(var);
}
foo();
print(var);
将打印出
global
local
global
方法内的var(第四行)变量属于局部变量,不会覆盖全局变量var(第一行)的因此改变var(第四行)变量不会影响到全局变量var(第一行)
范围参考:super
使用super关键字可以在局部参考到全局变量
var = “global”;
foo() {
String var = “local”;
print(var);
print(super.var);
}
foo();
将输出
local
global
脚本对象
this对象
在java标准语言中可以使用this返回一个类的一个实例
// MyClass.java
MyClass {
Object getObject() {
return this; // return a reference to our object
}
}
在这个例子中getObject() 方法是返回MyClass类的一个实例
在BeanShell中对象中的变量只是局部的变量在对象内可以使用,在对象外是不可以使用(不同于前面for-loop,if-else中的使用);
// Define the foo() method:
foo() {
bar = 42;
print( bar );
}
// Invoke the foo() method:
foo(); // prints 42
print( bar ); // Error, bar is undefined here
可以使用this返回对象,使用对象加上“.”运算符参考属性(类似JS)
foo() {
bar = 42;
return this;
}
fooObj = foo();
print( fooObj.bar ); // prints 42!
同样对象中也可以定义一些方法
foo() {
bar() {

}
}
例如
foo() {
int a = 42;
bar() {
print(“The bar is open!”);
}
bar();
return this;
}
// Construct the foo object
fooObj = foo(); // prints “the bar is open!”
// Print a variable of the foo object
print ( fooObj.a ) // 42
// Invoke a method on the foo object
fooObj.bar(); // prints “the bar is open!”
也可以把bar()和foo也可以代参数
foo() {
return this;
}
bar(int a) {
print(“The bar is open!” + a);
}
foo().bar(1);
也可以把bar()方法定义到对象外面
foo() {
bar(int a) {
print(“The bar is open!” + a);
}
return this;
}
foo().bar(1);
BeanShell一种松散的脚本语言,有很多中声明的方法可以使用
This super global
This是参考当前对象
Super是参考父亲对象
Global是参考最上层对象
super.super.super…foo = 42; // Chain super. to reach the top
global.foo = 42;
简单例子:
文本拖动:
dragText() {
f = new Frame(“Drag in the box”);
f.setFont( new Font(“Serif”, Font.BOLD, 24) );
f.setSize(300, 300);
f.show();
gc = f.getGraphics();
gc.setColor(Color.cyan);
mouseDragged( e ) {
gc.drawString(“Drag Me!”, e.getX(), e.getY());
}
mouseMoved( e ) { }
f.addMouseMotionListener( this );
}
简单画图
import bsh.util.BshCanvas; // BshCanvas simply buffers graphics
graph( int width, int height ) {
canvas=new BshCanvas();
canvas.setSize( width, height );
frame=frame( canvas );
graphics=canvas.getBufferedGraphics();
// draw axis
graphics.setColor( Color.red );
graphics.drawLine( 0, height/2, width, height/2 );
graphics.drawLine( width/2, 0, width/2, height );
graphics.setColor( Color.black );
plot(int x, int y) {
graphics.fillOval( (x+width/2-1), (y+height/2-1), 3, 3);
canvas.repaint();
}
return this;
}
drawSin( graph ) {
for (int x=-100; x<100; x++ ) {
y=(int)(50*Math.sin( x/10.0 ));
graph.plot( x, y );
}
}
简单web浏览器
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import java.awt.event.*;
import java.awt.*;
JFrame browser( startingUrl ) {
invoke( method, args ) {}
windowClosing(WindowEvent we) {
we.getWindow().setVisible(false);
}
setPage( url ) {
try {
pane.setPage( url );
} catch(Exception e) {
statusBar.setText(“Error opening page: “+url);
}
}
hyperlinkUpdate( HyperlinkEvent he ) {
type = he.getEventType();
if (type == HyperlinkEvent.EventType.ENTERED) {
pane.setCursor(
Cursor.getPredefinedCursor( Cursor.HAND_CURSOR) );
statusBar.setText(he.getURL().toString());
} else
if (type == HyperlinkEvent.EventType.EXITED) {
pane.setCursor( Cursor.getDefaultCursor() );
statusBar.setText(” “);
} else {
setPage( he.getURL() );
if (urlField != null)
urlField.setText(he.getURL().toString());
}
}
frame = new JFrame(“Browser”);
frame.setSize(400,300);
frame.addWindowListener( this );
urlPanel = new JPanel();
urlPanel.setLayout(new BorderLayout());
urlField = new JTextField(startingUrl);
urlPanel.add(new JLabel(“Site: “), BorderLayout.WEST);
urlPanel.add(urlField, BorderLayout.CENTER);
statusBar = new JLabel(” “);
pane = new JEditorPane();
pane.setEditable(false);
setPage( startingUrl );
jsp = new JScrollPane(pane);
frame.getContentPane().add(jsp, BorderLayout.CENTER);
frame.getContentPane().add(urlPanel, BorderLayout.SOUTH);
frame.getContentPane().add(statusBar, BorderLayout.NORTH);
// This is the equivalent of an inner class in bsh.
urlTextHandler() {
actionPerformed(ActionEvent ae) {
setPage( ae.getActionCommand() );
}
return this;
}
urlField.addActionListener( urlTextHandler() );
pane.addHyperlinkListener( (HyperlinkListener)this );
return frame;
}
browser = browser(“http://java.sun.com/”);
browser.show();
更多的文档参考BeanShell网站
http://www.beanshell.org