Java各种规则引擎
Java各种规则引擎
一. Drools规则引擎
- 简介:
Drools就是为了解决业务代码和业务规则分离的引擎。
Drools 规则是在 Java 应用程序上运行的,其要执行的步骤顺序由代码确定
,为了实现这一点,Drools 规则引擎将业务规则转换成执行树。
- 特性:
优点:
1、简化系统架构,优化应用
2、提高系统的可维护性和维护成本
3、方便系统的整合
4、减少编写“硬代码”业务规则的成本和风险
3.原理:

- 使用方式:
(1)Maven 依赖:
<dependencies>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
<version>6.5.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>6.5.0.Final</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
(2)新建配置文件/src/resources/META-INF/kmodule.xml
<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
<kbase name="rules" packages="rules">
<ksession name="myAgeSession"/>
</kbase>
</kmodule>
(3)新建drools规则文件/src/resources/rules/age.drl
import com.lrq.wechatDemo.domain.User // 导入类
dialect "mvel"
rule "age" // 规则名,唯一
when
$user : User(age<15 || age>60) //规则的条件部分
then
System.out.println("年龄不符合要求!");
end
工程搭建完毕,效果如图:

测试用例:
/**
* CreateBy: haleyliu
* CreateDate: 2018/12/26
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath*:applicationContext.xml"})
public class TestUser {
private static KieContainer container = null;
private KieSession statefulKieSession = null;
@Test
public void test(){
KieServices kieServices = KieServices.Factory.get();
container = kieServices.getKieClasspathContainer();
statefulKieSession = container.newKieSession("myAgeSession");
User user = new User("duval yang",12);
statefulKieSession.insert(user);
statefulKieSession.fireAllRules();
statefulKieSession.dispose();
}
}
二.Aviator表达式求值引擎
- 简介:
Aviator是一个高性能、轻量级的java语言实现的表达式求值引擎,主要用于各
种表达式的动态求值。现在已经有很多开源可用的java表达式求值引擎,为什
么还需要Avaitor呢?
Aviator的设计目标是轻量级和高性能 ,相比于Groovy、JRuby的笨重,Aviator
非常小,加上依赖包也才450K,不算依赖包的话只有70K;当然,Aviator的语法
是受限的,它不是一门完整的语言,而只是语言的一小部分集合。
其次,Aviator的实现思路与其他轻量级的求值器很不相同,其他求值器一般都
是通过解释的方式运行,而Aviator则是直接将表达式编译成Java字节码,交给
JVM去执行。简单来说,Aviator的定位是介于Groovy这样的重量级脚本语言和
IKExpression这样的轻量级表达式引擎之间。
- 特性:
(1)支持大部分运算操作符,包括算术操作符、关系运算符、逻辑操作符、
正则匹配操作符(=~)、三元表达式?: ,并且支持操作符的优先级和括号强制优
先级,具体请看后面的操作符列表。
(2)支持函数调用和自定义函数。
(3)支持正则表达式匹配,类似Ruby、Perl的匹配语法,并且支持类Ruby的
$digit指向匹配分组。自动类型转换,当执行操作的时候,会自动判断操作数类
型并做相应转换,无法转换即抛异常。
(4)支持传入变量,支持类似a.b.c的嵌套变量访问。
(5)性能优秀。
(6)Aviator的限制,没有if else、do while等语句,没有赋值语句,仅支持逻
辑表达式、算术表达式、三元表达式和正则匹配。没有位运算符
-
整体结构:
整体结构.png -
maven依赖:
<dependency>
<groupId>com.googlecode.aviator</groupId>
<artifactId>aviator</artifactId>
<version>${aviator.version}</version>
</dependency>
- 执行方式
执行表达式的方法有两个:execute()、exec();
execute(),需要传递Map格式参数
exec(),不需要传递Map
示例:
/**
* CreateBy: haleyliu
* CreateDate: 2018/12/25
*/
public class Test {
public static void main(String[] args) {
// exec执行方式,无需传递Map格式
String age = "18";
System.out.println(AviatorEvaluator.exec("'His age is '+ age +'!'", age));
// execute执行方式,需传递Map格式
Map<String, Object> map = new HashMap<String, Object>();
map.put("age", "18");
System.out.println(AviatorEvaluator.execute("'His age is '+ age +'!'",
map));
}
}
-
使用函数
Aviator可以使用两种函数:内置函数、自定义函数
(1)内置函数
Aviator内置函数.png

