读书人

Java脚本技术运用实例

发布时间: 2012-12-28 10:29:04 作者: rapoo

Java脚本技术应用实例
前言

一直以来都很喜欢可以自由扩展的软件,这一点应该已经在很多文章里提到,也重复过很多次了。但是,可扩展性,灵活性是开发人员最喜欢的东西了,本性难改。平时使用的开发环境如vim/emacs, IDE中的Eclipse/Netbeans, 浏览器FF/Chrome都具有强大而灵活的可扩展支持。而关于Java的脚本支持,我已经在数篇文章中提及,大多是关于JavaScript引擎rhino和宿主Java之间的合成,但是Java的脚步支持远不止这些,这篇文章尝试讨论一下,Java对其他语言的支持。

?

文中实现一个简单的工资计算器,本来是在来到新公司不久,用以和同事们交流脚本技术的应用时做的,后来又进行了一些改动,由于只是一个示例,界面很简单:


Java脚本技术运用实例

?

工资计算器

这个计算器很简单,从脚本中获取转换表(convertTable)及基数(base),即:当工资低于base时,直接返回工资数目,如果高于base,则根据转换表来查找税率,然后扣除税款,得到实际工资。由于在实际生活中,税率会不断的调整,这部分内容就应该放入脚本:

?

?

//base salaryvar base = 2000;/** * range and tax-rage convert table */var convertTable = {"0~1000" : 0.1,"1000~2000" : 0.15,"2000~3000" : 0.2,"3000~5000" : 0.25,"5000~8000" : 0.3,"8000~-1" : 0.4}

?

这里用-1表示不限。

?

在本文的示例中,每一个脚本会被作为一个"插件",插件可以被创建,激活,安装到应用程序中,安装之后的插件,存在于应用程序的运行时环境(RuntimeEnv),并可以在需要的时候被调用执行。比如在本文中,初始化应用程序的时候,init方法将被调用:

?

?

public void init(){Plugin system = new SimplePlugin("scripts/calc.js");system.activate();SimplePluginManager.getInstance().install(system);}

?

然后,当按钮[计算实际工资]被点击的时候,会调用:

?

?

btnCalc.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) {SimplePluginManager.getInstance().getPlugin("calc").activate();String salary = textSalary.getText();Double d = Double.parseDouble(salary);Double r = (Double)RuntimeEnv.getInstance().invokeFunction("calc", d);textReal.setText(String.valueOf(r));}});

?

仔细观察会发现,在actionPerformed方法中,首先会将get出来的插件做激活(activate)动作,这是因为,如果应用程序在运行期间,脚本做过修改,则可以事实的反映在结果上。这里去掉了一些验证,比如根据脚本文件的lastModified来判断是否需要激活等。

?


Java脚本技术运用实例

我将script做了一个简单的包装,成为插件,这个示例中的插件结构如上图所示。RuntimeEnv为一个单例的实例,在应用中是始终有一个,每个组件都可以向这个实例请求执行脚本中的函数,至于函数的参数传递,类型转换等工作,由底层的脚本引擎来负责执行。

?

为了脚本可以被重复使用,可以将脚本先编译为“已编译脚本”对象:

?

?

/** * compile the script-file into an <code>CompiledScript</code> object * @return */public CompiledScript compile(File file){Date scriptDate = new Date(file.lastModified());if(lastModified == null || scriptDate.after(lastModified)){Reader reader = null;try {reader = new FileReader(file);compiledScript = RuntimeEnv.getInstance().getCompilableEngine().compile(reader);lastModified = scriptDate;} catch (FileNotFoundException e) {e.printStackTrace();} catch (ScriptException e) {e.printStackTrace();}finally{if(reader != null){try {reader.close();} catch (IOException e) {}}}}this.status = Plugin.STATUS_LOADED;return compiledScript;}
?

?

JavaScript版本的实现

下面为JavaScript版本的脚本,包含完整的计算逻辑,如果税率有新的调整,则仅仅需要修改脚本文件,甚至是在应用程序已处于运行状态。

?

?

