Rhino脚本引擎技术介绍 您所在的位置:网站首页 犀牛介绍英文翻译 Rhino脚本引擎技术介绍

Rhino脚本引擎技术介绍

2024-07-01 12:06| 来源: 网络整理| 查看: 265

 

 

Rhino是一个开源的脚本引擎框架,可以运行类似javascript语法的脚本,并可以调用java的方法,并可以嵌入Java执行,脚本修改后不需要重启JVM进程,就可以使用解析或编译方式执行,非常方便。由于Rhino脚本中可以写入任何表达式和javacript程序,既可以进行条件规则的判断,也可以进行各类简单或复杂的计算,因此是BPS中以前参与者规则和连线规则的一个良好替代方案,在某银行新一代流程平台中,我们使用了Rhino脚本引擎来替代以前基于Antlr词法分析器的规则引擎。

 

 

由于Rhino的灵活和强大的功能,从JDK1.6开始,JDK将Rhino开源软件纳入JDK内部API中,形成了以javax.script为包名的脚本引擎API。

 

 

使用Rhino有如下好处:

1、实现简单,灵活,功能强大,对比以前BPS规则用的Antlr词法分析器,实现更加简单,不需要进行规则文件编辑和代码生成(而且对不同规则需要生成多套代码,很不灵活),脚本引擎可以进行几乎任何运算或Java调用,能满足某银行新一代流程平台的要求。

2、即时生效,修改脚本后不用重启Java进程就可以立即生效运行。

3、有编译和解析两种运行方式,编译方式在大量并发的调用情况下性能更好。

4、轻量,JDK内置,不需要引入其他第三方jar。

 

 

下面主要介绍JDK内置的Rhino脚本引擎,以及其javax.script的API用法。

翻开JDK1.6的javax.script的API,可以看到脚本API中只包含6个接口和6个类(其中一个还是一个异常),整个API非常简单易用。

 

主要的类图如下(类图做了一些省略,对一些不常用的类和接口省略了,并只显示了主要的方法):

 

 

Bindings接口可以理解为上下文,可以往上下文中设置一个Java对象或通过key获取一个对象,它有一个实现类,SimpleBindings,内部就是一个map。

 

上下文是给脚本引擎执行脚本时使用的,脚本引擎在执行脚本的时候,用到上下文中放置的Java对象,执行其方法,使用其属性。

 

ScriptEngine接口就是脚本引擎,用于执行脚本计算结果的接口,其实现类是AbstractScriptEngine和底层的RhinoScriptEngine,这些类是脚本引擎的核心类。eval(String script)和eval(String script, Bindings n)两个方法就是执行一段脚本返回计算结果的两个方法,第二个方法会传入上下文,即运行脚本时,脚本需要使用上下文中设置的Java变量的方法或属性。

 

上下文是有范围的,分三种范围:

 

   全局的:所有脚本引擎都可以使用的,由ScriptContext. GLOBAL_SCOPE常量来定义其范围的名称。ScriptEngine.getBindings(ScriptContext.GLOBAL_SCOPE)可以获GLOBAL取这类上下文。    引擎即的:只是一个脚本引擎可以使用的,由ScriptContext. ENGINE_SCOPE常量来定义其范围的名称。ScriptEngine.getBindings(ScriptContext.ENGINE_SCOPE)可以获取这类上下文。    局部的:引擎的一次计算用到的Bindings,没有常量定义,ScriptEngine.createBindings()创建的就是这类上下文。

 

 

ScriptEngineManager可以认为是脚本引擎的一个管理类或工厂,一般我们获取javascript脚本引擎时,会调用这个类实例的getEngineByName("js")方法来获得支持js语法的脚本引擎。

 

脚本引擎在执行脚本的时候有两种方式:

 

   解释执行:直接运行ScriptEngine的eval方法    编译执行:运行CompiledScript的eval方法,脚本引擎的内部实现类RhinoScriptEngine又实现了Compilable接口,可以将脚本语句编译成编译后脚本(CompiledScript),CompiledScript可以直接运行eval方法,进行编译方式的脚本执行。

 

 

按理来说,编译执行要快于解释执行,但在实际的测试中发现,只有在大量计算的情况下(循环次数在1-10万以上),编译执行快于解释执行,否则,解释执行可能更快。

 

下面举例说明脚本引擎的基本用法:

 

 

   进行简单的脚本表达式计算:

package demo.scriptengine; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; public class SimpleScript { public static void main(String[] args) throws ScriptException { ScriptEngineManager seManager=new ScriptEngineManager(); ScriptEngine se=seManager.getEngineByName("js"); Object ret=se.eval("3+4;"); System.out.println(ret); } }计算结果打印出7.0.

 

 

   使用Bindings上下文计算

