Рекомендуемый подход для вызова функций (использовать CompiledScript или нет?)
Я пишу библиотеку, которая предлагает поддержку макросов для выполнения на различных языках, не являющихся Java, на JVM. Подумайте о JavaScript, Ruby и т. Д.
Поэтому я хочу использовать API сценариев JSR-223.
Этот API имеет понятие CompiledScript
класс, и я предполагаю, что это будет наилучшим способом предварительной компиляции сценариев во время загрузки и их повторного использования при выполнении.
Это хорошая практика, чтобы проверить, если ScriptEngine
это экземпляр 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;
}