在 Java 开发中,经常需要处理动态逻辑、规则计算或配置解析。硬编码这些逻辑缺乏灵活性,而 MVEL (MVFLEX Expression Language) 作为一款高性能、功能丰富的表达式引擎,可以很好的解决这类问题。

MVEL

1、MVEL 简介

MVEL 是一种基于 Java 的动态表达式语言运行时。它不仅仅是一个简单的属性提取工具(如 OGNL),更是一个强大的脚本引擎。其核心优势在于:

  • 高性能: 采用解释和编译两种执行模式,编译后执行速度接近原生 Java。

  • 功能强大: 支持完整的控制流语句 (if, for, while)、赋值、函数调用、集合操作、正则表达式、投影/收集等。

  • 语法简洁: 借鉴 Java 语法,易于学习,表达式直观易读。

  • 灵活集成: 易于嵌入到 Java 应用程序中,与各种框架(如规则引擎 Drools, 模板引擎)无缝协作。

  • 强类型与弱类型结合: 支持类型推断,也允许动态类型操作。

  • 应用广泛: 规则引擎中的条件/动作、动态配置解析、模板渲染(如邮件模板)、简单脚本任务、数据映射转换等。

为什么选择 MVEL?

  • 相比 java.util.regex 或字符串切割,它能处理更复杂的逻辑。

  • 相比完整的脚本引擎(如 Groovy),它更轻量级,启动更快,安全性控制更直接。

  • 相比 OGNL、SpEL (Spring Expression Language),它在复杂脚本和性能(尤其是编译模式)方面通常更有优势。

文档:Language Guide for 2.0

2、MVEL使用

将 MVEL 集成到Java 项目非常简单,引入maven依赖:

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

2.1、执行表达式

可以很方便的执行一些算术表达式:

public class MvelTest {
    public static void main(String[] args) {
        String expression = "2 + 3 * 4";
        Object result = MVEL.eval(expression);
        System.out.println("Result: " + result);
    }
}

2.2、变量绑定与执行上下文

可以将变量传入表达式执行环境:

public class MvelTest {
    public static void main(String[] args) {
        String expression = "x + y";
        Map<String, Integer> variables = new HashMap<>(4);
        variables.put("x", 2);
        variables.put("y", 3);
        Object result = MVEL.eval(expression, variables);
        System.out.println("Result: " + result);
    }
}

2.3、执行脚本

MVEL 可以执行包含复杂逻辑的脚本块,如if-else语句、foreach语句等

public class MvelTest {
    public static void main(String[] args) {
        String expression = "if (x > y) { x } else { y }";
        Map<String, Object> variables = new HashMap<>(4);
        variables.put("x", 2);
        variables.put("y", 3);
        Object result = MVEL.eval(expression, variables);
        System.out.println("Result: " + result);
    }
}

使用foreach语句

public class MvelTest {
    public static void main(String[] args) {
        String expression = "foreach (item : list) { System.out.print(item) }";
        Map<String, Object> variables = new HashMap<>(2);
        variables.put("list", Arrays.asList(1, 2, 3, 4, 5));
        Object result = MVEL.eval(expression, variables);
        System.out.println("Result: " + result);
    }
}

2.4、对象操作

public class MvelTest {
    public static void main(String[] args) {
        String expression = "person.name + ' ' + person.age";
        Map<String, Object> variables = new HashMap<>(2);
        variables.put("person", new Person("John", 30));
        Object result = MVEL.eval(expression, variables);
        System.out.println("Result: " + result);
    }

    private static class Person {

        private String name;
        private int age;

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public int getAge() {
            return age;
        }
    }
}

2.5、集合操作

public class MvelTest {
    public static void main(String[] args) {
        String expression = "list.size()";
        Map<String, Object> variables = new HashMap<>(2);
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        variables.put("list", list);
        Object result = MVEL.eval(expression, variables);
        System.out.println("Result: " + result);
    }
}

2.6、使用函数

public class MvelTest {
    public static void main(String[] args) {
        String expression = "Math.pow(x, y)";
        Map<String, Object> variables = new HashMap<>();
        variables.put("x", 2);
        variables.put("y", 3);
        Object result = MVEL.eval(expression, variables);
        System.out.println("Result: " + result);
    }
}

2.7、使用自定义函数


public class MvelTest {
    public static void main(String[] args) {
        String expression = "myFunction(x, y)";
        Map<String, Object> variables = new HashMap<>();
        variables.put("x", 2);
        variables.put("y", 3);
        variables.put("myFunction", new MyFunction());
        Object result = MVEL.eval(expression, variables);
    }

    private static class MyFunction {
        public double myFunction(double x, double y) {
            return Math.pow(x, y);
        }
    }
}

2.8、使用自定义类

public class MvelTest {
    public static void main(String[] args) {
        String expression = "cn.river.base.mvel.StringUtils.reverse(s)";
        Map<String, Object> variables = new HashMap<>();
        variables.put("s", "Hello, World!");
        Object result = MVEL.eval(expression, variables);
        System.out.println("Result: " + result);
    }
}

public class StringUtils {
    public static String reverse(String s) {
        return new StringBuilder(s).reverse().toString();
    }
}

2.9、编译与执行 (提升性能)

对于需要重复执行的表达式,先编译再执行效率更高:

public class MvelTest {
    public static void main(String[] args) {
        String expression = "x + y * 10";
        Map<String, Object> variables = new HashMap<>(4);
        variables.put("x", 2);
        variables.put("y", 3);
        Serializable serializable = MVEL.compileExpression(expression);
        Object result = MVEL.executeExpression(serializable, variables);
        System.out.println("Result: " + result);
    }
}

MVEL.compileExpression(string)是将表达式编译成MVEL可执行的内容,然后通过MVEL.executeExpression(expression)执行。编译后的表达式可以缓存起来,下次直接执行,减少编译时间,提升性能。

3、结语

MVEL以其高性能、丰富的功能和简洁的语法,成为Java生态中处理动态表达式和脚本任务的首选工具之一。无论是简单的属性提取、条件判断,还是包含循环和赋值的复杂脚本逻辑,MVEL 都能轻松胜任。如果你正在寻找一个功能强大且不臃肿的表达式引擎,不妨尝试下MVEL。