BeanShell使用背景:公司的抓取管理平台,公司的产品人员每天都需要对各个地方的运营商网站看一些违规,投诉,公告等信息进行监控,为了保证产品人员不必要每天都上各个网站上看信息,所以针对内部需求,我们采用抓取策略,用程序模拟登录每一个网站,然后对我们要的信息,如公告信息进行抓取,当然抓取到网页之后还要配合HtmlParse技术进行处理,然后将我们提取出的信息显示到我们平台上,这样产品人员不需要登录每一个网站看信息,只要登录我们的抓取平台就可以看各个网站最新的公告等信息。因为每一个运营商的各个地方的网站是不一样的,也就是说抓取的各个业务是不一样的,针对这种情况,我们采用BeanShell来处理各个不同的业务。对不同的网站采用不同的BSH文件来处理,这样各个网站的抓取代码都放到不同的BSH文件中,不用每多抓取一个网站重新修改代码,重新发布。这样可以减少很多工作量。下面介绍一下BeanShell.

首先:BeanShell:是一种对象脚本语言。BeanShell的解释器是用Java写的,开源并且免费的,它的运作方式“它将脚本化对象看作简单闭包方法 (simple method closure)来支持,就如同在 JavaScript中的一样。 它具有以下的一些特点:使用Java反射API以提供Java语句和表达式 的实时解释执行;可以透明地访问任何Java对象和API;可以在命令行模式、控制台模式、小程序模式和远程线程服务器模式等四种模式下面运行;与在应用 程序中一样,可以在小程序中(Applet)正常运行(无需编译器或者类装载器);非常精简的解释器jar文件大小为175k ”。

     使用BeanShell可以处理现实中不规则的业务,举个很典型的例子,我们知道,一个保险公司有很多险种,每个险种的投入和收益的算法是很复杂的,无法 用规则的关系数据库模型来描述,所以很多保险系统在处理险种的算法都是硬编码,如果要在系统中新加一个险种,是非常麻烦的,重新修改代码,重新发布,这对 开发/维护人员和客户都是很痛苦的,有了BeanShell,我们可以从这种痛苦中解脱出来,对每个险种使用不同的脚本,新加的险种我们新配一个脚本,这 样既可以满足业务多变的要求,又可以减少工作量,节约成本。

     BeanShell的一个特点是动态执行Java代码,脚本文件改变不会影响当前脚本的调用,新脚本将在脚本的下一次调用生效,这不同于配置文件,配置文件改变一般都需要应用重启。

       一个BeanShell的简单例子:

通过建立一个BeanShell解释器,使用eval()或source()命令,你可以在你的应用程序中求文本表达式的值和运行脚本。如果你希望在你的脚本内部使用一个对象,可以用set()方法传递对象的变量参照给BeanShell,并通过get()方法取得结果。

Java文件中

package com.an;
import java.io.FileNotFoundException;
import java.io.IOException;
 
import bsh.EvalError;
import bsh.Interpreter;
 
 
public class TestBeanShell {
    /**
     * 一个简单往BEANSHELL的文件传入参数,然后.java文件接收参数进行处理,然后返回结果
     * 在.java文件中打印结果
     */
    public static void main(String[] args) {
       Interpreter  inter  = new       
       try {
           //往bsh文件中传入参数(BeanShell文件中可以直接用,不用再定义)
           inter.set("inValue",new   
           //调用并执行BSH文件
           inter.source("src/com/an/testBeanShell.bsh"); 
           //获得bsh文件中的结果
           String resultValue = inter.get("outValue").toString();
           System.out.println("=====输出结果========="+resultValue);
       } catch         
           e.printStackTrace();
       } catch           
           e.printStackTrace();
       } catch          
           e.printStackTrace();
       }      
    }
}

Bsh文件

//BeanShell中打印调用print()函数

print("=======传入的参数======="+inValue);

outValue = inValue+1;

 

一些常用的命令 (绿色的是我在项目中用到的)

print():跟ava的System.out.println()非常的相像,除非它能保证输出总是命令行。print()也可以显示一些对象的类型(如数组),但比Java的更详细。

source(), run() :将一个bsh脚本读到解释器或运行在另一个解释器。

frame() - 显示一个Frame或JFrame的GUI组件.
load(), save() - 载入和保存一个序列化的对象到一个文件.
cd(), cat(), dir(), pwd(), etc. - 类unix的shell命令。
exec() - 运行一个本地的程序。
javap() - 打印一个对象的方法和字段,类似于Java的javap命令。
setAccessibility() - 开启无限制的存取private 和protected的组件。

 

脚本方法

你可以在bsh中宣告和使用方法,就像在java的类中一样。只是bsh的方法可以有动态的(宽松的)参数和返回类型。

//bsh文件中的定义方法(两个数相加)
public int add(int num1 , int num2 ){
    return num1+num2;
}
int result = add(1,2);
print(result);

注意:bsh文件的加载顺序是从上到下加载,上面例子中如果

int result = add(1,2);
print(result);
public int add(int num1 , int num2 ){
    return num1+num2;
}

则会报

 

ourced file: src/com/an/testBeanShell.bsh : Typed variable declaration : Command not found: add( int, int ) : at Line: 1 : in file: src/com/an/testBeanShell.bsh : add ( 1 , 2 )

    at bsh.Name.invokeLocalMethod(Unknown Source)

这个是BSH文件中常到的一个错误Unknown Source(未知源对象)。