- 浏览: 454386 次
- 性别:
- 来自: 西安
文章分类
最新评论
-
进退取舍:
谢谢,这个用上了!!
Java 一个线程池的示例 -
pb_water:
感谢楼主,打算买楼主的书,支持一下,楼主功德无量
JavaScript内核系列第0版整理稿下载 -
lancezhcj:
有图会直观的多呢,再摸索摸索
有限自动机与建模 -
hsmsyy:
这里应该是原创了吧,楼主我觉得闭包的作用:实现面向对象。有待商 ...
JavaScript内核系列 第7章 闭包 -
wll52:
在应用退出之前,需要释放连接 con.disconnect() ...
使用smack与GTalk通信
前言
一直以来都很喜欢可以自由扩展的软件,这一点应该已经在很多文章里提到,也重复过很多次了。但是,可扩展性,灵活性是开发人员最喜欢的东西了,本性难改。平时使用的开发环境如vim/emacs, IDE中的Eclipse/Netbeans, 浏览器FF/Chrome都具有强大而灵活的可扩展支持。而关于Java的脚本支持,我已经在数篇文章中提及,大多是关于JavaScript引擎rhino和宿主Java之间的合成,但是Java的脚步支持远不止这些,这篇文章尝试讨论一下,Java对其他语言的支持。
文中实现一个简单的工资计算器,本来是在来到新公司不久,用以和同事们交流脚本技术的应用时做的,后来又进行了一些改动,由于只是一个示例,界面很简单:
工资计算器
这个计算器很简单,从脚本中获取转换表(convertTable)及基数(base),即:当工资低于base时,直接返回工资数目,如果高于base,则根据转换表来查找税率,然后扣除税款,得到实际工资。由于在实际生活中,税率会不断的调整,这部分内容就应该放入脚本:
//base salary var 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 来判断是否需要激活等。
我将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 salary var 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 infinity high = 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 base if(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 base base = 2000 # convert table of range and rate 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 } # test value in range or not def 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 code def calc(salary): value = None if(salary <= base): return salary else: f = salary - base for 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的实现
评论
其实并不是所有应用都需要考虑执行效率的。对于非大型多用户应用,开发的灵活性和及时性更重要。
举个例子,魔兽世界的插件使用lua语言编写的,任何人懂这个语言和游戏的人用一个文本编辑器就可以做出一个插件来,这样的便利性有多高可想而知
就我个人的观点来说,几乎所有地方都可以加入脚本,当然,肯定会有效率,调试等方面的限制,因此我建议你在效率要求不高,而软件需求变化较频繁(考虑到实施等问题,最好使用脚本),或者软件的扩展性,定制性要求较高的场合。举例子的话,比如我上边提到的,编辑器,浏览器,IDE,图形编辑软件,播放器等等,都可以使用脚本。
总的来说,软件开发应该考虑到扩展性,尽量提供一个通用的基础平台,提供足够的接口,然后其他的功能都通过插件来实现,如Eclipse, Netbeans, Vim/Emacs等那样。
脚本语言的好处有很多:比如接口既定的情况下,无需编译宿主程序,即可直接运行;又比如脚本语言本身的灵活性,以及其他的一些特性,如JS的函数式编程;又比如,脚本语言本身无法完成的功能,如文件读写,网络访问,数据库访问等功能可以通过宿主语言来完成,等等。
仔细想了下。。。是的,用脚本来写程序中可plugin的地方真的不错,无需编译很给力。。。下次有机会尝试下,就不用去写配置文件+实现类来plugin了 哈哈
你可以尝试使用JavaCompiler,在将你编写的java源文件放入一个pugin目录下,使用的时候使用JavaCompiler进行编译,然后执行
C发明于1972年,知识分子们还在上山下乡,众多的javaeyer还没有出生,现在还不是有大量相关的书籍,文章发表?
Java发明于1991年,改革开放才刚刚真正的开始,众多的javaeyer还没见过计算机,现在还不是天天有相关的文章在出现?
2011年怎么了?呵呵。
呵呵 LZ理解错了,我没有其他意思,只是看到你下面写的更新是2010/1/23 只是说现在是2011年了,不是2010
哦,不好意思,我以为你是再说技术过时的问题,我修改下更新时间(没有上下文,很容易误解,不好意思)。
编写服务器端脚本,开发多人在线实时交互应用
性能完全没有问题
C发明于1972年,知识分子们还在上山下乡,众多的javaeyer还没有出生,现在还不是有大量相关的书籍,文章发表?
Java发明于1991年,改革开放才刚刚真正的开始,众多的javaeyer还没见过计算机,现在还不是天天有相关的文章在出现?
2011年怎么了?呵呵。
呵呵 LZ理解错了,我没有其他意思,只是看到你下面写的更新是2010/1/23 只是说现在是2011年了,不是2010
Netbeans 6.5的UML插件。很奇怪的是,6.9版本竟然把UML插件去掉了,换成一个叫VP的东东。
就我个人的观点来说,几乎所有地方都可以加入脚本,当然,肯定会有效率,调试等方面的限制,因此我建议你在效率要求不高,而软件需求变化较频繁(考虑到实施等问题,最好使用脚本),或者软件的扩展性,定制性要求较高的场合。举例子的话,比如我上边提到的,编辑器,浏览器,IDE,图形编辑软件,播放器等等,都可以使用脚本。
总的来说,软件开发应该考虑到扩展性,尽量提供一个通用的基础平台,提供足够的接口,然后其他的功能都通过插件来实现,如Eclipse, Netbeans, Vim/Emacs等那样。
脚本语言的好处有很多:比如接口既定的情况下,无需编译宿主程序,即可直接运行;又比如脚本语言本身的灵活性,以及其他的一些特性,如JS的函数式编程;又比如,脚本语言本身无法完成的功能,如文件读写,网络访问,数据库访问等功能可以通过宿主语言来完成,等等。
仔细想了下。。。是的,用脚本来写程序中可plugin的地方真的不错,无需编译很给力。。。下次有机会尝试下,就不用去写配置文件+实现类来plugin了 哈哈
我觉得这是一个取舍的问题,并没有完美的方案
打个比方哈。。。小弟初学很不解 而且最终脚本也是转为java字节码,除了获得灵活简洁的语法还有其他原因不
就我个人的观点来说,几乎所有地方都可以加入脚本,当然,肯定会有效率,调试等方面的限制,因此我建议你在效率要求不高,而软件需求变化较频繁(考虑到实施等问题,最好使用脚本),或者软件的扩展性,定制性要求较高的场合。举例子的话,比如我上边提到的,编辑器,浏览器,IDE,图形编辑软件,播放器等等,都可以使用脚本。
总的来说,软件开发应该考虑到扩展性,尽量提供一个通用的基础平台,提供足够的接口,然后其他的功能都通过插件来实现,如Eclipse, Netbeans, Vim/Emacs等那样。
脚本语言的好处有很多:比如接口既定的情况下,无需编译宿主程序,即可直接运行;又比如脚本语言本身的灵活性,以及其他的一些特性,如JS的函数式编程;又比如,脚本语言本身无法完成的功能,如文件读写,网络访问,数据库访问等功能可以通过宿主语言来完成,等等。
打个比方哈。。。小弟初学很不解 而且最终脚本也是转为java字节码,除了获得灵活简洁的语法还有其他原因不
你是说例子中的计算器是否支持复杂脚本吗?由于内部使用的rhino引擎,并没有进行任何方面的限制,因此理论上,可以支持任意复杂的脚本。比如自己用JavaScript来实现OO语言系统,利用宿主语言Java的多线程,UI等便利来改善JS应用的性能和外观等。
复杂脚本毫无问题,前年一个项目,业务规则就是用JS写的,跑Rhino
如果是纯解释的话,效率的确很低,但是Java脚本框架中提供CompiledScript接口,如果脚本引擎实现该接口,则可以将脚本预先编译,效率就基本没有问题了。这有点像JDBC中的PreparedStatement,效率就没什么问题了。
还是不够高
虽然可以编译,但它的执行比java慢的不是一个数量级
在很多工作流产品中, 都拿rhino来做迁移的判断以及前后置脚本的执行,在高并发情况下,java执行只要几十或者几百毫秒的时候,js要2秒左右
并且,编译会带来一个问题
有许多js脚本是通过java代码生成的,这就意味着生成的js的长度在某些情况下会很长,当超过64k的时候,编译会失败的
http://hi.baidu.com/freish/blog/item/5d02e450f4dbf24e1138c2ed.html
确实会有此类的问题,这个在之前的项目中遇到过:一个开发人员将JSP文件写的非常大,业务逻辑(很多的条件判断等代码)全部都写在JSP中,最后生成Servlet的时候,超出了方法的长度限制。不过我认为这种情况可以通过设计来避免,比如类/方法的拆分等。也就是说,这并非引擎有什么问题,比如,你手工的将一个Java方法写的超过64k,同样会有这样的问题。
如果是纯解释的话,效率的确很低,但是Java脚本框架中提供CompiledScript接口,如果脚本引擎实现该接口,则可以将脚本预先编译,效率就基本没有问题了。这有点像JDBC中的PreparedStatement,效率就没什么问题了。
还是不够高
虽然可以编译,但它的执行比java慢的不是一个数量级
在很多工作流产品中, 都拿rhino来做迁移的判断以及前后置脚本的执行,在高并发情况下,java执行只要几十或者几百毫秒的时候,js要2秒左右
遇到高并发这种情况,我没有做过实验,可能确实效率较低。毕竟,可能会有诸如校验,类型转换之类的动作,这个我下来再看看。就一般应用(并非服务器如httpd之类)而言,如编辑器,浏览器,IDE等,脚本作为插件的形式存在于应用程序的生命周期中,不会涉及到高并发这类的需求。如果是freish兄所说的这种情况,通常会把代码编译成动态库(C)或者可供虚拟机直接执行的bytecode(Java), 脚本语言本身则无法做到。
如果是纯解释的话,效率的确很低,但是Java脚本框架中提供CompiledScript接口,如果脚本引擎实现该接口,则可以将脚本预先编译,效率就基本没有问题了。这有点像JDBC中的PreparedStatement,效率就没什么问题了。
还是不够高
虽然可以编译,但它的执行比java慢的不是一个数量级
在很多工作流产品中, 都拿rhino来做迁移的判断以及前后置脚本的执行,在高并发情况下,java执行只要几十或者几百毫秒的时候,js要2秒左右
并且,编译会带来一个问题
有许多js脚本是通过java代码生成的,这就意味着生成的js的长度在某些情况下会很长,当超过64k的时候,编译会失败的
http://hi.baidu.com/freish/blog/item/5d02e450f4dbf24e1138c2ed.html
如果是纯解释的话,效率的确很低,但是Java脚本框架中提供CompiledScript接口,如果脚本引擎实现该接口,则可以将脚本预先编译,效率就基本没有问题了。这有点像JDBC中的PreparedStatement,效率就没什么问题了。
还是不够高
虽然可以编译,但它的执行比java慢的不是一个数量级
在很多工作流产品中, 都拿rhino来做迁移的判断以及前后置脚本的执行,在高并发情况下,java执行只要几十或者几百毫秒的时候,js要2秒左右
如果是纯解释的话,效率的确很低,但是Java脚本框架中提供CompiledScript接口,如果脚本引擎实现该接口,则可以将脚本预先编译,效率就基本没有问题了。这有点像JDBC中的PreparedStatement,效率就没什么问题了。
C发明于1972年,知识分子们还在上山下乡,众多的javaeyer还没有出生,现在还不是有大量相关的书籍,文章发表?
Java发明于1991年,改革开放才刚刚真正的开始,众多的javaeyer还没见过计算机,现在还不是天天有相关的文章在出现?
2011年怎么了?呵呵。
发表评论
-
JavaScript内核系列 第15章 服务器端的JavaScript
2012-02-12 21:39 2385第15章已经在icodeit上发布,这一章分为上/下两篇,请朋 ... -
使用vim开发python及graphviz绘图
2011-12-23 14:49 6494基本需求 使用vim中的autocmd命令可以很容易的将正在 ... -
可编程计算器(phoc)的设计与实现
2011-01-17 11:34 2016前言 借助JavaScript脚本 ... -
函数式编程(javascirpt)
2009-04-18 22:18 1291前言 Javascript,有人称 ... -
C和指针
2009-05-21 23:15 1135前言 指针是C的灵魂,正是指针使得C存在了这么多年,而且将长 ... -
C和指针(续)
2009-05-25 23:41 1385前言 上一篇《C和指针》可能对关于C和指针的有些内容没有说透 ... -
有限自动机与建模
2009-06-06 10:48 1830前言 在学校学程序设计语言的时候,能接触到的所有例子没有一个 ... -
事件和监听器
2009-06-21 22:06 1456前言 事件监听器是经 ... -
基于总线的消息服务(BBMS)的设计与实现
2009-07-25 22:19 1371前言 异步事件的通知机制在比较有规模的软件设计中必然会有涉及 ... -
JavaScript内核系列 第9章 函数式的Javascript
2010-05-13 19:20 3817第九章 函数式的Javascript 要说Ja ... -
JavaScript内核系列 第8章 面向对象的JavaScript(下)
2010-05-06 09:40 3681接上篇:JavaScript内核系列 第8章 面向对象的Jav ... -
JavaScript内核系列 第8章 面向对象的JavaScript(上)
2010-05-06 09:26 2930第八章 面向对象的 Javascript ... -
JavaScript内核系列 第7章 闭包
2010-05-04 08:48 3930第七章 闭包 闭包向来给包括JavaScript程序 ... -
JavaScript内核系列 第6章 正则表达式
2010-04-27 19:44 4082第六章 正则表达式 正则表达式是对字符串的结构 ... -
JavaScript内核系列 第5章 数组
2010-04-24 15:17 4599第五章 数组 JavaScript的数组也是一个比较 ... -
Swing小应用(Todo-List)之三
2010-04-22 20:47 2149前言 去年9月份开发的那个小工具sTodo,只是做到了能用, ... -
JavaScript内核系列 第4章 函数
2010-04-18 17:31 5113第四章 函数 函数,在C语言之类的过程式语言中 ... -
JavaScript内核系列 第3章 对象与JSON
2010-04-12 09:12 6181第三章 对象与JSON JavaScript对象与传 ... -
JavaScript内核系列 第2章 基本概念
2010-04-03 19:44 5742第二章 基本概念 ... -
JavaScript内核系列 第1章 前言及概述
2010-04-01 23:15 9980前言 从2006年第一次接触JavaScript至今,算来也 ...
相关推荐
由于标签中提到了“android test”,这可能意味着这个Java脚本是专门为Android应用设计的测试工具,可能使用了如Espresso、Robolectric或Mockito等针对Android平台的测试库。这些库可以帮助开发者模拟用户交互,进行...
总之,Java脚本教程涵盖了如何在Java应用程序中集成和执行脚本语言的各个方面,包括如何发现和实例化脚本引擎,以及如何与不同的脚本环境进行交互。通过学习这些内容,开发者可以更好地利用Java的多语言支持,提高...
虽然描述中没有提供具体信息,但通常介绍一个引入Java脚本API的主题可能涉及如何将脚本引擎集成到Java应用中,以及如何使用这些引擎来执行动态代码。在实际开发中,这可能包括以下步骤: 1. **添加依赖**:为了使用...
本教程聚焦于"JAVA 脚本各种特效",通过JavaScript代码实例来深入理解其在网页动态效果和用户交互方面的应用。 首先,我们来探讨JavaScript的基础。JavaScript是基于ECMAScript规范的,它的核心语法包括变量声明...
Rhino脚本引擎可以嵌入Java应用程序中执行,其最大的特点是脚本的修改不需要重启Java虚拟机(JVM)就能生效,这使得它非常适合在需要频繁更新和测试的场景中使用。Rhino的优势在于它的简单、灵活性以及强大的功能,...
根据给定的信息,“Java脚本编程:语言、框架与模式”这一主题包含了三个核心部分:Java作为一门编程语言的基础知识、流行的Java开发框架以及在Java编程中常用的软件设计模式。 ### Java编程语言 #### 1. Java语言...
主要内容包括:择日与算命的基本概念、神煞在择日中的应用、Java脚本语言的特点及其在数据库操作中的实现。 ### 择日与算命概述 1. **择日**:在中国传统文化中,择日是指选择合适的日子进行某些重要的活动或仪式...
在后续章节(例如第23章)中,会进一步探讨JavaScript在Web浏览器环境中的应用,特别是在Java applet和Java插件中的脚本化Java技术。这涵盖了JavaScript如何在浏览器环境中与Java代码交互,增强了Web应用程序的功能...
《Java脚本语言程序员手册》是一本专门为Java脚本编程者设计的指南,旨在帮助开发者深入理解和高效利用Java脚本语言。手册详细介绍了Java Scripting API(JSR 223)以及相关的脚本框架,如Rhino和Nashorn,这些都是...
《精通Java EE:精通Java EE 整合应用案例\源代码第三章》是关于Java企业级应用开发的深度学习资源,主要聚焦于实际项目中的整合应用。本章内容可能涵盖多个Java EE技术的综合运用,如Servlet、JSP、EJB、JPA、JSF、...
Java Web应用开发技术实用教程是针对大学学习者设计的一本应用教程,主要涵盖了使用Java语言进行Web应用程序开发的各种核心技术。本教程旨在帮助学生和初学者深入理解如何利用Java技术栈构建功能丰富的Web应用。 ...
本书“精通Java EE”显然旨在帮助开发者深入理解和掌握Java EE技术,通过整合应用案例来增强实践能力。光盘案例数据库部分是书中理论知识的实践补充,提供了丰富的实际操作示例,以便读者能够更直观地学习如何在真实...
在IT行业中,脚本特效是Web开发中一个重要的组成部分,特别是在Java和JSP技术的应用上。Java是一种广泛使用的面向对象的编程语言,而JSP(Java Server Pages)是基于Java平台的一种动态网页技术,它允许开发者将静态...
Java脚本API设计用于在Java应用程序中嵌入脚本引擎的能力,无需依赖具体的脚本语言。这一API的核心价值在于提供了一种灵活的方式,使得开发者能够根据实际需求选择最适合项目的脚本语言,同时也允许最终用户根据个人...
Java 8 Nashorn脚本引擎是Java平台上的一个强大工具,它允许开发者在Java应用程序中直接执行JavaScript代码。Nashorn引擎是Oracle公司为Java 8引入的一个重要特性,其目的是提升Java与JavaScript之间的互操作性,...
标题中的“用BeanShell来运行Java脚本”指的是利用BeanShell这个开源库在Java环境中执行动态的、交互式的Java代码。BeanShell是一个轻量级的Java Scripting引擎,它允许你在运行时执行Java代码,无需编译,极大地...
【标题】"JAVA PHP的应用实例"揭示了这个压缩包文件主要涵盖了使用Java和PHP两种编程语言在实际web开发中的应用。Java和PHP都是广泛应用于Web开发的后端编程语言,它们各自具有不同的特点和优势。 Java,作为一种...