表达式解析器Mvel2.0(MVFLEX Expression Language)

时间过的好快,突然就发现,已经过去一两年了,这一两年博客也写的不多,快要进入中年了,最重要的就是自律。要好好睡觉,好好学习,好好工作。

废话不多说,这次给大家说的是 表达式语言解析Mvel2.0

简介

MVEL为 MVFLEX Expression Language(MVFLEX表达式语言)的缩写,它是一种动态/静态的可嵌入的表达式语言和为Java平台提供Runtime(运行时)的语言。最初是作为一个应用程序框架实用程序的语言开始,该项目现已发展完全独立。

MVEL通常用于执行用户(程序员)通过配置XML文件或注释等定义的基本逻辑。它也可以用来解析简单的JavaBean表达式。Runtime(运行时)允许MVEL表达式通过解释执行或者预编译生成字节码后执行。

MVEL可以和drools 规则引擎配合使用

2.0版本,具有以下特性:

  1. 动态JIT优化器。当负载超过一个确保代码产生的阈值时,选择性地产生字节代码,这大大减少了内存的使用量。

新的静态类型检查和属性支持,允许集成类型安全表达。

  1. 错误报告的改善。包括行和列的错误信息。

  2. 新的脚本语言特征。MVEL2.0 包含函数定义,如:闭包,lambda定义,标准循环构造(for, while, do-while, do-until…),空值安全导航操作,内联with-context运营 ,易变的(isdef)的测试运营等等。

  3. 改进的集成功能。迎合主流的需求,MVEL2.0支持基础类型的个性化属性处理器,集成到JIT中。

  4. 更快的模板引擎,支持线性模板定义,宏定义和个性化标记定义。

  5. 新的交互式shell(MVELSH)。

mvel 与ognl,Groovy 表达式语言的性能对比结果

1:目前:MVEL拥有最快的解析器和编译器
2:MVEL优于其他嵌入式脚本语言的所有基准,除了算术性能基准方面:JEXL和MVEL并列( 12ms操作50000次迭代) 。
3:Groovy的编译器最慢,其次是JUEL然后OGNL 。
4:OGNL最差缓存反射性能,其次是JEXL 。
5:OGNL的嵌套map基准表现最差。这个基准包括解决从使用索引语法的Map中获取属性的问题(foo[‘bar’][‘something’]) 。
6:Groovy的编译器是目前使用一个特设的方式的时候速度太慢。

代码时刻

mvel2.x表达式包含以下部分的内容:属性表达式,布尔表达式,方法调用,变量赋值,函数定义。

我这边是做规则判断时用到此表达式语言,所以将自己用到的情况及例子贴出来。关于mvel 其他的一些用途和功能,大家可以下载文末的 mvel2.0文档,自行进行学习。

首先引入依赖

 <dependency>
            <groupId>org.mvel</groupId>
            <artifactId>mvel2</artifactId>
            <version>2.4.7.Final</version>
        </dependency>

创建mvel引擎对象和方法

import java.io.Serializable;
import java.util.Map;

import org.mvel2.MVEL;

/**
 * 脚本语言性能测试结果
 * https://www.iteye.com/topic/361794
 * https://www.iteye.com/blog/caoyaojun1988-163-com-2089726
 *
 * @author yyb
 * @time 2020/8/12
 */
public class MvelEngine {


    /**
     * 执行表达式
     *
     * @param expr
     * @param data
     * @return
     */
    public Object exec(String expr, Map<String, Object> data) {
        try {
            Object result = MVEL.eval(expr, data);
            if (result != null) {
                return result;
            }
        } catch (Exception e) {
            System.out.println("表达式执行错误");
            return false;
        }
        return null;

    }

    /**
     * 编译表达式
     *
     * @param expr
     * @return
     */
    public Serializable compileExpr(String expr) {
        try {
            Serializable compiled = MVEL.compileExpression(expr);
            return compiled;
        } catch (Exception e) {
            System.out.println("表达式编译错误:" + expr);
            return null;
        }
    }

    /**
     * 执行编译后的表达式
     *
     * @param expr
     * @param data
     * @return
     */
    public boolean execCompiled(Object expr, Map<String, Object> data) {
        try {
            Object result = MVEL.executeExpression(expr, data);
            if (result instanceof Boolean) {
                return (Boolean) result;
            } else {
                return false;
            }
        } catch (Exception e) {
            System.out.println("表达式执行错误");
            return false;
        }
    }

    /**
     * 执行有返回值的表达式
     *
     * @param expr
     * @param data
     * @return
     */
    public Object execReturnCompiled(Object expr, Map<String, Object> data) {
        try {
            Object result = MVEL.executeExpression(expr, data);
            if (result != null) {
                return result;
            }
        } catch (Exception e) {
            System.out.println("表达式执行错误");
            return false;
        }
        return null;
    }


