我正在编写一个库,它提供宏支持以在 JVM 上以各种非 Java 语言执行。想想 JavaScript、Ruby 等。
因此我想使用 JSR-223 Scripting API。
这个 API 有一个CompiledScript
类的概念,我认为这将是在加载时预编译脚本并在执行时重新使用它们的最佳方式。
ScriptEngine
检查是否是 instanceof是否是一个好习惯,如果是Compilable
,则使用一种CompiledScript
方法,否则只评估函数ScriptEngine
本身?
例如(简化):
Invocable invocable;
if (scriptEngine instanceof Compilable) {
// Compile the code.
CompiledScript compiledFunction = ((Compilable) scriptEngine).compile(function);
compiledFunction.eval();
invocable = (Invocable) compiledFunction.getEngine();
} else {
// Run the code to load the function into the script engine.
scriptEngine.eval(function);
invocable = (Invocable) scriptEngine;
}
Object value = invocable.invokeFunction(resolveFunctionName(name), args);
return value != null ? value.toString() : null;
在这种情况下,使用 有好处CompiledScript
还是可以忽略不计?
我的实际实现稍微高级一点,并且有一个单独的加载和调用模式来重用实际的CompiledScript
:
public void load(String name, String[] code) {
if (scriptEngine == null) {
logger.warn("Cannot load macro '{}' as no script engine was found for '{}'", name, scriptEngineShortName);
} else {
// Create a unique function name called the same as the object macro name.
String function = resolveFunctionCode(name, code);
try {
if (scriptEngine instanceof Compilable) {
// Compile the code.
CompiledScript compiledFunction = ((Compilable) scriptEngine).compile(function);
compiledFunction.eval();
compiledFunctions.put(name, compiledFunction);
} else {
// Run the code to load the function into the script engine.
scriptEngine.eval(function);
}
} catch (ScriptException e) {
logger.error("Error loading code for marco '{}'", name, e);
}
}
}
public String call(String name, String[] fields) {
String result = null;
if (scriptEngine == null) {
logger.warn("Cannot call macro '{}' as no script engine was found for '{}'", name, scriptEngineShortName);
} else {
try {
Invocable invocable = null;
if (scriptEngine instanceof Compilable) {
if (compiledFunctions.containsKey(name)) {
CompiledScript compiledFunction = compiledFunctions.get(name);
invocable = (Invocable) compiledFunction.getEngine();
}
} else {
invocable = (Invocable) scriptEngine;
}
if (invocable != null) {
Object value = invocable.invokeFunction(resolveFunctionName(name), rs, fields);
if (value != null) {
result = value.toString();
}
} else {
logger.warn("Cannot call macro '{}' as no function was found", name);
}
} catch (ScriptException e) {
logger.error("Error invoking function for macro '{}'", name, e);
} catch (NoSuchMethodException e) {
logger.error("Error invoking function for macro '{}'", name, e);
}
}
return result;
}