JAVA的嵌入式脚本开发(下)

本文将分以下几个小节来学习:

作用域

上例中"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编译并没有任何意义,只是作为演示使用。一般把重复执行的脚本编译,以提高性能。

原文地址:https://www.cnblogs.com/zhaiqianfeng/p/4618265.html