    private static MvelEngine engine;

    /**
     * 创建基于MVEL的表达式引擎。
     *
     * @return
     */
    public synchronized static MvelEngine defaultEngine() {
        if (engine == null) {
            engine = new MvelEngine();
        }
        return engine;
    }
}

测试代码


public class MvelTest {

    public static void main(String[] args) {
        ageTest();
        containsTest();
        startsWithTest();
        emptyTest();
        multipleTest();
        returnTest();
        execExprTest();


    }


    /**
     * 布尔表达式:
     * 大于小于 等于 以及 优先级
     */
    public static void ageTest() {
        String expr = "(age > 10 && age <= 20) || age == 11 ";
        MvelEngine engine = MvelEngine.defaultEngine();
        Object obj = engine.compileExpr(expr);
        Map<String, Object> params = new HashedMap();
        params.put("age", 12);
        if (engine.execCompiled(obj, params)) {
            //满足表达式
            System.out.println("少年");
        } else {
            System.out.println("不满足条件");
        }
    }


    /**
     * 判断包含
     */
    public static void containsTest() {
        String expr = "name contains(\"张\")";
        MvelEngine engine = MvelEngine.defaultEngine();
        Object obj = engine.compileExpr(expr);
        Map<String, Object> params = new HashedMap();
        params.put("name", "张三");
        params.put("age", 11);
        if (engine.execCompiled(obj, params)) {
            //满足表达式
            System.out.println("包含张");
        } else {
            System.out.println("不满足条件");
        }
    }

    /**
     * 判断以xx开头
     */
    public static void startsWithTest() {
        String expr = "mobile.startsWith(136)";
        MvelEngine engine = MvelEngine.defaultEngine();
        Object obj = engine.compileExpr(expr);
        Map<String, Object> params = new HashedMap();
        params.put("mobile", "13643489802");
        params.put("age", 11);
        if (engine.execCompiled(obj, params)) {
            //满足表达式
            System.out.println("包含136开头手机号");
        } else {
            System.out.println("不满足条件");
        }
    }

    /**
     * 判空,多个表达式时,只有最后一个表达式的结果为返回
     */
    public static void emptyTest() {
        String expr = "foo == null ; foo1 == nil; foo2 == empty";
        MvelEngine engine = MvelEngine.defaultEngine();
        Object obj = engine.compileExpr(expr);
        Map<String, Object> params = new HashedMap();
        params.put("foo", 1);
        params.put("foo1", 1);
        params.put("foo2", " ");
        if (engine.execCompiled(obj, params)) {
            //满足表达式
            System.out.println("true");
        } else {
            System.out.println("不满足条件");
        }
    }


    /**
     * 多个表达式时,只有最后一个表达式的结果为返回
     * 您可以编写具有任意数量语句的脚本,使用分号表示语句的终止。这在所有情况下都是必需的,除非只有一条语句,或者脚本中的最后一条语句。
     */
    public static void multipleTest() {
        String expr = "age > 20; sex == 1; name contains(\"张2\")";
        MvelEngine engine = MvelEngine.defaultEngine();
        Object obj = engine.compileExpr(expr);
        Map<String, Object> params = new HashedMap();
        params.put("age", 10);
        params.put("sex", 1);
        params.put("name", "张三");
        if (engine.execCompiled(obj, params)) {
            //满足表达式
            System.out.println("true");
        } else {
            System.out.println("不满足条件");
        }
    }

    /**
     * 有返回值的表达式
     */
    public static void returnTest() {
        String expr = "a = 10;b = (a = a * 2) + 10; a;";
        MvelEngine engine = MvelEngine.defaultEngine();
        Object obj = engine.compileExpr(expr);
        Map<String, Object> params = new HashedMap();
        params.put("a", 1);
        Object r = engine.execReturnCompiled(obj, params);
        if (null != r) {
            //满足表达式
            System.out.println("a = " + r);
        } else {
            System.out.println("不满足条件");
        }
    }

    /**
     * 不用编辑即可执行
     */
    public static void execExprTest() {
        String expr = "x * y";
        MvelEngine engine = MvelEngine.defaultEngine();
        Map vars = new HashMap();
        vars.put("x", new Integer(5));
        vars.put("y", new Integer(10));
        Object r = engine.exec(expr, vars);
        if (r != null) {
            //满足表达式
            System.out.println(r);
        } else {
            System.out.println("不满足条件");
        }
    }

}

mvel2.0语法指南文档点我下载

参考资料

https://blog.csdn.net/shichen2010/article/details/78466293

http://mvel.codehaus.org/

https://www.iteye.com/topic/361794

你可能感兴趣的:(2.Java,2.7,规则引擎Drools,2.1,Java基础)