/**
* CreateBy: haleyliu
* CreateDate: 2018/12/25
*/
public class Test {
public static void main(String[] args) {
Map<String,Object> map = new HashMap<>();
map.put("s1","123qwer");
map.put("s2","123");
System.out.println(AviatorEvaluator.execute("string.startsWith(s1,s2)",map));
}
}
(2)自定义函数
自定义函数要继承AbstractFunction类,重写目标方法。
/**
* CreateBy: haleyliu
* CreateDate: 2018/12/25
*/
public class Test {
public static void main(String[] args) {
// 注册自定义函数
AviatorEvaluator.addFunction(new MultiplyFunction());
// 方式1
System.out.println(AviatorEvaluator.execute("multiply(12.23, -2.3)"));
// 方式2
Map<String, Object> params = new HashMap<>();
params.put("a", 12.23);
params.put("b", -2.3);
System.out.println(AviatorEvaluator.execute("multiply(a, b)", params));
}
}
class MultiplyFunction extends AbstractFunction{
@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
double num1 = FunctionUtils.getNumberValue(arg1, env).doubleValue();
double num2 = FunctionUtils.getNumberValue(arg2, env).doubleValue();
return new AviatorDouble(num1 * num2);
}
@Override
public String getName() {
return "multiply";
}
}
-
常用操作符的使用
(1)操作符列表
操作符列表.png
(2)常量和变量

