Java动态脚本
动态脚本有诸多用途,对于不停机变更执行逻辑,实现部分开放式的业务动态性非常有帮助。不过好的设计需要考虑性能、边界、变更控制等问题,以达到“受控的动态”能力。
JVM提供了不错的脚本接口,从invokedynamic到GraalVM,多语言、动态语言、高性能是发展方向。
Groovy作为可以和Java无缝交互的动态语言,利用了invokedynamic来实现核心功能,开发比较活跃,是动态化比较好的选择。下面介绍几种Groovy嵌入Java应用的方法。为达到class缓存、线程安全等目的,一些其他的方法不做介绍。
1、直接使用GroovyScriptEngine,加载test1.groovy文件执行:
public void testRun1() {
String[] roots = new String[] { getCwd() + "\\src\\test\\groovy\\"};
try {
GroovyScriptEngine gse = new GroovyScriptEngine(roots);
Binding binding = new Binding();
binding.setVariable("input", "world");
gse.run("test1.groovy", binding);
System.out.println(binding.getVariable("output"));
} catch (Exception e) {
e.printStackTrace();
}
}
test1.groovy如下:
output = "Hello, ${input}!"
问题:如何做性能加速?
2、使用GroovyClassLoader,加载test2.groovy文件执行:
public void testRun2() {
ClassLoader parent = getClass().getClassLoader();
GroovyClassLoader loader = new GroovyClassLoader(parent);
try {
String filePath = getCwd() + "\\src\\test\\groovy\\test2.groovy";
Class groovyClass = loader.parseClass(new File(filePath));
Binding binding = new Binding();
binding.setVariable("input", "world");
GroovyObject groovyObject = (GroovyObject) groovyClass.getDeclaredConstructor().newInstance();
Object[] args = {binding};
groovyObject.invokeMethod("run", args);
System.out.println(binding.getVariable("output"));
} catch (Exception e) {
e.printStackTrace();
}
}
test2.groovy如下:
def run(binding) {
println binding.getVariable("input");
binding.setVariable("output", "hi test2")
}
问题:如何做性能加速?
3、使用ScriptEngineManager获取脚本引擎,加载test3.groovy文件执行:
public void testRun3() {
try {
String scriptFile = getCwd() + "\\src\\test\\groovy\\test3.groovy";
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("groovy");
SimpleBindings binding = new SimpleBindings();
binding.put("input", "groovy ScriptEngineManager");
if (engine instanceof Compilable) {
Compilable compilable = (Compilable) engine;
CompiledScript compiledScript = compilable.compile(new FileReader(new File(scriptFile)));
Object out = compiledScript.eval(binding);
System.out.println("eval output is: " + out.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
test3.groovy如下:
output = "Hello, ${input}!";
return output;
问题:如何做性能加速?
对于jdk8~11使用ScriptEngineManager还可以获取javascript脚本引擎,和testRun3对groovy脚本操作类似。加载test4.js文件执行如下:
public void testRun4() {
try {
String scriptFile = getCwd() + "\\src\\test\\js\\test4.js";
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("javascript");
SimpleBindings binding = new SimpleBindings();
binding.put("input", "javascript ScriptEngineManager");
if (engine instanceof Compilable) {
Compilable compilable = (Compilable) engine;
CompiledScript compiledScript = compilable.compile(new FileReader(new File(scriptFile)));
Object out = compiledScript.eval(binding);
System.out.println("eval output is: " + out.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
test4.js如下:
output = "Hello, " + input;
output;