2019-02-27
2019-02-27 本文已影响4人
老柿子
java 调用groovy脚本
调用方式其实是有几种方式,但是每个使用不当都会有一定的问题,因此这里专门进行总结下
一共有两种方式:
- 通过GroovyShell调用
- 通过GroovyClassLoader调用
- 享元工厂方式生成调用
GroovyShell调用
其中我们最常用的是用GroovyShell方式
错误
//这种调用方式是有问题的,会有两个无法清理,一个是InnerLoader对象和脚本Class
@Test
public void testRun() throws InterruptedException {
GroovyShell shell = new GroovyShell();
shell.evaluate(getScript());
}
正确
@Test
public void testRun() throws InterruptedException {
GroovyShell shell = new GroovyShell();
shell.evaluate(getScript());
//运行完,记得将内部的缓存清理
shell.getClassLoader().clearCache();
}
GroovyClassLoader调用
这种调用方式也是我们常用的
错误
//这种调用方式也是有问题的
@Test
public void testRun2() throws InterruptedException {
GroovyClassLoader loader = new GroovyClassLoader();
InvokerHelper.createScript(loader.parseClass(getScript()), new Binding()).run();
}
正确
每次调用完之后也需要将缓存清理掉
//这种调用方式也是有问题的
@Test
public void testRun2() throws InterruptedException {
GroovyClassLoader loader = new GroovyClassLoader();
InvokerHelper.createScript(loader.parseClass(getScript()), new Binding()).run();
loader.clearCache();
}
通过工厂方式
通过享元工厂方式达到相同脚本共享问题
1.脚本通过SHA256进行压缩节省空间
2.相同脚本使用以前的脚本
3.脚本执行完成之后清理缓存
/**
* groovy脚本类享元工厂
*
* @author zhouzhenyong
* @since 2019/1/17 下午7:33
*/
@SuppressWarnings("unchecked")
public class GroovyScriptFactory {
private static Map<String, Class<Script>> scriptCache = new HashMap<>();
private GroovyClassLoader classLoader = new GroovyClassLoader();
private static GroovyScriptFactory factory = new GroovyScriptFactory();
/**
* 设置为单例模式
*/
private GroovyScriptFactory(){}
public static GroovyScriptFactory getInstance(){
return factory;
}
private Class getScript(String key) {
// 压缩脚本节省空间
String encodeStr = EncryptUtil.SHA256(key);
if(scriptCache.containsKey(encodeStr)){
return scriptCache.get(encodeStr);
}else{
// 脚本不存在则创建新的脚本
Class<Script> scriptClass = classLoader.parseClass(key);
scriptCache.put(encodeStr, scriptClass);
return scriptClass;
}
}
private Object run(Class<Script> script, Binding binding) {
Script scriptObj = InvokerHelper.createScript(script, binding);
Object result = scriptObj.run();
// 每次脚本执行完之后,一定要清理掉内存
classLoader.clearCache();
return result;
}
public Object scriptGetAndRun(String key, Binding binding) {
return run(getScript(key), binding);
}
}
附件代码:
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import lombok.experimental.UtilityClass;
/**
* @author zhouzhenyong
* @since 2019/2/22 上午11:20
*/
@UtilityClass
public class EncryptUtil {
/**
* 传入文本内容,返回 encrypt-256 串
*/
public String SHA256(final String strText) {
return encrypt(strText, "SHA-256");
}
/**
* 传入文本内容,返回 encrypt-512 串
*/
public String SHA512(final String strText) {
return encrypt(strText, "SHA-512");
}
public String MD5(final String strText){
return encrypt(strText, "MD5");
}
/**
* 字符串 encrypt 加密
*/
private String encrypt(final String str, final String strType) {
MessageDigest messageDigest;
String encodeStr = "";
if (null == str || str.length() == 0) {
return encodeStr;
}
try {
messageDigest = MessageDigest.getInstance(strType);
messageDigest.update(str.getBytes());
// 将byte 转换为字符展示出来
StringBuilder stringBuffer = new StringBuilder();
String temp;
for (byte aByte : messageDigest.digest()) {
temp = Integer.toHexString(aByte & 0xFF);
if (temp.length() == 1) {
//1得到一位的进行补0操作
stringBuffer.append("0");
}
stringBuffer.append(temp);
}
encodeStr = stringBuffer.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return encodeStr;
}
}