Java中动态规则的实现方式

在Struts 2 的标签库中都是使用OGNL表达式访问ApplicationContext中的对象数据,简单示例:

复制代码
Foo foo = new Foo();
foo.setName(“test”);
Map<String, Object> context = new HashMap<String, Object>();
context.put(“foo”,foo);
String expression = “foo.name == ‘test’”;
try {
Boolean result = (Boolean) Ognl.getValue(expression,context);
System.out.println(result);
} catch (OgnlException e) {
e.printStackTrace();
}
复制代码
MVEL

MVEL最初作为Mike Brock创建的 Valhalla项目的表达式计算器(expression evaluator),相比最初的OGNL、JEXL和JUEL等项目,而它具有远超它们的性能、功能和易用性 - 特别是集成方面。它不会尝试另一种JVM语言,而是着重解决嵌入式脚本的问题。

MVEL主要使用在Drools,是Drools规则引擎不可分割的一部分。

MVEL语法较为丰富,不仅包含了基本的属性表达式,布尔表达式,变量复制和方法调用,还支持函数定义,详情参见MVEL Language Guide 。

MVEL在执行语言时主要有解释模式(Interpreted Mode)和编译模式(Compiled Mode )两种:

解释模式(Interpreted Mode)是一个无状态的,动态解释执行,不需要负载表达式就可以执行相应的脚本。
编译模式(Compiled Mode)需要在缓存中产生一个完全规范化表达式之后再执行。
复制代码
//解释模式
Foo foo = new Foo();
foo.setName(“test”);
Map context = new HashMap();
String expression = “foo.name == ‘test’”;
VariableResolverFactory functionFactory = new MapVariableResolverFactory(context);
context.put(“foo”,foo);
Boolean result = (Boolean) MVEL.eval(expression,functionFactory);
System.out.println(result);

//编译模式
Foo foo = new Foo();foo.setName(“test”);
Map context = new HashMap();
String expression = “foo.name == ‘test’”;
VariableResolverFactory functionFactory = new MapVariableResolverFactory(context);context.put(“foo”,foo);
Serializable compileExpression = MVEL.compileExpression(expression);
Boolean result = (Boolean) MVEL.executeExpression(compileExpression, context, functionFactory);
复制代码
SpEL

SpEl(Spring表达式语言)是一个支持查询和操作运行时对象导航图功能的强大的表达式语言。 它的语法类似于传统EL,但提供额外的功能,最出色的就是函数调用和简单字符串的模板函数。SpEL类似于Struts2x中使用的OGNL表达式语言,能在运行时构建复杂表达式、存取对象图属性、对象方法调用等等,并且能与Spring功能完美整合,如能用来配置Bean定义。

SpEL主要提供基本表达式、类相关表达式及集合相关表达式等,详细参见Spring 表达式语言 (SpEL) 。

类似与OGNL,SpEL具有expression(表达式),Parser(解析器),EvaluationContext(上下文)等基本概念;类似与MVEL,SpEl也提供了解释模式和编译模式两种运行模式。

复制代码
//解释器模式
Foo foo = new Foo();
foo.setName(“test”);
// Turn on:
// - auto null reference initialization
// - auto collection growing
SpelParserConfiguration config = new SpelParserConfiguration(true,true);
ExpressionParser parser = new SpelExpressionParser(config);
String expressionStr = “#foo.name == ‘test’”;
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable(“foo”,foo);
Expression expression = parser.parseExpression(expressionStr);
Boolean result = expression.getValue(context,Boolean.class);

//编译模式
config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, RunSpel.class.getClassLoader());
parser = new SpelExpressionParser(config);
context = new StandardEvaluationContext();
context.setVariable(“foo”,foo);
expression = parser.parseExpression(expressionStr);
result = expression.getValue(context,Boolean.class);
复制代码
规则引擎
一些规则引擎(rule engine):aviator,easy-rules,drools,esper

aviator

AviatorScript 是一门高性能、轻量级寄宿于 JVM 之上的脚本语言。

使用场景包括:

规则判断及规则引擎
公式计算
动态脚本控制
集合数据 ELT 等
复制代码
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);

}
}
复制代码
easy-rules

Easy Rules is a Java rules engine。

使用POJO定义规则:

复制代码
@Rule(name = “weather rule”, description = “if it rains then take an umbrella”)
public class WeatherRule {

@Condition
public boolean itRains(@Fact("rain") boolean rain) {
    return rain;
}

@Action
public void takeAnUmbrella() {
    System.out.println("It rains, take an umbrella!");
}

}