//base salaryvar base = 2000;/** * range and tax-rage convert table */var convertTable = {"0~1000" : 0.1,"1000~2000" : 0.15,"2000~3000" : 0.2,"3000~5000" : 0.25,"5000~8000" : 0.3,"8000~-1" : 0.4}/** * if the value is in the range? */function inRange(value, range){var vs = range.split("~");var low, high;low = parseFloat(vs[0]);high = parseFloat(vs[1]);if(high == -1){//-1 means infinityhigh = Number.MAX_VALUE;}return (value >= low && value <= high);}/** * This is the function will be invoked by java program * @param salary * @return */function calc(salary){var value;// less that or equals to baseif(salary <= base){value = salary;}else{var f = salary - base;for(var item in convertTable){if(inRange(f, item)){value = salary - salary * convertTable[item];break;}}}return value;}
?

?

Python版本的实现?

python版本仅仅作为JavaScript版本的翻译,但是在应用程序的角度来看,是没有任何差别的(可能在有错误的时候,会产生不同的异常)。

?

?

## author : juntao.qiu@gmail.com## salary basebase = 2000# convert table of range and rateconvertTable = {"0~1000" : 0.1,"1000~2000" : 0.15,"2000~3000" : 0.2,"3000~5000" : 0.25,"5000~8000" : 0.3,"8000~-1" : 0.4}# test value in range or notdef inRange(value, range):vs = range.split("~")low = float(vs[0])high = float(vs[1])if(high == -1):high = "inf"return (value >= low and value <= high)# calculate salary without tax, invoked by java codedef calc(salary):value = Noneif(salary <= base):return salaryelse:f = salary - basefor item in convertTable:if(inRange(f, item)):value = salary - salary * convertTable[item]break;return value

?

?

应该注意的是,jython的版本应该等于或者大于2.5.1,在2.5.1中,jython才实现了java的脚本扩展接口,我在测试的时候,jython的最新版本为2.5.1,不知道现在是否已经更新。

?

=========================================================

更新:

2011/1/23:添加了代码下载,感兴趣的朋友可以自行下载,需要注意的是,尽量使用JDK1.6版本,如果要验证jython,请使用2.5.1以上版本。JDK1.6中吧有JavaScript的实现



打个比方哈。。。小弟初学很不解 而且最终脚本也是转为java字节码,除了获得灵活简洁的语法还有其他原因不

打个比方哈。。。小弟初学很不解 而且最终脚本也是转为java字节码,除了获得灵活简洁的语法还有其他原因不

就我个人的观点来说,几乎所有地方都可以加入脚本,当然,肯定会有效率,调试等方面的限制,因此我建议你在效率要求不高,而软件需求变化较频繁(考虑到实施等问题,最好使用脚本),或者软件的扩展性,定制性要求较高的场合。举例子的话,比如我上边提到的,编辑器,浏览器,IDE,图形编辑软件,播放器等等,都可以使用脚本。

总的来说,软件开发应该考虑到扩展性,尽量提供一个通用的基础平台,提供足够的接口,然后其他的功能都通过插件来实现,如Eclipse, Netbeans, Vim/Emacs等那样。

脚本语言的好处有很多:比如接口既定的情况下,无需编译宿主程序,即可直接运行;又比如脚本语言本身的灵活性,以及其他的一些特性,如JS的函数式编程;又比如,脚本语言本身无法完成的功能,如文件读写,网络访问,数据库访问等功能可以通过宿主语言来完成,等等。 22 楼 DOCDOC 2011-01-24 eclipse-my 写道动态脚本确实效率比较低,顾此失彼
我觉得这是一个取舍的问题,并没有完美的方案 23 楼 robiplus 2011-01-24 abruzzi 写道
就我个人的观点来说,几乎所有地方都可以加入脚本,当然,肯定会有效率,调试等方面的限制,因此我建议你在效率要求不高,而软件需求变化较频繁(考虑到实施等问题,最好使用脚本),或者软件的扩展性,定制性要求较高的场合。举例子的话,比如我上边提到的,编辑器,浏览器,IDE,图形编辑软件,播放器等等,都可以使用脚本。

总的来说,软件开发应该考虑到扩展性,尽量提供一个通用的基础平台,提供足够的接口,然后其他的功能都通过插件来实现,如Eclipse, Netbeans, Vim/Emacs等那样。

