本文将分以下几个小节来学习:
作用域
上例中"ScriptContext.GLOBAL_SCOPE"就是作用域。
ScriptContext的属性以及Bindings接口对象都有作用域属性。作用域有优先级,优先级高的作用域先查找。在获取属性或Bindings键值对时也可以设置要查找的作用域。
ScriptContext中预定义的有两个作用域ScriptContext.ENGINE_SCOPE和ScriptContext.GLOBAL_SCOPE。前者表示的作用域对应的是当前脚本引擎,优先级高;后者表示的 作用域对应的是从同一引擎工厂中创建出来的所有脚本引擎对象,优先级低。
package net.oseye; import java.io.*; import javax.script.*; public class ScriptTest { public static void main(String[] args) throws ScriptException, IOException { ScriptEngineManager factory=new ScriptEngineManager(); ScriptEngine se=factory.getEngineByName("JavaScript"); ScriptContext sc=se.getContext(); sc.setAttribute("name", "osEye", ScriptContext.ENGINE_SCOPE); sc.setAttribute("name", "kevin", ScriptContext.GLOBAL_SCOPE); se.eval("println(name)"); System.out.println(sc.getAttribute("name")); System.out.println(sc.getAttribute("name",ScriptContext.GLOBAL_SCOPE)); Bindings bindings=se.getBindings(ScriptContext.ENGINE_SCOPE); bindings.put("age", "10"); se.eval("println(age);"); } }
输出:
osEye osEye kevin 10
方法的调用
如果脚本中的方法支持在在Java中调用,那么这种脚本引擎必须实现javax.script.Invocable接口。通过Invocable接口可以调用脚本中的顶层方法,也可以调用对象的成员方法。而JavaScript引擎是实现了Invocable接口的,我们来看看。
package net.oseye; import javax.script.*; public class ScriptTest { public static void main(String[] args) throws NoSuchMethodException, ScriptException { ScriptEngineManager factory=new ScriptEngineManager(); ScriptEngine se=factory.getEngineByName("JavaScript"); //脚本顶层方法 se.eval("function greet(name){println('Hello,'+name);}"); Invocable invocable=(Invocable) se; invocable.invokeFunction("greet", "kevin"); //脚本中对象的方法 se.eval("var obj={greet:function(name){return 'Hello,'+name;}}"); invocable=(Invocable)se; Object object=se.get("obj"); Object res=invocable.invokeMethod(object, "greet", "kevin"); System.out.println(res); } }
输出:
Hello,kevin Hello,kevin
invokeFunction和invokeMethod方法基本一样,只是invokeMethod要指定包含待调用方法的对象。
如果脚本语言中实现了Java的接口,在Java中就可以调用脚本中方法,使与Java接口交互的应用不用关心接口是由什么方式来实现的,如:
package net.oseye; import javax.script.*; public class ScriptTest { public static void main(String[] args) throws NoSuchMethodException, ScriptException { ScriptEngineManager factory=new ScriptEngineManager(); ScriptEngine se=factory.getEngineByName("JavaScript"); se.eval("function sayHello(name){return 'Hello,'+name;}"); Invocable invocable=(Invocable) se; Greet greet=invocable.getInterface(Greet.class); String res=greet.sayHello("kevin"); System.out.println(res); se.eval("var obj={sayHello:function(name){return 'Hello,'+name;}}"); invocable=(Invocable) se; greet=invocable.getInterface(se.get("obj"), Greet.class); res=greet.sayHello("osEye"); System.out.println(res); } } interface Greet{ String sayHello(String name); }
输出:
Hello,kevin Hello,osEye
编译脚本
脚本语言一般都是解释执行的,如果需要执行的更快的可以把脚本编译。只要脚本引擎时间了javax.script.Compilable接口,就可以把脚本编译。
package net.oseye; import javax.script.*; public class ScriptTest { public static void main(String[] args) throws NoSuchMethodException, ScriptException { ScriptEngineManager factory=new ScriptEngineManager(); ScriptEngine se=factory.getEngineByName("JavaScript"); if(se instanceof Compilable){ CompiledScript script=((Compilable) se).compile("println('kevin test compiel')"); script.eval(); }else{ System.out.println("脚本引擎不支持编译"); } } }
当然这个Demo编译并没有任何意义,只是作为演示使用。一般把重复执行的脚本编译,以提高性能。