本文将分以下几个小节来学习:
作用域
上例中"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编译并没有任何意义,只是作为演示使用。一般把重复执行的脚本编译,以提高性能。