这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战
使用 Java 自定义模块
除了可以用 AviatorScript 来定义模块之外,也可以用 Java 来定义。 Java 实现模块就是一个普通的 Java 类,它的所有静态方法将作为模块方法提供。
我们来实现一个最简单的 str
模块:
@Import(ns = "str")
public static class StringModule {
public static boolean isBlank(final String s) {
return s == null || s.trim().length() == 0;
}
}
Import
annotation 指定了模块的 namespace 名称为 str
,提供了一个静态方法 isBlank(s)
来判断字符串是否是空白的。
接下来我们使用 addModule
来添加模块到执行引擎:
AviatorEvaluator.getInstance().addModule(StringModule.class);
添加之后,就可以用 require
来加载模块,并在脚本里使用:
String script = "let str = require('str'); str.isBlank(s) ";
System.out.println(AviatorEvaluator.execute(script, AviatorEvaluator.newEnv("s", "hello")));
System.out.println(AviatorEvaluator.execute(script, AviatorEvaluator.newEnv("s", " ")));
System.out.println(AviatorEvaluator.execute(script, AviatorEvaluator.newEnv("s", null)));
输出 :
false
true
true
你可以使用类似的方法来自定义模块。
Java Scripting API 支持
在 6.3 节我们看到了如何在 AviatorScript 中调用 Java 函数,这里我们将介绍如何用 Java 提供的脚本 API 来调用 AviatorScript 脚本中的函数等。
AviatorScript 内置了对 ****Java Scripting API 的支持,并且提供了 AviatorScriptEngineFactory
的 SPI 实现,只要你的 classpath 包含了 aviator 的 jar 引用,就可以直接使用。我们来看一些例子(所有示例代码在源码 example 的 scripting 目录)。
获取执行引擎
通过 ScriptEngineManager
可以获得 AviatorScript 的执行引擎:
package com.googlecode.aviator.example.scripting;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class ScriptEngineExample {
public static void main(final String[] args) {
final ScriptEngineManager sem = new ScriptEngineManager();
ScriptEngine engine = sem.getEngineByName("AviatorScript");
}
}
接下来我们将使用这个 engine 做各种例子演示。
配置执行引擎
可以从 ScriptEngine
里获取底层的 AviatorEvaluatorInstance
引用,进行引擎的相关配置:
package com.googlecode.aviator.example.scripting;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import com.googlecode.aviator.AviatorEvaluatorInstance;
import com.googlecode.aviator.Feature;
import com.googlecode.aviator.Options;
import com.googlecode.aviator.script.AviatorScriptEngine;
public class ConfigureEngine {
public static void main(final String[] args) throws Exception {
final ScriptEngineManager sem = new ScriptEngineManager();
ScriptEngine engine = sem.getEngineByName("AviatorScript");
AviatorEvaluatorInstance instance = ((AviatorScriptEngine) engine).getEngine();
// Use compatible feature set
instance.setOption(Options.FEATURE_SET, Feature.getCompatibleFeatures());
// Doesn't support if in compatible feature set mode.
engine.eval("if(true) { println('support if'); }");
}
}
默认的引擎处于下列模式:
- 全语法特性支持
- 缓存编译模式
求值
最简单的,你可以直接执行一段 AviatorScript 脚本,调用 eval(script)
方法即可
package com.googlecode.aviator.example.scripting;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class EvalScriptExample {
public static void main(final String[] args) throws Exception {
final ScriptEngineManager sem = new ScriptEngineManager();
ScriptEngine engine = sem.getEngineByName("AviatorScript");
engine.eval("print('Hello, World')");
}
}
这将打印 Hello, World
到控制台,调用了 print 函数,
如果你的脚本是文件,也可以用 eval(reader)
方法:
import javax.script.*;
public class EvalFile {
public static void main(String[] args) throws Exception {
// create a script engine manager
ScriptEngineManager factory = new ScriptEngineManager();
// create AviatorScript engine
ScriptEngine engine = factory.getEngineByName("AviatorScript");
// evaluate AviatorScript code from given file - specified by first argument
engine.eval(new java.io.FileReader(args[0]));
}
}
文件名通过执行的第一个参数指定。
默认引擎处于缓存表达式模式。
注入变量
可以注入全局变量到脚本,并执行:
package com.googlecode.aviator.example.scripting;
import java.io.File;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class ScriptVars {
public static void main(final String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("AviatorScript");
File f = new File("test.txt");
// expose File object as variable to script
engine.put("file", f);
// evaluate a script string. The script accesses "file"
// variable and calls method on it
engine.eval("print(getAbsolutePath(file))");
}
}
这里我们将文件 f
通过 engine.put
方法作为全局变量注入,然后执行脚本 print(getAbsolutePath(file))
,打印文件的绝对路径。
默认引擎启用了基于 java 反射的方法调用模式。