脚本语言的好处有很多:比如接口既定的情况下,无需编译宿主程序,即可直接运行;又比如脚本语言本身的灵活性,以及其他的一些特性,如JS的函数式编程;又比如,脚本语言本身无法完成的功能,如文件读写,网络访问,数据库访问等功能可以通过宿主语言来完成,等等。

仔细想了下。。。是的,用脚本来写程序中可plugin的地方真的不错,无需编译很给力。。。下次有机会尝试下,就不用去写配置文件+实现类来plugin了 哈哈 24 楼 生活小丑 2011-01-24 嗯,好想法!弱弱的问一句,楼主这图是什么工具画出来的? 25 楼 abruzzi 2011-01-24 生活小丑 写道嗯,好想法!弱弱的问一句,楼主这图是什么工具画出来的?

Netbeans 6.5的UML插件。很奇怪的是,6.9版本竟然把UML插件去掉了,换成一个叫VP的东东。 26 楼 hu437 2011-01-24 abruzzi 写道hu437 写道楼主现在是2011年了,呵呵~~

C发明于1972年,知识分子们还在上山下乡,众多的javaeyer还没有出生,现在还不是有大量相关的书籍,文章发表?
Java发明于1991年,改革开放才刚刚真正的开始,众多的javaeyer还没见过计算机,现在还不是天天有相关的文章在出现?
2011年怎么了?呵呵。

呵呵 LZ理解错了,我没有其他意思,只是看到你下面写的更新是2010/1/23 只是说现在是2011年了,不是2010 27 楼 tooor 2011-01-25 www.create-world.com

编写服务器端脚本,开发多人在线实时交互应用

性能完全没有问题 28 楼 abruzzi 2011-01-25 hu437 写道abruzzi 写道hu437 写道楼主现在是2011年了,呵呵~~

C发明于1972年,知识分子们还在上山下乡,众多的javaeyer还没有出生,现在还不是有大量相关的书籍,文章发表?
Java发明于1991年,改革开放才刚刚真正的开始,众多的javaeyer还没见过计算机,现在还不是天天有相关的文章在出现?
2011年怎么了?呵呵。

呵呵 LZ理解错了,我没有其他意思,只是看到你下面写的更新是2010/1/23 只是说现在是2011年了,不是2010

哦,不好意思,我以为你是再说技术过时的问题,我修改下更新时间(没有上下文,很容易误解,不好意思)。 29 楼 chenyongxin 2011-01-25 robiplus 写道abruzzi 写道
就我个人的观点来说,几乎所有地方都可以加入脚本,当然,肯定会有效率,调试等方面的限制,因此我建议你在效率要求不高,而软件需求变化较频繁(考虑到实施等问题,最好使用脚本),或者软件的扩展性,定制性要求较高的场合。举例子的话,比如我上边提到的,编辑器,浏览器,IDE,图形编辑软件,播放器等等,都可以使用脚本。

总的来说,软件开发应该考虑到扩展性,尽量提供一个通用的基础平台,提供足够的接口,然后其他的功能都通过插件来实现,如Eclipse, Netbeans, Vim/Emacs等那样。

脚本语言的好处有很多:比如接口既定的情况下,无需编译宿主程序,即可直接运行;又比如脚本语言本身的灵活性,以及其他的一些特性,如JS的函数式编程;又比如,脚本语言本身无法完成的功能,如文件读写,网络访问,数据库访问等功能可以通过宿主语言来完成,等等。

仔细想了下。。。是的,用脚本来写程序中可plugin的地方真的不错,无需编译很给力。。。下次有机会尝试下,就不用去写配置文件+实现类来plugin了 哈哈
你可以尝试使用JavaCompiler,在将你编写的java源文件放入一个pugin目录下,使用的时候使用JavaCompiler进行编译,然后执行 30 楼 kaneg 2011-01-31 freish 写道动态脚本执行的效率较低,尤其是js在java高并发的时候

其实并不是所有应用都需要考虑执行效率的。对于非大型多用户应用,开发的灵活性和及时性更重要。

举个例子,魔兽世界的插件使用lua语言编写的,任何人懂这个语言和游戏的人用一个文本编辑器就可以做出一个插件来,这样的便利性有多高可想而知

读书人网 >编程

热点推荐