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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章