Добавить CompiledScript или добавить два CompiledScript

Привет я пользуюсь Groovy двигатель для оценки определенного сценария. Проблема в том, что время выполнения немного велико, поэтому я хочу разделить свой сценарий на два сценария. Первый является статическим и может быть скомпилирован внутри @PostConstruct Метод, а второй является переменной, и это зависит от некоторых параметров, которые выбирает пользователь. Вот что я хочу сделать:

Bindings bindings;
CompiledScript scriptC;
String script1="Static Script";
String script2="Variable Script";
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("groovy");
scriptC = ((Compilable) engine).compile(script1); 
//Execute some instruction to generate 'script2'
scriptC += ((Compilable) engine).compile(script2);//Please note the += operator

или же

Bindings bindings;
CompiledScript scriptC;
String script1="Static Script";
String script2="Variable Script";
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("groovy");
scriptC = ((Compilable) engine).compile(script1); 
//Execute some instruction to generate 'script2'
scriptC.append(((Compilable) engine).compile(script2));//Please note the append function

Эти два кода не работают наверняка, я использовал их только для иллюстрации того, что я пытаюсь сделать. Можно ли объединить два скрипта в один?

1 ответ

Решение

Вы не можете объединить, как эти два CompiledScript объекты. Если речь идет о Groovy - когда скрипт Groovy компилируется, он создает класс, который расширяет groovy.lang.Script с несколькими методами внутри. В этом случае добавление двух сценариев друг к другу означает объединение двух классов Java.

Рассмотрим оценку обоих сценариев в качестве альтернативы. Посмотрите на следующий пример:

import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleBindings;

public class ScriptTest {

    public static void main(String[] args) throws ScriptException {
        final ScriptEngineManager manager = new ScriptEngineManager();
        final ScriptEngine engine = manager.getEngineByName("Groovy");

        final Bindings bindings = new SimpleBindings();
        bindings.put("a", 3);

        final String script1 = "println 'Running first script...'; def c = 2; def d = c + a; return d";
        final CompiledScript compiledScript1 = ((Compilable) engine).compile(script1);

        //Execute some instruction to generate 'script2'
        final String script2 = "println 'Running second script...';";
        final CompiledScript compiledScript2 = ((Compilable) engine).compile(script2);

        Integer returnedValue = (Integer) compiledScript1.eval(bindings);
        System.out.println("Returned value from the first script: " + returnedValue);

        if (returnedValue > 1) {
            compiledScript2.eval(bindings);
        }
    }
}

Создание CompiledScript объект это одно. Во-вторых, оценка этих сценариев. Если вы всегда оцениваете script1 а также script2 сразу же, тогда вам просто нужно:

compiledScript1.eval(bindings);
compiledScript2.eval(bindings);

тем не мение script1 может вернуть некоторое значение и на основании этого значения вы можете решить, если script2 должны быть оценены. Скажем script1 возвращает Integer и я буду оценивать script2 только если возвращаемое значение больше 1:

Integer returnedValue = (Integer) compiledScript1.eval(bindings);
if (returnedValue > 1) {
    compiledScript2.eval(bindings);
}

В качестве альтернативы вы можете основываться на значениях привязок после запуска script1, Скажем script1 изменяет привязки a а также b и установите оба true (при условии, что они держат boolean тип):

compiledScript1.eval(bindings);
if (bindings.get("a") && bindings.get("b")) {
    compiledScript2.eval(bindings);
}

Вызов функции, определенной в script1 от script2

Скажем script1 определяется следующим образом:

import groovy.json.JsonOutput

def json(Map map) {
    return new JsonOutput().toJson(map)
}

println json([test: 1])

В случае, если вам нужно позвонить json(map) функция внутри script2 - ты можешь это сделать. Взгляните на этот пример:

import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleBindings;

public class ScriptTest {

    public static void main(String[] args) throws ScriptException {
        final ScriptEngineManager manager = new ScriptEngineManager();
        final ScriptEngine engine = manager.getEngineByName("Groovy");

        final Bindings bindings = new SimpleBindings();
        bindings.put("a", 3);

        final String script1 = "import groovy.json.JsonOutput\n" +
                "\n" +
                "def json(Map map) {\n" +
                "    return new JsonOutput().toJson(map)\n" +
                "}\n" +
                "\n" +
                "println json([test: 1])";

        final CompiledScript compiledScript1 = ((Compilable) engine).compile(script1);

        //Execute some instruction to generate 'script2'
        final String script2 = "println 'Running second script...'; println json([test: 2]);";
        final CompiledScript compiledScript2 = ((Compilable) engine).compile(script2);

        compiledScript1.eval(bindings);
        compiledScript2.eval(bindings);
    }
}

script2 определяется как:

println 'Running second script...';
println json([test: 2]);

Когда вы запустите его, вы увидите в консоли:

{"test":1}
Running second script...
{"test":2}

Первые две строки взяты из script1 в то время как последняя строка генерируется script2, Имейте в виду, что оба CompiledScript храните ссылку на тот же движок, чтобы вы могли ссылаться на функции, определенные в ранее оцененных скриптах.

Другие вопросы по тегам