开始啰嗦的介绍
现在有很多脚本语言,大家平时使用的比较多的包括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);