package demo.scriptengine; import javax.script.Bindings; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; public class ScriptUsingBindings { public static void main(String[] args) throws ScriptException { ScriptEngineManager seManager=new ScriptEngineManager(); ScriptEngine se=seManager.getEngineByName("js"); Bindings bindings=se.createBindings(); bindings.put("user", new User("张三",19)); Object ret=se.eval("print(user.getName()); if(user.age>=18) '已成年'; else '未成年';",bindings); System.out.println(ret); } }User是一个对象,用name和age两个属性和getName()和getAge()两个方法,在脚本中使用user.age和user.getAge()都可以。

 

   计算后结果返回:张三已成年

   以上两个例子都是使用解释方式进行计算,下面的例子使用编译的方式进行计算。

 

   使用编译方式进行计算。

package demo.scriptengine; import javax.script.Bindings; import javax.script.Compilable; import javax.script.CompiledScript; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; public class CompiledUsingBindings { public static void main(String[] args) throws ScriptException { ScriptEngineManager seManager=new ScriptEngineManager(); ScriptEngine se=seManager.getEngineByName("js"); Compilable ce=(Compilable)se; String script="println(user.getName()+'的年龄为'+user.getAge());if(user.age>=18) '已成年'; else '未成年';"; CompiledScript cs=ce.compile(script); Bindings bindings=se.createBindings(); bindings.put("user", new User("张三",19)); Object ret=cs.eval(bindings); System.out.println(ret); } }控制台打印出:

 

   张三的年龄为19

   已成年

   注意:print,println是脚本引擎内置函数,是向控制台打印输出。

 

   解释方式执行javascript函数

package demo.scriptengine; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; public class JSFunc { public static void main(String[] args) throws ScriptException { ScriptEngineManager seManager=new ScriptEngineManager(); ScriptEngine se=seManager.getEngineByName("js"); String script="function sum(a,b) { return a+b; }"; se.eval(script); Object ret=se.eval("sum(3,4)"); System.out.println(ret); } }返回结果为7.0

 

   se.eval(script);

   Object ret=se.eval("sum(3,4)");

   这种语法和"function sum(a,b) { return a+b; } sum(3,4);"语法相同。

 

   编译方式执行javascript函数

package demo.scriptengine; import javax.script.Bindings; import javax.script.Compilable; import javax.script.CompiledScript; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; public class JSFuncCompiled { public static void main(String[] args) throws ScriptException { ScriptEngineManager seManager=new ScriptEngineManager(); ScriptEngine se=seManager.getEngineByName("js"); Compilable ce=(Compilable)se; String script="function sum(a,b) { return a+b; } sum(a,b);"; CompiledScript cs=ce.compile(script); Bindings bindings=se.createBindings(); bindings.put("a", 3); bindings.put("b", 4); Object ret=cs.eval(bindings); System.out.println(ret); } }   返回结果为7.0

 

   JS函数调用的高级用法

package demo.scriptengine; import javax.script.*; public class InvokeScriptFunction { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("JavaScript"); // JavaScript code in a String String script = "function hello(name) { print('Hello, ' + name); }"; // evaluate script engine.eval(script); // javax.script.Invocable is an optional interface. // Check whether your script engine implements or not! // Note that the JavaScript engine implements Invocable interface. Invocable inv = (Invocable) engine; // invoke the global function named "hello" inv.invokeFunction("hello", "Scripting!!" ); } }函数使用高级用法2,调用对象的方法。 package demo.scriptengine; import javax.script.*; public class InvokeScriptMethod { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("JavaScript"); // JavaScript code in a String. This code defines a script object 'obj' // with one method called 'hello'. String script = "var obj = new Object(); obj.hello = function(name) { print('Hello, ' + name); }"; // evaluate script engine.eval(script); // javax.script.Invocable is an optional interface. // Check whether your script engine implements or not! // Note that the JavaScript engine implements Invocable interface. Invocable inv = (Invocable) engine; // get script object on which we want to call the method Object obj = engine.get("obj"); // invoke the method named "hello" on the script object "obj" inv.invokeMethod(obj, "hello", "Script Method !!" ); } }调用js文件 package demo.scriptengine.calljava; import java.io.FileReader; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; public class ListFileTest { public static void main(String[] args){ ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("js"); String jsFilename="listFiles.js"; try { engine.eval(new FileReader(jsFilename)); } catch (Exception e) { e.printStackTrace(); } } } listFiles.js内容如下: importClass(java.io.File); var rootDir = new File("c:/"); var files = rootDir.listFiles(); var fixlength=40; for(var i=0;i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有