Java动态从外部加载groovy脚本并执行。因为java可以直接把对象绑定到groovy脚本中执行,所以完全可以把一些系统中不确定的处理留下钩子,用groovy脚本处理,逻辑变了就直接改脚本,不用走发布流程。
核心代码
CompilerConfiguration conf = new CompilerConfiguration();
conf.setDebug(false);
shell = new GroovyShell(conf);
String extCP = "/extlib/xxx.jar";
shell.getClassLoader().addClasspath(extCP);
String scriptName = "Script.groovy";
String scriptText = "String hello(){ return args[0] }";
Script script = (Class<Script>) shell.parse(scriptText, scriptName).getClass();
Thread.currentThread().setContextClassLoader(shell.getClassLoader());
//获取groovy代码中的hello方法
Method method = script.getDeclaredMethod("hello");
Script instance = script.newInstance();
Map bindings = instance.getBinding().getVariables();
bindings.clear();
//绑定args全局变量
bindings.put("args", args);
String ret = method.invoke(instance);
bindings.clear();
依赖
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-json</artifactId>
<version>2.5.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-sql</artifactId>
<version>2.5.4</version>
<scope>provided</scope>
</dependency>
<!-- groovy-all does not include groovy-dateutil by default, so must explicitly
include it here -->
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-dateutil</artifactId>
<version>2.5.4</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-jsr223</artifactId>
<version>2.5.4</version>
</dependency>
优化
可以根据脚本内容/脚本id等对script / method 来进行缓存,避免每次执行都要编译。编译会有大量的时间消耗,并造成metaspace增长。