Java 表达式引擎分析

本文将和介绍及分析表达式引擎。

表达式引擎

表达式引擎是把字符串表达式转换为计算机可以理解运行的计算规则。

Groovy就是最常见的基于JVM动态语言的表达式引擎之一。

表达式的引擎是基于编程语言的基础之上编译原理的一种实现。

常见功能

表达式引擎常见的功能有操作符对象条件语句循环语句函数集合异常脚本等。

java_expression_plugin_01.png

原理

编译型与解释型

计算机是不能理解高级语言的,更不能直接执行高级语言。

任何高级语言编写的程序若想被计算机运行,都必须将其转换成计算机语言(机器码)。

编译型是将高级语言源代码一次性编译成可被该平台硬件执行的机器码。

解释型不需要事先编译而直接将源代码解释成机器码并立即执行。

与预编译相比,解释机器码并执行效率较低。

在Java的表达式引擎中,MVEL支持普通的解释运行及编译运行。

强类型与弱类型

弱类型检查不会对变量类型做任何假设,而是在运行时做类型推断及自动转化。

强类型检查可以保证在编译时就确定变量类型从而才能生成高效和正确的代码。


在Java的表达式引擎中,

FEL属于强类型检查,它没有自己的类型系统,而是利用Java类型来实现;

QLExpressGroovy属于弱类型检查,在编译时不会对类型做任何检查,而是在运行期对其推断并转换。


表达式解析

表达式可以分为波兰式(前缀表达式)逆波兰式(后缀表达式)中缀表达式

其中,波兰式逆波兰式更适合计算机来执行,具体可以参考

表达式会首先被解析为语法树AST(中缀表达式),但中缀表达式不适合计算机运算,因此,需要转换为波兰式逆波兰式


Java表达式引擎原理

表达式引擎的基础是编译原理Java字节码技术。

在编译原理中,需要实现解释器编译器

解释器包括语法分析词法分析语义分析,而解释器包括中间代码目标代码

Java中的规则引擎一般会把表达式生成.class字节码,并利用JVM加载到内存中来执行,从而达到编译的运行效率。


目前,规则的引擎的实现大体分为两种:利用Java类运行时动态编译技术利用ASM字节码生成技术

利用Java类运行时动态编译技术

核心接口: javax.tools接口JavaCompiler

  • 使用antlr解析把表达式成AST
  • 使用JDK工具(javax.tools.JavaCompiler)动态编译成.class文件;
  • 利用URLClassLoader.class文件放入JVM直接运行。
1
expression string -> antlr -> AST -> comiple -> java source template -> java class -> Expression

具体可参考

利用ASM字节码生成技术

核心技术:antlr语法解析器ASM字节码生成技术

  • 使用antlr解析把表达式成AST
  • 利用AMSAST的节点重新编排成.class文件或者指令;
  • 利用URLClassLoader.class文件放入JVM直接运行。

Java中的表达式引擎

表达式引擎的对比介绍可参考

基础功能

FELSimpleExpress都是仅支持表达式的基础功能,依赖Java类型系统。

此外,还包括JUELJSEL

高级功能

Aviator有自己的类型系统,属于若类型检查。

QLExpress是阿里开源的表达式引擎,同样属于若类型检查,强调功能扩展。

Groovy兼容Java语法,同时支持强类型和若类型检查,支持更多的集合操作。

GroovyJava官方的脚本语言,更适合构建大型规则引擎。


性能对比:

表达式:
foobar * 100 < 200 || foobar > 300 || (foobar < 200 && foobar + 5 < 300)

循环次数:
100 * 10000

结果:

1
2
3
4
5
6
7
8
9
10
11
jsel::exec  Run Time:   2164 ms
jselCompiled::exec Run Time: 28 ms
mvel::exec Run Time: 1881 ms
mvelCompiled::exec Run Time: 120 ms
qlexpress::exec Run Time: 14471 ms
qlexpressCompiled::exec Run Time: 113 ms
juel::exec Run Time: 159 ms
groovy::exec Run Time: 680 ms
groovyCompiled::exec Run Time: 45 ms
aviator::exec Run Time: 16736 ms
aviatorCompiled::exec Run Time: 43 ms


应用场景

流程编排:通过动态脚本来管理流程调度,例如,基于微服务来动态搭建流程。

规则引擎:利用动态表达式来实时修改配置,例如,营销规则配置、审核流条件判断。

脚本引擎:利用动态脚本来实现在线编辑器。