(3)编译表达式
/**
* CreateBy: haleyliu
* CreateDate: 2018/12/25
*/
public class Test {
public static void main(String[] args) {
String expression = "a+(b-c)>100";
// 编译表达式
Expression compiledExp = AviatorEvaluator.compile(expression);
Map<String, Object> env = new HashMap<>();
env.put("a", 100.3);
env.put("b", 45);
env.put("c", -199.100);
// 执行表达式
Boolean result = (Boolean) compiledExp.execute(env);
System.out.println(result);
}
}
(4) 访问数组和集合
List和数组用list[0]和array[0],Map用map.date
/**
* CreateBy: haleyliu
* CreateDate: 2018/12/25
*/
public class Test {
public static void main(String[] args) {
final List<String> list = new ArrayList<>();
list.add("hello");
list.add(" world");
final int[] array = new int[3];
array[0] = 0;
array[1] = 1;
array[2] = 3;
final Map<String, Date> map = new HashMap<>();
map.put("date", new Date());
Map<String, Object> env = new HashMap<>();
env.put("list", list);
env.put("array", array);
env.put("map", map);
System.out.println(AviatorEvaluator.execute(
"list[0]+':'+array[0]+':'+'today is '+map.date", env));
}
}
(5) 三元比较符
/**
* CreateBy: haleyliu
* CreateDate: 2018/12/25
*/
public class Test {
public static void main(String[] args) {
Map<String, Object> env = new HashMap<String, Object>();
env.put("a", -5);
String result = (String) AviatorEvaluator.execute("a>0? 'yes':'no'", env);
System.out.println(result);
}
}
(6) 正则表达式匹配
/**
* CreateBy: haleyliu
* CreateDate: 2018/12/25
*/
public class Test {
public static void main(String[] args) {
String email = "hello2018@gmail.com";
Map<String, Object> env = new HashMap<String, Object>();
env.put("email", email);
String username = (String) AviatorEvaluator.execute("email=~/([\\w0-8]+)@\\w+[\\.\\w+]+/ ? $1 : 'unknow' ", env);
System.out.println(username);
}
}
(7) 变量的语法糖衣
/**
* CreateBy: haleyliu
* CreateDate: 2018/12/25
*/
public class Test {
public static void main(String[] args) {
User user = new User(1,"jack","18");
Map<String, Object> env = new HashMap<>();
env.put("user", user);
String result = (String) AviatorEvaluator.execute(" '[user id='+ user.id + ',name='+user.name + ',age=' +user.age +']' ", env);
System.out.println(result);
}
}
/**
* CreateBy: haleyliu
* CreateDate: 2018/12/25
*/
public class User {
private int id;
private String name;
private String age;
public User() {
}
public User(int id, String name, String age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
}
(8) nil对象[任何对象都比nil大除了nil本身]
nil是Aviator内置的常量,类似java中的null,表示空的值。nil跟null不同的在
于,在java中null只能使用在==、!=的比较运算符,而nil还可以使用>、>=、
<、<=等比较运算符。Aviator规定,[任何对象都比nil大除了nil本身]。用户传入
的变量如果为null,将自动以nil替代。
AviatorEvaluator.execute("nil == nil"); //true
AviatorEvaluator.execute(" 3> nil"); //true
AviatorEvaluator.execute(" true!= nil"); //true
AviatorEvaluator.execute(" ' '>nil "); //true
AviatorEvaluator.execute(" a==nil "); //true,a is null
nil与String相加的时候,跟java一样显示为null
(9) 日期比较
/**
* CreateBy: haleyliu
* CreateDate: 2018/12/25
*/
public class Test {
public static void main(String[] args) {
Map<String, Object> env = new HashMap<String, Object>();
final Date date = new Date();
String dateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SS").format(date);
env.put("date", date);
env.put("dateStr", dateStr);
Boolean result = (Boolean) AviatorEvaluator.execute("date==dateStr",
env);
System.out.println(result);
result = (Boolean) AviatorEvaluator.execute("date > '2009-12-20
00:00:00:00' ", env);
System.out.println(result);
result = (Boolean) AviatorEvaluator.execute("date < '2200-12-20
00:00:00:00' ", env);
System.out.println(result);
result = (Boolean) AviatorEvaluator.execute("date ==date ", env);
System.out.println(result);
}
}
(10) 语法手册
数据类型
-
Number类型:数字类型,支持两种类型,分别对应Java的Long和Double,也就是说任何整数都将被转换为Long,而任何浮点数都将被转换为Double,包括用户传入的数值也是如此转换。不支持科学计数法,仅支持十进制。如-1、100、2.3等。
-
String类型: 字符串类型,单引号或者双引号括起来的文本串,如'hello world',变量如果传入的是String或者Character也将转为String类型。
-
Bool类型: 常量true和false,表示真值和假值,与java的Boolean.TRUE和Boolean.False对应。
-
Pattern类型: 类似Ruby、perl的正则表达式,以//括起来的字符串,如//d+/,内部实现为java.util.Pattern。
-
变量类型: 与Java的变量命名规则相同,变量的值由用户传入,如"a"、"b"等
-
nil类型: 常量nil,类似java中的null,但是nil比较特殊,nil不仅可以参与==、!=的比较,也可以参与>、>=、<、<=的比较,Aviator规定任何类型都n大于nil除了nil本身,nil==nil返回true。用户传入的变量值如果为null,那么也将作为nil处理,nil打印为null。
算术运算符
Aviator支持常见的算术运算符,包括+ - <tt></tt> / % 五个二元运算符,和一元运算符"-"。其中 - <tt></tt> / %和一元的"-"仅能作用于Number类型。
"+"不仅能用于Number类型,还可以用于String的相加,或者字符串与其他对象的相加。Aviator规定,任何类型与String相加,结果为String。
逻辑运算符
Avaitor的支持的逻辑运算符包括,一元否定运算符"!",以及逻辑与的"&&",逻辑或的"||"。逻辑运算符的操作数只能为Boolean。
关系运算符
Aviator支持的关系运算符包括"<" "<=" ">" ">=" 以及"=="和"!=" 。
&&和||都执行短路规则。
关系运算符可以作用于Number之间、String之间、Pattern之间、Boolean之间、变量之间以及其他类型与nil之间的关系比较,不同类型除了nil之外不能相互比较。
Aviator规定任何对象都比nil大除了nil之外。
匹配运算符
匹配运算符"=~"用于String和Pattern的匹配,它的左操作数必须为String,右操作数必须为Pattern。匹配成功后,Pattern的分组将存于变量$num,num为分组索引。
三元运算符
Aviator没有提供if else语句,但是提供了三元运算符 "?:",形式为 bool ? exp1: exp2。 其中bool必须为结果为Boolean类型的表达式,而exp1和exp2可以为任何合法的Aviator表达式,并且不要求exp1和exp2返回的结果类型一致。
- 两种模式
默认AviatorEvaluator以编译速度优先:
AviatorEvaluator.setOptimize(AviatorEvaluator.COMPILE);
你可以修改为运行速度优先,这会做更多的编译优化:
AviatorEvaluator.setOptimize(AviatorEvaluator.EVAL);
三.MVEL表达式解析器
1.简介 :
MVEL在很大程度上受到Java语法的启发,作为一个表达式语言,也有一些根本
的区别,旨在更高的效率,例如:直接支持集合、数组和字符串匹配等操作以
及正则表达式。 MVEL用于执行使用Java语法编写的表达式。
2.特性:
MVEL是一个功能强大的基于Java应用程序的表达式语言。
目前最新的版本是2.0,具有以下特性:
(1). 动态JIT优化器。当负载超过一个确保代码产生的阈值时,选择性地产生字
节代码,这大大减少了内存的使用量。新的静态类型检查和属性支持,允许集成
类型安全表达。
(2). 错误报告的改善。包括行和列的错误信息。
(3). 新的脚本语言特征。MVEL2.0 包含函数定义,如:闭包,lambda定义,
标准循环构造(for, while, do-while, do-until…),空值安全导航操作,内联with
-context运营 ,易变的(isdef)的测试运营等等。
(4). 改进的集成功能。迎合主流的需求,MVEL2.0支持基础类型的个性化属性处理器,集成到JIT中。
(5). 更快的模板引擎,支持线性模板定义,宏定义和个性化标记定义。
(6). 新的交互式shell(MVELSH)。
(7). 缺少可选类型安全
(8). 集成不良,通常通过映射填入内容。没有字节码不能运作用字节码生成编
译时间慢,还增加了可扩展性问题;不用字节码生成运行时执行非常慢
(9). 内存消耗过大
(10). Jar巨大/依赖规模
3.原理:
与java不同,MVEL是动态类型(带有可选分类),也就是说在源文件中是没有
类型限制的。一条MVEL表达式,简单的可以是单个标识符,复杂的则可能是
一个充满了方法调用和内部集合创建的庞大的布尔表达式。
4.使用方式:
maven引入jar:
<dependency>
<groupId>org.mvel</groupId>
<artifactId>mvel2</artifactId>
<version>2.3.1.Final</version>
</dependency>
测试:
package com.lrq.wechatdemo.utils;
import com.google.common.collect.Maps;
import org.mvel2.MVEL;
import java.util.Map;
/**
* CreateBy: haleyliu
* CreateDate: 2018/12/26
*/
public class MvelUtils {
public static void main(String[] args) {
String expression = "a == null && b == nil ";
Map<String,Object> map = Maps.newHashMap();
map.put("a",null);
map.put("b",null);
Object object = MVEL.eval(expression,map);
System.out.println(object);
}
}
四.EasyRules规则引擎
1.简介:
easy-rules首先集成了mvel表达式,后续可能集成SpEL的一款轻量
级规则引擎
2.特性:
easy rules是一个简单而强大的java规则引擎,它有以下特性:
轻量级框架,学习成本低
基于POJO
为定义业务引擎提供有用的抽象和简便的应用
从原始的规则组合成复杂的规则
它主要包括几个主要的类或接口:Rule,RulesEngine,RuleListener,Facts
还有几个主要的注解:@Action,@Condition,@Fact,@Priority,@Rule
3.使用方式:
有两种使用方式:
- java方式
首先先创建规则并标注属性
package com.lrq.wechatdemo.rules;
import org.jeasy.rules.annotation.Action;
import org.jeasy.rules.annotation.Condition;
import org.jeasy.rules.annotation.Fact;
import org.jeasy.rules.annotation.Rule;
import org.jeasy.rules.support.UnitRuleGroup;
/**
* CreateBy: haleyliu
* CreateDate: 2018/12/26
*/
public class RuleClass {
@Rule(priority = 1) //规则设定优先级
public static class FizzRule {
@Condition
public boolean isFizz(@Fact("number") Integer number) {
return number % 5 == 0;
}
@Action
public void printFizz() {
System.out.print("fizz\n");
}
}
@Rule(priority = 2)
public static class BuzzRule {
@Condition
public boolean isBuzz(@Fact("number") Integer number) {
return number % 7 == 0;
}
@Action
public void printBuzz() {
System.out.print("buzz\n");
}
}
public static class FizzBuzzRule extends UnitRuleGroup {
public FizzBuzzRule(Object... rules) {
for (Object rule : rules) {
addRule(rule);
}
}
@Override
public int getPriority() {
return 0;
}
}
@Rule(priority = 3)
public static class NonFizzBuzzRule {
@Condition
public boolean isNotFizzNorBuzz(@Fact("number") Integer number) {
// can return true, because this is the latest rule to trigger according to
// assigned priorities
// and in which case, the number is not fizz nor buzz
return number % 5 != 0 || number % 7 != 0;
}
@Action
public void printInput(@Fact("number") Integer number) {
System.out.print(number+"\n");
}
}
}
然后客户端调用
package com.lrq.wechatdemo.rules;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.api.RulesEngine;
import org.jeasy.rules.core.DefaultRulesEngine;
import org.jeasy.rules.core.RulesEngineParameters;
/**
* CreateBy: haleyliu
* CreateDate: 2018/12/26
*/
public class RuleJavaClient {
public static void main(String[] args) {
// 创建规则引擎
RulesEngineParameters parameters = new RulesEngineParameters().skipOnFirstAppliedRule(true);
RulesEngine fizzBuzzEngine = new DefaultRulesEngine(parameters);
// 创建规则集并注册规则
Rules rules = new Rules();
rules.register(new RuleClass.FizzRule());
rules.register(new RuleClass.BuzzRule());
rules.register(new RuleClass.FizzBuzzRule(new RuleClass.FizzRule(), new RuleClass.BuzzRule()));
rules.register(new RuleClass.NonFizzBuzzRule());
// 执行规则
Facts facts = new Facts();
for (int i = 1; i <= 100; i++) {
facts.put("number", i);
fizzBuzzEngine.fire(rules, facts);
System.out.println();
}
}
}
2.yml方式
resources目录下新建fizzbuzz.yml
---
name: "fizz rule"
description: "print fizz if the number is multiple of 5"
priority: 1
condition: "number % 5 == 0"
actions:
- "System.out.println(\"fizz\")"
---
name: "buzz rule"
description: "print buzz if the number is multiple of 7"
priority: 2
condition: "number % 7 == 0"
actions:
- "System.out.println(\"buzz\")"
---
name: "fizzbuzz rule"
description: "print fizzbuzz if the number is multiple of 5 and 7"
priority: 0
condition: "number % 5 == 0 && number % 7 == 0"
actions:
- "System.out.println(\"fizzbuzz\")"
---
name: "non fizzbuzz rule"
description: "print the number itself otherwise"
priority: 3
condition: "number % 5 != 0 || number % 7 != 0"
actions:
- "System.out.println(number)"
客户端调用:
package com.lrq.wechatdemo.rules;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.api.RulesEngine;
import org.jeasy.rules.core.DefaultRulesEngine;
import org.jeasy.rules.core.RulesEngineParameters;
import org.jeasy.rules.mvel.MVELRuleFactory;
import java.io.FileNotFoundException;
import java.io.FileReader;
/**
* CreateBy: haleyliu
* CreateDate: 2018/12/26
*/
public class RuleYmlClient {
public static void main(String[] args) throws FileNotFoundException {
// create a rules engine
RulesEngineParameters parameters = new RulesEngineParameters().skipOnFirstAppliedRule(true);
RulesEngine fizzBuzzEngine = new DefaultRulesEngine(parameters);
// create rules
Rules rules = MVELRuleFactory.createRulesFrom(new FileReader("fizzbuzz.yml"));
// fire rules
Facts facts = new Facts();
for (int i = 1; i <= 100; i++) {
facts.put("number", i);
fizzBuzzEngine.fire(rules, facts);
System.out.println();
}
}
}

http://www.findsrc.com/java/detail/8664
Java表达式引擎fel/groovy/expression4j/java脚本引擎的性能对比【原创】
发布时间:2016-06-07 10:48:10
有 7221 人浏览来源:码云网又是性能对比,最近跟性能较上劲了。
产品中需要用到数学表达式,表达式不复杂,但是对性能要求比较高。选用了一些常用的表达式引擎计算方案,包含:java脚本引擎(javax/script)、groovy脚本引擎、Expression4j、Fel表达式引擎。
其中java脚本引擎使用了解释执行和编译执行两种方式、groovy脚本只采用了编译执行(解释执行太慢)、Fel采用了静态参数和动态参数两种方式。以下为测试代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
public class ExpressionTest extends BaseTest { private int count = 100000 ; //javax的编译执行,效率比解释执行略高?为什么才略高?? @Test public void testCompiledJsScript() throws Throwable { javax.script.ScriptEngine se = new ScriptEngineManager().getEngineByName( "js" ); Compilable ce = (Compilable) se; CompiledScript cs = ce.compile( "a*b*c" ); Bindings bindings = se.createBindings(); bindings.put( "a" , 3600 ); bindings.put( "b" , 14 ); bindings.put( "c" , 4 ); long start = System.currentTimeMillis(); for ( int i = 0 ; i < count ; i++) { cs.eval(bindings); } System.out. println (System.currentTimeMillis() - start); } //javax script解释执行 @Test public void testJsScript() throws Throwable { javax.script.ScriptEngine se = new ScriptEngineManager().getEngineByName( "js" ); Bindings bindings = se.createBindings(); bindings.put( "a" , 3600 ); bindings.put( "b" , 14 ); bindings.put( "c" , 4 ); long start = System.currentTimeMillis(); for ( int i = 0 ; i < count ; i++) { se.eval( "a*b*c" , bindings); } System.out. println (System.currentTimeMillis() - start); } //groovy的编译执行 @Test public void testGroovy() { //这里的ScriptEngine和GroovyScriptEngine是自己编写的类,不是原生的 ScriptEngine se = this.getBean(GroovyScriptEngine. class ); Map<String, Object> paramMap = new HashMap<String, Object>(); paramMap.put( "param" , 5 ); //ScriptEngine首次执行会缓存编译后的脚本,这里故意先执行一次便于缓存 se.eval( "3600*34*param" , paramMap); long start = System.currentTimeMillis(); for ( int i = 0 ; i < count ; i++) { se.eval( "3600*34*param" , paramMap); } System.out. println (System.currentTimeMillis() - start); } //Expression4J的表达式引擎,这里是通过函数的方式,有点特别 @Test public void testExpression4j() throws Throwable { Expression expression = ExpressionFactory.createExpression( "f(a,b,c)=a*b*c" ); System.out. println ( "Expression name: " + expression.getName()); System.out. println ( "Expression parameters: " + expression.getParameters()); MathematicalElement element_a = NumberFactory.createReal( 3600 ); MathematicalElement element_b = NumberFactory.createReal( 34 ); MathematicalElement element_c = NumberFactory.createReal( 5 ); Parameters parameters = ExpressionFactory.createParameters(); parameters.addParameter( "a" , element_a); parameters.addParameter( "b" , element_b); parameters.addParameter( "c" , element_c); long start = System.currentTimeMillis(); for ( int i = 0 ; i < count ; i++) { expression.evaluate(parameters); } System.out. println (System.currentTimeMillis() - start); } //fel的表达式引擎(静态参数,同上面) @Test public void felTest() { FelEngine e = FelEngine.instance; final FelContext ctx = e.getContext(); ctx.set( "a" , 3600 ); ctx.set( "b" , 14 ); ctx.set( "c" , 5 ); com.greenpineyu.fel.Expression exp = e.compile( "a*b*c" , ctx); long start = System.currentTimeMillis(); Object eval = null ; for ( int i = 0 ; i < count ; i++) { eval = exp.eval(ctx); } System.out. println (System.currentTimeMillis() - start); System.out. println (eval); } //fel表达式引擎(动态参数,这里动态参数的产生和变量改变都会消耗时间,因此这个测试时间不准确,只是验证对于动态参数的支持) @Test public void felDynaTest() { FelEngine e = FelEngine.instance; final FelContext ctx = e.getContext(); ctx.set( "a" , 3600 ); ctx.set( "b" , 14 ); ctx.set( "c" , 5 ); com.greenpineyu.fel.Expression exp = e.compile( "a*b*c" , ctx); long start = System.currentTimeMillis(); Object eval = null ; Random r = new Random(); for ( int i = 0 ; i < count ; i++) { ctx.set( "a" , r.nextInt( 10000 )); ctx.set( "b" , r.nextInt( 100 )); ctx.set( "c" , r.nextInt( 100 )); eval = exp.eval(ctx); } System.out. println (System.currentTimeMillis() - start); System.out. println (eval); } public static void main(String[] args) throws Throwable { ExpressionTest et = new ExpressionTest(); //执行100W次的测试 et. count = 1000000 ; et.testCompiledJsScript(); et.testJsScript(); et.testExpression4j(); et.testGroovy(); et.felTest(); } } |
测试结果如下:
表达式引擎 | 执行时间(毫秒) | 备注 |
java脚本引擎编译后执行 |
7662 |
|
java脚本引擎解释执行 | 10609 | |
expression4j | 578 | |
groovy编译执行 | 224 | |
fel静态参数 | 19 | |
fel动态参数 | 107 | 该项测试比较不公平,随机数的产生以及参数的变更也会占用一定时间,测试目的只是为了验证是不是存在静态优化,从而导致静态性能远高于动态性能的情况。 |
结论:
从以上性能对比来看(抛开表达式的功能),fel明显占据很大优势,groovy和expression4j也是可以接受的。java脚本引擎的执行偏慢。因此,对于表达式不是很复杂性能要求高的情况下,推荐使用fel或者groovy编译执行的方式。
QQ群:762080163