这是我参与8月更文挑战的第27天,活动详情查看:8月更文挑战
调用脚本函数
在 java 中调用 script 函数也同样支持:
package com.googlecode.aviator.example.scripting;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class InvokeScriptFunction {
public static void main(final String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("AviatorScript");
// AviatorScript code in a String
String script = "fn 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 AviatorScript engine implements Invocable interface.
Invocable inv = (Invocable) engine;
// invoke the global function named "hello"
inv.invokeFunction("hello", "Scripting!!" );
}
}
我们在脚本里定义了 hello
函数,然后通过 Invocable
接口就可以在 java 代码里调用并传入参数:
Hello, Scripting!!
在 AviatorScript 中可以使用 map 和闭包来模拟面向对象编程,同样,我们可以在 java 代码里调用 AviatorScript 中“对象”的方法:
package com.googlecode.aviator.example.scripting;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class InvokeScriptMethod {
public static void main(final String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("AviatorScript");
// AviatorScript code in a String. This code defines a script object 'obj'
// with one method called 'hello'.
String script =
"let obj = seq.map(); obj.hello = lambda(name) -> print('Hello, ' + name); end;";
// evaluate script
engine.eval(script);
// javax.script.Invocable is an optional interface.
// Check whether your script engine implements or not!
// Note that the AviatorScript 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 !!");
}
}
我们定义了对象 obj
,它有一个方法 hello(name)
,在 java 代码里通过 engine.get("obj")
获取该对象,然后通过 Invocable
接口调用 invokeMethod(obj, 方法名,方法参数列表)
就可以调用到该对象的方法。
使用脚本实现 Java 接口
我们可以用 AviatorScript 脚本实现 java 中的接口,然后将函数或者对象方法转成该接口在 java 代码里使用,比如我们用 AviatorScript 实现 Runnable
接口:
package com.googlecode.aviator.example.scripting;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class RunnableImpl {
public static void main(final String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("AviatorScript");
// AviatorScript code in a String
String script = "fn run() { println('run called'); }";
// evaluate script
engine.eval(script);
Invocable inv = (Invocable) engine;
// get Runnable interface object from engine. This interface methods
// are implemented by script functions with the matching name.
Runnable r = inv.getInterface(Runnable.class);
// start a new thread that runs the script implemented
// runnable interface
Thread th = new Thread(r);
th.start();
}
}
我们在 AviatorScript 实现了一个 run()
函数, 接下来就可以从引擎里获取一个 Runnable
接口实现,它会自动去调用已定义的 run 函数并执行,然后我们将获取的 Runnable 实例用在了线程里:
run called
不仅是函数,对于“对象”也同样可以的:
package com.googlecode.aviator.example.scripting;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class RunnableImplObject {
public static void main(final String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("AviatorScript");
// AviatorScript code in a String
String script =
"let obj = seq.map(); obj.run = lambda() -> println('run method called'); end; ";
// evaluate script
engine.eval(script);
// get script object on which we want to implement the interface with
Object obj = engine.get("obj");
Invocable inv = (Invocable) engine;
// get Runnable interface object from engine. This interface methods
// are implemented by script methods of object 'obj'
Runnable r = inv.getInterface(obj, Runnable.class);
// start a new thread that runs the script implemented
// runnable interface
Thread th = new Thread(r);
th.start();
}
}
你可以将某个对象的方法转成特定接口的实现。
多 Scope 支持
在上面的注入变量一节,我们注入了全局变量,Scripting API 也支持多个全局变量环境同时执行,相互隔离,这是通过 ScriptContext
实现,你可以把他理解成一个类似 Map<String, Object>
的映射:
package com.googlecode.aviator.example.scripting;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.SimpleScriptContext;
public class MultiScopes {
public static void main(final String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("AviatorScript");
engine.put("x", "hello");
// print global variable "x"
engine.eval("println(x);");
// the above line prints "hello"
// Now, pass a different script context
ScriptContext newContext = new SimpleScriptContext();
Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE);
// add new variable "x" to the new engineScope
engineScope.put("x", "world");
// execute the same script - but this time pass a different script context
engine.eval("println(x);", newContext);
// the above line prints "world"
}
}
在 newContext
的 engine 级别绑定里我们重新定义了 x 为 world
字符串,并传入 eval
执行,两者打印的结果将不同:
hello
world