Java语言是一种静态类型的编程语言,静态类型的含义是指在编译时进行类型检查。Java源代码中的每个变量的类型都需要显式地进行声明。所有变量、方法的参数和返回值的类型在程序运行之前就必须是已知的。与静态类型语言相对应的是动态类型语言,如javaScript和Ruby等。动态类型语言的类型检查是在运行时进行。源代码不需要显式地声明类型。这样就可以减少开发人员需要编写的代码量。这也是动态语言得以流行的一个原因。
在JSR223(Scripting for the java platform)中规范了在java虚拟机上运行的脚本语言与java程序之间的交互方式。JSR223是java6的一部分,在java标准API中的包是javax.script
一、 获取到脚本引擎有三种方式:
(1)通过文件拓展名获取
ScriptEngine engine =ScriptEngineManager().getEngineByExtension("js");
(2)通过脚本名称获取
ScriptEngine engine= new ScriptEngineManager().getEngineByName("JavaScript");
(3)通过MIME类型来获取
ScriptEngine engine = new ScriptEngineManager().getEngineByMimeType("text/javascript");
注意:下面用到的
getJavaScriptEngine(); 方法都是这个方法
public static ScriptEngine getJavaScriptEngine() {
return new ScriptEngineManager().getEngineByExtension("js");
}
二、一个脚本引擎的一般写法:
public static void useDefaultBinding() throws ScriptException {
ScriptEngine engine = getJavaScriptEngine();
engine.put("name", "weiguang");
engine.eval("var message='Hello,'+name;");
engine.eval("println(message);");
Object obj = engine.get("message");
System.err.println(obj);
}
三、语言绑定
(1) 脚本引擎默认的语言绑定对象示例
public static void greet() throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
// 通过脚本名称获取
ScriptEngine engine = manager.getEngineByName("JavaScript");
if (engine == null) {
throw new RuntimeException("找不到JavaScript语言执行引擎");
}
engine.eval("println('Hello weiguang!');");
}
(2)自定义语言绑定对象示例
public static void useCustomeBinding()throws ScriptException{
ScriptEngine engine=getJavaScriptEngine();
Bindings bindings=new SimpleBindings();
bindings.put("hobby","playing basketball!");
engine.eval("println('I like'+hobby);",bindings);
}
四、脚本执行上下文
与脚本引擎执行相关的另外一个重要的接口是javax.script.ScriptContext,其中包含脚本引擎执行过程中相关上下文信息。也允许开发人员通过此对象来配置脚本引擎的行为。该上下文对象中主要包含以下3类信息。
(1)输入与输出
public static void scriptToFile()throws IOException,ScriptException{
ScriptEngine engine=getJavaScriptEngine();
ScriptContext context=engine.getContext();
context.setWriter(new FileWriter("C:\\Users\\Administrator\\Desktop\\output.txt"));
engine.eval("println('Hello world!');");
}
(2)自定义属性
ScriptContext中也有与ServletContex中类似的获取和设置属性的方法,即setAttribute和getAttribute。所不同的是,ScriptContext中属性是有作用域之分的,常量ScriptContext.ENGINE_SCOPE表示的作用域对应的是当前的脚本引擎,而ScriptContext.GLOBAL_SCOPE表示的作用域对应的是从同一引擎工厂创建出来的所有脚本引擎对象,前者的优先级较高。
public static void scriptContextAttribute() throws ScriptException{
ScriptEngine engine=getJavaScriptEngine();
ScriptContext context= engine.getContext();
context.setAttribute("name","Alex",ScriptContext.GLOBAL_SCOPE);
context.setAttribute("name", "Bob", ScriptContext.ENGINE_SCOPE);
context.getAttribute("name"); //值为Bob
engine.eval("println(name);");//检测是否为Bob
}
结果输出为:Bob。
(3)语言绑定对象
public static void myScriptContextBindings() throws ScriptException {
ScriptEngine engine = getJavaScriptEngine();
ScriptContext context = engine.getContext();
Bindings bindings1 = engine.createBindings();
bindings1.put("name", "Alex");
context.setBindings(bindings1, ScriptContext.GLOBAL_SCOPE);
Bindings bindings2 = engine.createBindings();
bindings2.put("name", "Bob");
context.setBindings(bindings2, ScriptContext.ENGINE_SCOPE);
engine.eval("println(name);"); //Bob
}
五、脚本的编译
脚本语言一般是解释执行的。脚本引擎在运行时需要先解释脚本之后再执行。一般来说,通过解释执行的方式来运行脚本的速度比编译之后再运行会慢一点。当一段程序
需要被多次重复执行时,可以先对脚本进行编译,那么这样就可以提高性能优势。
//进行脚本编译方法
public static CompiledScript compile(String scriptText)throws ScriptException{
ScriptEngine engine=getJavaScriptEngine();
if(engine instanceof Compilable){
CompiledScript script=((Compilable)engine).compile(scriptText);
return script;
}
return null;
}
//执行脚本引擎编译js语言,当所用的脚本js要执行多次时,那么用脚本编译后的程序,性能更具优势
public static void run(String scriptText)throws ScriptException{
CompiledScript script=compile(scriptText);
if(script==null){
return;
}
for(int i=0;i<100;i++){
script.eval();
}
}
六、方法调用
(1)在java中调用脚本中顶层方法的示例
//调用脚本中的方法
public static void invokeFunction()throws ScriptException,NoSuchMethodException{
ScriptEngine engine=getJavaScriptEngine();
String scriptText="function greet(name){println('Hello,'+name);}";
engine.eval(scriptText);
Invocable invocable=(Invocable)engine;
invocable.invokeFunction("greet", "weiguang");
}
(2)在java中调用脚本中对象成员方法的示例
//调用脚本中对象的成员方法示例
public static void invokeMethod()throws ScriptException,NoSuchMethodException{
ScriptEngine engine=getJavaScriptEngine();
String scriptText="var obj={"
+ "getGreeting:function(name){return 'hello,'+name}}";
engine.eval(scriptText);
Invocable invocable=(Invocable)engine;
Object scope=engine.get("obj");
Object result=invocable.invokeMethod(scope, "getGreeting", "weiguang");
System.err.println(result);
}
(3)在java中实现java接口示例
(3.1)创建接口代码示例
public interface Greet {
public String getGreeting(String name);
}
(3.2)实现java接口示例
//在有些脚本引擎中,可以再java语言中定义接口,并在脚本中编写接口的实现。这样程序中的其他部分
//可以只同java接口交互,并不需要关心接口是由什么方式来实现的
public static void useInterface()throws ScriptException{
ScriptEngine engine=getJavaScriptEngine();
String scriptText="function getGreeting(name){ return 'Hello,'+name;}";
engine.eval(scriptText);
Invocable invocable=(Invocable)engine;
Greet greet=invocable.getInterface(Greet.class);
System.out.println(greet.getGreeting("weiguang"));
}
以上所贴代码都是经过实验验证,有需要源代码的同学可以给我留言!由于水平有限,文中有啥不妥的地方可以给我留言,谢谢大家。