在项目里面有时有这样的场景,我们需要一个权限表来控制权限,当满足权限表条件时,阻止用户操作并返回错误信息,表的结构类似:
这时有一种传统方式是,我们用mybatis之类的工具,写一段sql,每次用这段sql校验权限:
SELECT * from permission_test where `condition1` = #{condition1} and `condition2` = #{condition2}
另外一种方式是,我们将table编译为一段可执行代码,然后每次执行这段代码,这段代码类似:
那么这2种方式的效率相差多大呢,楼主写了一段测试代码:
执行结果是,compiledtester的执行时间总是1ms,而sqltester的执行时间则在800ms左右。
那么,compiledtester是怎么生成的呢?本文将简单介绍这个生成机制。
本文用到了楼主的开源项目 autogrammer : http://git.oschina.net/notebook
它的jar包可以在published项目下面下载到。
本文所用主要代码可以在这里 http://www.oschina.net/code/snippet_573815_50916 看到
首先有一个接口类 DBDataTester 这个类里面有2种实现,一种是传统的数据库实现SqlDataTester,另外一种是编译为java代码 DBDataTesterImpl 类的实现。
主要编译代码:
我们的思路是,从数据库里面把所有的record读取出来,然后利用autogrammer提供的功能编译这些record,最终生成目标代码。
编译java代码相关的知识你可以从这篇文章里面学到:
http://www.oschina.net/code/snippet_573815_50891
我们从数据库里面读取的record可以看作如下语句:
condition (name:"condition1", data:"condition1-1")
condition (name:"condition2", data:"condition1-2")
end (data: "错误数据1")
......
第一步:autogrammer要实现自定义编译器,首先需要你定义语法。代码中文法放在 yp/published/grammer/Grammer.txt 中:
其中,第三句表示,一个condition可以规约为一个conditionlist
第二句表示,一个conditionlist 和 condition 可以规约为一个 conditionlist
这样我们的文法就支持condition的无线罗列了
第一句表示,当遇到一个end时,表明当前句子结束(类似于编程语句中的;)此时会对整个句子进行编译,生成一段代码
类似:
if ("condition1-1".equals(data.getCondition1()) && "condition2-1".equals(data.getCondition2())) {
return "错误数据1";
}
第二步:有了文法以后,我们就需要一个词法分析器,这个词法分析器可以从数据库中读取数据,然后转化为文法中所对应的token流。
词法分析器需要继承,并实现TokenReader接口
public class DBTokenReader implements TokenReader
它的关键代码在这里:
第三步,我们需要针对我们定义的语法注册处理函数
public class ConditionHandler extends DefaultExecuteHandler
注册编译最开始的初始化函数:主要初始化ExecutePram
注册编译结束的函数:这里利用ExecuteParam 编译最终实现类DBDataTesterImpl
注册各个规约语句的处理函数
处理函数中,tokenWordList为一个List<TokenWord>, 里面的成员就是 "->" 左边的值(condition),
originalWord为 "->" 右边的值(conditionlist)。每一个tokenWord都有一个Object data成员可以放入自定义对象。
paramContext则是本次编译执行的参数。
最后,当我们凑齐了 语法文件,词法分析器,以及相关handler之后,就可以进行编译过程。在主要编译代码中,我们可以看到首先我们根据语法文件生成一个StateTable,然后生成自己的TokenReader,ExecuteHandler,最终利用3者生成一个ExecuteContext并且执行编译的过程。
再次贴出链接:
主要代码:http://www.oschina.net/code/snippet_573815_50916
编译java代码相关介绍: http://www.oschina.net/code/snippet_573815_50891
项目地址:http://git.oschina.net/notebook
其中本项目用到的是autogrammer,jar包在published项目下面。