(注:相关代码请参考 com.ql.util.express.test.ExpressCacheTest类,
QLExpress 源代码下载地址:http://code.taobao.org/p/QLExpress/src/ )
1、QLExpress的缓存带来的好处:
自带了一个本地缓存,用于缓存指令集,已减少编译阶段的时间消耗。
@Test public void testScriptCache() throws Exception { runner.addMacro("计算平均成绩", "(语文+数学+英语)/3.0"); IExpressContext<String, Object> context =new DefaultContext<String, Object>(); context.put("语文", 88); context.put("数学", 99); context.put("英语", 95); long times =10000; long start = new java.util.Date().getTime(); while(times-->0){ calulateTask(false, context); } long end = new java.util.Date().getTime(); echo("不做缓存耗时:"+ (end-start) +" ms"); times =10000; start = new java.util.Date().getTime(); while(times-->0){ calulateTask(true, context); } end = new java.util.Date().getTime(); echo("做缓存耗时:"+ (end-start) +" ms"); } private void echo(Object obj){ System.out.println(obj); } private void calulateTask(boolean isCache, IExpressContext<String, Object> context) throws Exception{ runner.execute("计算平均成绩", context, null, isCache, false); }
实验结果:效果是非常明显的!
不做缓存耗时:890 ms 做缓存耗时:22 ms
2、ExpressRunner 自带的缓存
在同一个ExpressRunner执行器内是全局的,脚本间也可以相互调用,非常的强大。
适用场景:业务逻辑非常复杂,但是全局统一,业务逻辑需要很高的复用性。
@Test public void testLocalCacheMutualImpact()throws Exception { //缓存在本地的脚本都是全局的,可以相互调用 runner.addMacro("计算平均成绩", "(语文+数学+英语)/3.0"); runner.addMacro("是否优秀", "计算平均成绩>90"); IExpressContext<String, Object> context =new DefaultContext<String, Object>(); context.put("语文", 88); context.put("数学", 99); context.put("英语", 95); echo(runner.execute("是否优秀", context, null, false, false)); }
3、独立于ExpressRunner的外部缓存处理器
适用场景:业务逻辑相对简单,脚本只依赖系统函数,不相互依赖,需要比较高的脚本隔离性和安全性,避免相互影响。
@Test public void testRemoteCache(){ //数据的预先加载 ExpressRunner runner =new ExpressRunner(); ExpressRemoteCacheRunner cacheRunner = new LocalExpressCacheRunner(runner); cacheRunner.loadCache("计算平均成绩", "(语文+数学+英语)/3.0"); cacheRunner.loadCache("是否优秀", "计算平均成绩>90"); IExpressContext<String, Object> context =new DefaultContext<String, Object>(); context.put("语文", 88); context.put("数学", 99); context.put("英语", 95); //ExpressRemoteCacheRunner都只能执行自己原有的脚本内容,而且相互之间隔离,保证最高的脚本安全性 echo(cacheRunner.execute("计算平均成绩", context, null, false, false, null)); try{ echo(cacheRunner.execute("计算平均成绩>90", context, null, false, false, null)); }catch(Exception e){ echo("ExpressRemoteCacheRunner只支持预先加载的脚本内容"); } try{ echo(cacheRunner.execute("是否优秀", context, null, false, false, null)); }catch(Exception e){ echo("ExpressRemoteCacheRunner不支持脚本间的相互调用"); } }
总结下:
1、缓存主要是将 文本-》生成指令集 这个过程缓存起来,所以ExpressRunner的编译执行的,但是编译过程又属于表达式类型脚本,只要符合定义的语法规范即可。
2、ExpressRunner自带的缓存会全局保存,每一次脚本执行的时候可以依赖到以前的指令。
3、ExpressRemoteCacheRunner每一次load脚本的时候,只将本次编译好的指令集缓存起来,可以放在本地也可以放入远程的缓存系统中(如淘宝的 tair 等),所以牺牲了复用性,得到了安全性和独立性。