Aviator 的基本过程是将字符串表达式直接翻译成对应的 java 字节码执行,整个过程最多扫两趟(开启执行优先模式,如果是编译优先模式下就一趟),这样就保证了它的性能超越绝大部分解释性的表达式引擎,测试也证明如此;其次,除了依赖 commons-beanutils 这个库之外(用于做反射)不依赖任何第三方库,因此整体非常轻量级,整个 jar 包大小哪怕发展到现在 5.0 这个大版本,也才 430K。同时, Aviator 内置的函数库非常“节制”,除了必须的字符串处理、数学函数和集合处理之外,类似文件 IO、网络等等你都是没法使用的,这样能保证运行期的安全,如果你需要这些高阶能力,可以通过开放的自定义函数来接入。因此总结它的特点是:
AviatorScript 编译和执行的入口是 AviatorEvaluatorInstance 类,该类的一个实例就是一个编译和执行的单元。
AviatorEvaluator.getInstance() 返回一个全局共享的AviatorEvaluatorInstance 类,没有定制化的需求,该默认引擎已足够我们本次的讲解。
AviatorEvaluatorInstance 入口常用Api:
public final class AviatorEvaluatorInstance {
//编译字符串表达式,cacheKey缓存标识,cached-是否缓存
public Expression compile(final String cacheKey, final String expression, final boolean cached)
//编译aviatorScript脚本文件,cacheKey缓存标识,cached-是否缓存
public Expression compileScript(final String cacheKey, final File file, final boolean cached) throws IOException
//执行字符串表达式,env环境变量,cached-是否缓存Expression对象
public Object execute(final String expression, final Map<String, Object> env,
final boolean cached)
}
示例1、执行字符串表达式
AviatorEvaluatorInstance aviatorEvaluatorInstance = AviatorEvaluator.newInstance();
//1.直接执行表达式
String exp1 = "1+2+3";
Object execute = aviatorEvaluatorInstance.execute(exp1);
System.out.println(execute);//6
String exp2 = "100>1000";
Object execute2 = aviatorEvaluatorInstance.execute(exp2);
System.out.println(execute2);//false
//2.使用环境变量
Map<String, Object> env = AviatorEvaluator.newEnv("a", 100, "b", 200, "c", 300);
String exp3 = "a+b+c";
Object execute3 = aviatorEvaluatorInstance.execute(exp3,env);
System.out.println(execute3);//600
String exp4 = "a+b==c";
Object execute4 = aviatorEvaluatorInstance.execute(exp4,env);
System.out.println(execute4);//false
//访问环境变量数组和集合
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
int[] nums = new int[5];
for(int i=0;i<nums.length;i++){
nums[i]=i;
}
Map<String,Object> map2 = new HashMap<String,Object>();
map2.put("date","2021-08-21");
Map<String,Object> map3 = new HashMap<String,Object>();
map3.put("list",list);
map3.put("nums",nums);
map3.put("map2",map2);
//hello world
System.out.println(AviatorEvaluator.execute("list[0]+' '+list[1]",map3));
//nums[0]+nums[1]+nums[2]=3
System.out.println(AviatorEvaluator.execute("'nums[0]+nums[1]+nums[2]='+ (nums[0]+nums[1]+nums[2])",map3));
//当前时间为:2021-08-21
System.out.println(AviatorEvaluator.execute("'当前时间为:'+map2.date",map3));
}
示例2、执行/导入函数
AviatorEvaluatorInstance aviatorEvaluatorInstance = AviatorEvaluator.newInstance();
//1.使用自有函数
System.out.println(AviatorEvaluator.execute("string.substring('habcello',1,3)"));//ab
System.out.println(AviatorEvaluator.execute("string.contains(\"abc\",\"ab\")"));//true
//2.导入静态方法
aviatorEvaluatorInstance.addStaticFunctions("StringUtils",StringUtils.class);
System.out.println(aviatorEvaluatorInstance.execute("StringUtils.isBlank('abc')"));//false
//3.导入实例方法
aviatorEvaluatorInstance.addInstanceFunctions("String",String.class);
System.out.println(aviatorEvaluatorInstance.execute("String.indexOf('abc','b')"));//1
//4.Function Missing调用
// 启用基于反射的方法查找和调用
AviatorEvaluator.setFunctionMissing(JavaMethodReflectionFunctionMissing.getInstance());
// 调用 String#indexOf
System.out.println(AviatorEvaluator.execute("indexOf('hello world', 'w')"));
示例3、使用自定义函数
public class TestAviator {
public static void main(String[] args) {
//注册函数
AviatorEvaluator.addFunction(new AddFunction());
System.out.println(AviatorEvaluator.execute("add(1, 2)")); // 3.0
System.out.println(AviatorEvaluator.execute("add(add(1, 2), 100)")); // 103.0
}
}
class AddFunction extends AbstractFunction {
@Override
public AviatorObject call(Map<String, Object> env,
AviatorObject arg1, AviatorObject arg2) {
Number left = FunctionUtils.getNumberValue(arg1, env);
Number right = FunctionUtils.getNumberValue(arg2, env);
return new AviatorDouble(left.doubleValue() + right.doubleValue());
}
public String getName() {
return "add";
}
}
Aviator具有两种运行模式:
1.执行优先,适合表达式不经常变化,将编译结果缓存并重复运行的场景(默认)
AviatorEvaluator.setOption(Options.OPTIMIZE_LEVEL, AviatorEvaluator.EVAL)
2.编译优先,适合表达式经常变化,不缓存直接运行的场景
AviatorEvaluator.setOption(Options.OPTIMIZE_LEVEL, AviatorEvaluator.COMPILE);
推荐优先使用执行优先模式,使用编译结果缓存模式,复用编译结果,传入不同变量执行。
外部变量传入,优先使用编译结果的 Expression#newEnv(…args) 方法创建外部 env,将会启用符号化,降低变量访问开销。
调用 Java 方法,优先使用自定义函数,其次是导入方法,最后是基于 FunctionMissing 的反射模式。
//最佳实践
//编译表达式,并缓存编译对象
Expression abc = aviatorEvaluatorInstance.compile("exp1","a+b+c",true);
//设置环境变量
Map<String, Object> stringObjectMap = abc.newEnv("a", 123, "b", 456, "c", 789);
//执行表达式
Object execute1 = abc.execute(stringObjectMap);
System.out.println(execute1);//1368
//读取缓存
Expression abc2 = aviatorEvaluatorInstance.getCachedExpressionByKey("exp1");
System.out.println(abc == abc2);//true
我们从最佳实践的流程中跟踪源码的实现方式,主要分为以下的三步:
Expression abc = aviatorEvaluatorInstance.compile(“exp1”,“a+b+c”,true);
首先进入compile方法
private Expression compile(final String cacheKey, final String expression,
final String sourceFile, final boolean cached) {
/* 忽略检查代码 */
if (cached) {//如果本次编译需要缓存
FutureTask<Expression> existedTask = null;
if (this.expressionLRUCache != null) {//如果开启LRU缓存配置,则缓存入LRU集合
boolean runTask = false;
synchronized (this.expressionLRUCache) {//对象加syn锁
existedTask = this.expressionLRUCache.get(cacheKey);//判断LRU集合是否存在缓存
if (existedTask == null) {
//无缓存结果,构建Callable编译任务
existedTask = newCompileTask(expression, sourceFile, cached);
runTask = true;
//将Callable任务存入缓存集合中
this.expressionLRUCache.put(cacheKey, existedTask);
}
}
if (runTask) {
existedTask.run();
}
} else {//普通缓存模式,存入ConcurrentHashMap集合中
FutureTask<Expression> task = this.expressionCache.get(cacheKey);
if (task != null) {
return getCompiledExpression(expression, task);
}
task = newCompileTask(expression, sourceFile, cached);
existedTask = this.expressionCache.putIfAbsent(cacheKey, task);
if (existedTask == null) {
existedTask = task;
existedTask.run();
}
}
//获取Callable任务的结果,existedTask.get()
return getCompiledExpression(cacheKey, existedTask);
} else {//未开启缓存,直接进行编译并返回
return innerCompile(expression, sourceFile, cached);
}
}
构建Callable编译任务:newCompileTask实际上也是调用了innerCompile方法,这里我们接着看innerCompile方法
private FutureTask<Expression> newCompileTask(final String expression, final String sourceFile,final boolean cached) {
return new FutureTask<>(new Callable<Expression>() {
@Override
public Expression call() throws Exception {
return innerCompile(expression, sourceFile, cached);
}
});
}
innerCompile:
private Expression innerCompile(final String expression, final String sourceFile,
final boolean cached) {
//词法分析器,用来对aviator脚本进行词法解析,如将脚本解析为变量、数字、字符串、注释等;
ExpressionLexer lexer = new ExpressionLexer(this, expression);
//字节码生成器,用于动态生成自定义的字节码;
CodeGenerator codeGenerator = newCodeGenerator(sourceFile, cached);
//表达式解析器,用于将脚本编译为表达式对象(BaseExpression)
ExpressionParser parser = new ExpressionParser(this, lexer, codeGenerator);
//通过ASM字节码生成技术生成字节码对象并利用构造函数生成实例对象,这里不进行分析
Expression exp = parser.parse();
if (getOptionValue(Options.TRACE_EVAL).bool) {
((BaseExpression) exp).setExpression(expression);
}
return exp;
}
"a+b+c"表达式生成的字节码对象反编译如下所示
public class SubClassExpression extends ClassExpression {
private final AviatorJavaType f0;//a
private final AviatorJavaType f1;//b
private final AviatorJavaType f2;//c
public SubClassExpression(final AviatorEvaluatorInstance instance, final List<String> varNames,final SymbolTable symbolTable){
super(instance, varNames, symbolTable);
f0 = new AviatorJavaType("a", symbolTable);
f1 = new AviatorJavaType("b", symbolTable);
f2 = new AviatorJavaType("c", symbolTable);
}
public final Object execute0(Env env){
return f0.add(f1,env).add(f2,env);
}
}
至此编译动作完成,返回Expression实例对象并加入缓存集合
Object execute1 =abc.execute(stringObjectMap)
首先看Expression实例对象.execute方法
public Object execute(Map<String, Object> map) {
if (map == null) {
map = Collections.emptyMap();
}
//环境变量封装
Env env = genTopEnv(map);
//环境变量执行器
EnvProcessor envProcessor = this.instance.getEnvProcessor();
if (envProcessor != null) {
envProcessor.beforeExecute(env, this);
}
try {
//执行
return executeDirectly(env);
} finally {
if (envProcessor != null) {
envProcessor.afterExecute(env, this);
}
}
}
接下来看下executeDirectly(Map<String, Object> env)
public Object executeDirectly(final Map<String, Object> env) {
try {
//执行ASM生成的字节码实例对象的execute0方法
Object result = execute0((Env) env);
if (RuntimeUtils.isTracedEval(env)) {
RuntimeUtils.printlnTrace(env, "Result : " + result);
}
//返回结果,这里是f0.add(f1,env).add(f2,env),123+456+789
return result;
} catch (ExpressionRuntimeException e) {
throw e;
} catch (Throwable t) {
throw Reflector.sneakyThrow(t);
}
}
Expression abc2 = aviatorEvaluatorInstance.getCachedExpressionByKey(“exp1”);
public Expression getCachedExpressionByKey(final String cacheKey) {
FutureTask<Expression> task = null;
if (this.expressionLRUCache != null) {//开启了LRU缓存则从LRU缓存中读取
synchronized (this.expressionLRUCache) {//syn锁,效率不如普通缓存集合
task = this.expressionLRUCache.get(cacheKey);
}
} else {//从普通缓存集合中读取
task = this.expressionCache.get(cacheKey);
}
if (task != null) {
return getCompiledExpression(cacheKey, task);
} else {
return null;
}
}
集合类型如下:
//普通集合为ConcurrentHashMap
private final ConcurrentHashMap<String, FutureTask<Expression>> expressionCache =
new ConcurrentHashMap<String, FutureTask<Expression>>();
//利用LinkedHashMap实现的LRU缓存集合
private LRUMap<String, FutureTask<Expression>> expressionLRUCache;
public class LRUMap<K, V> extends LinkedHashMap<K, V> {
static final long serialVersionUID = -1L;
private final int maxCapacity;
public class LRUMap<K, V> extends LinkedHashMap<K, V> {
public LRUMap(final int maxCapacity) {
super(16, 0.75f, true);
if (maxCapacity <= 0) {
throw new IllegalArgumentException("Invalid maxCapacity: " + maxCapacity);
}
this.maxCapacity = maxCapacity;
}
@Override
protected boolean removeEldestEntry(final java.util.Map.Entry<K, V> eldest) {
return this.size() > this.maxCapacity;
}
}
1.公式计算
2.数据处理及转换
3.数据核对
4.工作流逻辑判定
5.鉴权校验
6.规则引擎
业务需求:
“根据不同的角色和动作决定结果”
表达式设计:
“flow(role,action)”
函数说明:
flow() : 获取角色、动作,执行结果
public class RuleEngineDemo {
public static void main(String[] args) {
//注册自定义表达式函数
AviatorEvaluator.addFunction(new FlowFunction());
//用户指定规则
String expression = "flow(role,action)";
Expression compiledExp = AviatorEvaluator.compile(expression);
//运行时收到数据
Map<String, Object> fields = new HashMap<String, Object>();
fields.put("role", "teacher");
fields.put("action", "talk");
compiledExp.execute(fields);
//"The teacher is talking"
Map<String, Object> fields2 = new HashMap<String, Object>();
fields.put("role", "student");
fields.put("action", "study");
//"The students are studying"
compiledExp.execute(fields2);
}
static class FlowFunction extends AbstractFunction {
@Override
public void call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
String role = FunctionUtils.getStringValue(arg1, env);
String action = FunctionUtils.getStringValue(arg2, env);
System.out.println("role : " + role + "action : " + action);
switch(role){
case "teacher": {
teacher(action);
break;
}
case "student": {
student(action);
break;
}
default: {
System.out.println("error role");
break;
}
}
}
public String getName() {
return "flow";
}
}
}
demo2转载自:http://shihlei.iteye.com/blog/2421576
业务需求:
“1小时,userid,在ip上,触发action 100次报警”
表达式设计:
“redisCount(‘1’,‘hour’,fields(‘userid,ip,action’)) >= 100”
函数说明:
fields() : 获取字段,校验,生成redis key
redisCount():使用 key进行查询,获取redis中存的量且redis +1
public class RuleEngineDemo {
public static void main(String[] args) {
//注册自定义表达式函数
AviatorEvaluator.addFunction(new FieldsFunction());
AviatorEvaluator.addFunction(new RedisCountFunction());
//用户指定规则
String expression = "redisCount('1','hour',fields('userid,ip,action')) >= 100";
Expression compiledExp = AviatorEvaluator.compile(expression);
//运行时收到数据
Map<String, Object> fields = new HashMap<String, Object>();
fields.put("userid", "9527");
fields.put("ip", "127.0.0.1");
fields.put("phone", "18811223344");
fields.put("action", "click");
Boolean needAlarm = (Boolean) compiledExp.execute(fields);
if (needAlarm) {
System.out.printf("报警");
}
}
static class FieldsFunction extends AbstractFunction {
@Override
public AviatorObject call(Map<String, Object> env, AviatorObject fieldsStrObj) {
//获取可变参数
String fieldStr = fieldsStrObj.stringValue(env);
String[] fields = fieldStr.split(",");
StringBuilder redisKey = new StringBuilder();
System.out.println("FieldsFunction : " + fieldStr);
for (String f : fields) {
Object value = env.get(f);
if (value != null) {
redisKey.append(value.toString());
} else {
//TODO 参数合法性校验
}
redisKey.append(":");
}
return new AviatorString(redisKey.toString());
}
public String getName() {
return "fields";
}
}
static class RedisCountFunction extends AbstractFunction {
@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3) {
String period = FunctionUtils.getStringValue(arg1, env);
String timeUnit = FunctionUtils.getStringValue(arg2, env);
String redisKey = FunctionUtils.getStringValue(arg3, env);
System.out.println("FieldsFunction : " + period + " , " + timeUnit + " , " + redisKey);
//TODO 读取redis
int redisCount = redisGetAndIncrease(redisKey);
return new AviatorLong(redisCount);
}
private int redisGetAndIncrease(String redisKey) {
System.out.println("get redis : " + redisKey);
//这里查询redis获得活动的值;
return 10000;
}
public String getName() {
return "redisCount";
}
}
}