Rule weatherRule = new RuleBuilder()
.name(“weather rule”)
.description(“if it rains then take an umbrella”)
.when(facts -> facts.get(“rain”).equals(true))
.then(facts -> System.out.println(“It rains, take an umbrella!”))
.build();
复制代码
支持使用表达式语言(MVEL/SpEL)来定义规则:

weather-rule.yml example:

name: “weather rule”
description: “if it rains then take an umbrella”
condition: “rain == true”
actions:

  • “System.out.println(“It rains, take an umbrella!”);”
    MVELRuleFactory ruleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader());
    Rule weatherRule = ruleFactory.createRule(new FileReader(“weather-rule.yml”));
    触发规则:

复制代码
public class Test {
public static void main(String[] args) {
// define facts
Facts facts = new Facts();
facts.put(“rain”, true);

    // define rules
    Rule weatherRule = ...
    Rules rules = new Rules();
    rules.register(weatherRule);

    // fire rules on known facts
    RulesEngine rulesEngine = new DefaultRulesEngine();
    rulesEngine.fire(rules, facts);
}

}
复制代码
drools

An open source rule engine, DMN engine and complex event processing (CEP) engine for Java and the JVM Platform.

定义规则:

复制代码
import com.lrq.wechatDemo.domain.User // 导入类
dialect “mvel”
rule “age” // 规则名,唯一
when
$user : User(age<15 || age>60) //规则的条件部分
then
System.out.println(“年龄不符合要求!”);
end
复制代码
参考例子:

复制代码
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();
}

}
复制代码
esper

Esper is a component for complex event processing (CEP), streaming SQL and event series analysis, available for Java as Esper, and for .NET as NEsper.

一个例子:

复制代码
public class Test {
public static void main(String[] args) throws InterruptedException {
EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider();

    EPAdministrator admin = epService.getEPAdministrator();

    String product = Apple.class.getName();
    String epl = "select avg(price) from " + product + ".win:length_batch(3)";

    EPStatement state = admin.createEPL(epl);
    state.addListener(new AppleListener());

    EPRuntime runtime = epService.getEPRuntime();

    Apple apple1 = new Apple();
    apple1.setId(1);
    apple1.setPrice(5);
    runtime.sendEvent(apple1);

    Apple apple2 = new Apple();
    apple2.setId(2);
    apple2.setPrice(2);
    runtime.sendEvent(apple2);

    Apple apple3 = new Apple();
    apple3.setId(3);
    apple3.setPrice(5);
    runtime.sendEvent(apple3);
}

}
复制代码
drools和esper都是比较重的规则引擎,详见其官方文档。

动态JVM语言
Groovy

Groovy除了Gradle 上的广泛应用之外,另一个大范围的使用应该就是结合Java使用动态代码了。Groovy的语法与Java非常相似,以至于多数的Java代码也是正确的Groovy代码。Groovy代码动态的被编译器转换成Java字节码。由于其运行在JVM上的特性,Groovy可以使用其他Java语言编写的库。

Groovy可以看作给Java静态世界补充动态能力的语言,同时Groovy已经实现了java不具备的语言特性:

函数字面值;
对集合的一等支持;
对正则表达式的一等支持;
对xml的一等支持;
Groovy作为基于JVM的语言,与表达式语言存在语言级的不同,因此在语法上比表达还是语言更灵活。Java在调用Groovy时,都需要将Groovy代码编译成Class文件。

Groovy 可以采用GroovyClassLoader、GroovyShell、GroovyScriptEngine和JSR223 等方式与Java语言集成。

一个使用GroovyClassLoader动态对json对象进行filter的例子:

复制代码
public class GroovyFilter implements Filter {
private static String template = “” +
“package com.alarm.eagle.filter;” +
“import com.fasterxml.jackson.databind.node.ObjectNode;” +
“def match(ObjectNode o){[exp]}”;

private static String method = "match";

private String filterExp;

private transient GroovyObject filterObj;

public GroovyFilter(String filterExp) throws Exception {
    ClassLoader parent = Thread.currentThread().getContextClassLoader();
    GroovyClassLoader classLoader = new GroovyClassLoader(parent);
    Class clazz = classLoader.parseClass(template.replace("[exp]", filterExp));
    filterObj = (GroovyObject)clazz.newInstance();
}

public boolean filter(ObjectNode objectNode) {
    return (boolean)filterObj.invokeMethod(method, objectNode);
}

}
龙华大道1号http://www.kinghill.cn/LongHuaDaDao1Hao/index.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值