google aviator:Java逻辑公式引擎

背景

在我们的业务场景中有一个需求,我们有一个配置功能,该功能需要配置两个变量之间比较大小。使用tab比较难表达,所以就提出了,可以让用户写比较简单的函数进行配置。或者选tab进行选择(前段直接将对应的tab字符串拼接来给后端执行)。

或者这么说吧,可以通过字符串的表达的意思,进行执行这个字符串的索要表达的逻辑,且这个逻辑和这个字符串可以自定义。
Aviator
简介

Aviator是一个高性能、轻量级的java语言实现的表达式求值引擎,主要用于各种表达式的动态求值。现在已经有很多开源可用的java表达式求值引擎,为什么还需要Avaitor呢?

Aviator的设计目标是轻量级和*高性能 ,相比于Groovy、JRuby的笨重,Aviator非常小,加上依赖包也才450K,不算依赖包的话只有70K;当然,Aviator的语法是受限的,它不是一门完整的语言,而只是语言的一小部分集合。

其次,Aviator的实现思路与其他轻量级的求值器很不相同,其他求值器一般都是通过解释的方式运行,而Aviator则是直接将表达式*编译成Java字节码,交给JVM去执行。简单来说,Aviator的定位是介于Groovy这样的重量级脚本语言和IKExpression这样的轻量级表达式引擎之间。
内部原理

    任何语言都是通过一步一步的抽象,从硬件原理再到我们人类可以认识的语言。
    Java语言是基于JVM虚拟机抽象上来的语言,通过编译器可以将我们写的代码进行类加载后编译为JVM可以认识的字节码,JVM在进行编译和运行再变为我们操作系统可以运行的代码,直到二极管三极管可以认识的的高低位。
    Aviator框架用自己规范最后也编译为JVM虚拟机可以认识的字节码。

 
基本使用规范

 

官方详细文档: https://github.com/killme2008/aviatorscript

    官方文档会讲的很清楚很多细节,在这里不做赘述

 

代码示例, 判断某个字符是否存在

     Object object = AviatorEvaluator.execute("string.contains(\"test\",
     string.substring('hello', 1, 2))");  // true
     System.out.println(object);

判断两个时间大小

            String nameValue = "a";
            String name1Value2 = "b";
            String expression = nameValue + ">" + name1Value2;
            // nameValue
            Object execute = compareAandB(nameValue, name1Value2, expression);
            System.out.println(execute);

传入变量  替换

            String name = "小龙";
            Map<String,Object> env = new HashMap<>();
            env.put("name", name);
            String result = (String) AviatorEvaluator.execute(" 'Hello ' + name ", env);
            System.out.println(result);

 Aviator的内置函数用法 获取字符长度

     
            String str = "带你学习使用Aviator";
            Map<String,Object> env1 = new HashMap<>();
            env1.put("str",str);
            Long length = (Long)AviatorEvaluator.execute("string.length(str)",env1);
            System.out.println(length);

compile用法

            String expression1 = "a-(b-c)>100";
            Expression compiledExp = AviatorEvaluator.compile(expression1);
            Map<String, Object> env2 = new HashMap<>();
            env2.put("a", 100.3);
            env2.put("b", 45);
            env2.put("c", -129.100);
            Boolean result1 = (Boolean) compiledExp.execute(env2);
            System.out.println(result1);

通过上面的代码片段可以看到
使用compile方法,先生成了 Expression 最后再由
Expression.execute,然后传入参数 map,进行计算
这么做的目的是,在我们实际使用过程中
很多情况下,我们要计算的公式都是一样的,只是每次的参数有所区别。
我们可以把一个编译好的Expression 缓存起来。
这样每次可以直接获取我们之前编译的结果直接进行计算,避免Perm区OutOfMemory

Aviator本身自带一个全局缓存
如果决定缓存本次的编译结果,只需要

Expression compiledExp = AviatorEvaluator.compile(expression,true);

这样设置后,下一次编译同样的表达式,Aviator会自从从全局缓存中,拿出已经编译好的结果,不需要动态编译。如果需要使缓存失效,可以使用

AviatorEvaluator.invalidateCache(String expression);

posted @ 2023-07-23 07:22  锐洋智能  阅读(419)  评论(0编辑  收藏  举报