起因
事情的起因源自上篇文章中源码分析的原因:要实现按需修改resolverFactory中缓存的参数,上篇及上上篇中为了实现功能添加了很多不必要的缓存,所以这篇文章中写一下我新的实现方法
改动点
去除对函数体的缓存
在上上篇文章中在缓存中保存了函数体,在新的解决方法中直接去掉就行了,因为不需要
添加对单个函数体的编译
由于采用的是按需添加缓存,但没有减少,所以当函数加入到resolverFactory的Map中后,除非是重启服务,否则只有全部清空,MapVariableResolverFactory中提供了clear()方法,下面是单个函数体编译的代码
public MapVariableResolverFactory rebuildVariableResolverFactoryByStr(String expStr) {
MapVariableResolverFactory resolverFactory = new MapVariableResolverFactory();
ParserContext ctx = new ParserContext();
try{
char[] charArr = expStr.toCharArray();
MVEL.eval(charArr, ctx, resolverFactory);
}catch (Exception e){
e.printStackTrace();
return null;
}
return resolverFactory;
}
实现逻辑
这里的实现逻辑是
- 从缓存中获取原来的resolverFactory
MapVariableResolverFactory resolverFactory = (MapVariableResolverFactory) getVariableResolverFactory();
- 将修改或新增的函数单独编译,调用上一步的编译方法
//newFunction.getFunctionEntity()为函数体,也就是函数的字符串
MapVariableResolverFactory newFuncResolverFactory = calculatorBuild.rebuildVariableResolverFactoryByStr(newFunction.getFunctionEntity());
-
进行相关参数的合并
这里进行3个参数的合并,下面一一说明:- 引用类合并
必须说明,在进行操作的时候一定要判断新编译的函数中是否存在引用类,不存在和跳过这一步,原理是:在mvel的编译行为进行的时候会对你传入的函数字符串进行扫描,如果发现import或import-static关键字就会生成ClassImportResolverFactory,并在这个类中保存引用的对象,以Map<String, Object> 的形式进行保存,其中Object为引用类的Class对象,在ClassImportResolverFactory中只提供了添加方法,不提供获取,代码如下,感兴趣的自行观看private Map<String, Object> dynImports; ... public Class addClass(Class clazz) { if (this.dynImports == null) {
- 引用类合并