介绍一款基于MVEL简单规则引擎

来源:互联网 发布:如何注册淘宝联盟账号 编辑:程序博客网 时间:2024/05/21 17:37

参考原文A Really Simple But Powerful Rule Engine

MVEL 介绍

最近正好有做规则引擎相关的需求,预研了一下,并找到一些可以满足我需求的技术。引入一个东西——MVEL,怎么定义MVEL表达式,参看MVEL Guide。

来一段代码看一下MVEL的功能,首先引入MVEL解析库:

    compile 'org.mvel:mvel2:2.3.2.Final'

下图显示的是本文所用到的Java Bean类:
这里写图片描述

MVEL example:
 @Test    public void testMvel() {        String rule1 = "(!(input.person.age < 26) && !(input.person.age > 59)) && input.account.ageInMonths > 24";        // compile表达式 异常表达式会报错         Serializable serializable = MVEL.compileExpression(rule1);        TarifRequest request = new TarifRequest();        request.setPerson(new Person());        request.setAccount(new Account());        request.getPerson().setAge(30);        request.getPerson().setName("jack");        request.getAccount().setAgeInMonths(25);        Map<String, TarifRequest> vars = new HashMap<>();        vars.put("input", request);        boolean res = (boolean) MVEL.executeExpression(serializable, vars);        System.out.println(res);   // true        String rule2 = "input.person.name == 'tom'";        boolean res1 = (boolean) MVEL.executeExpression(MVEL.compileExpression(rule2), vars);        System.out.println(res1);  // false        String rule3 = "['jack', 'tom', 'hanson'].contains(input.person.name)";        boolean res2 = (boolean) MVEL.executeExpression(MVEL.compileExpression(rule3), vars);        System.out.println(res2);    //true        // MVEL.eval() 直接计算出表达式的值         System.out.println(MVEL.eval(rule2, vars));  //false    }

基于MVEL的 简单规则引擎

github源码地址
引入依赖:

    compile 'ch.maxant:rules:2.2.1'
1. 执行规则

这个规则引擎比较简单,我居然都能看懂里面的源码,看测试代码:

 @Test    public void testRules() throws Exception {        Rule r1 = new Rule("one", "input.person.age < 26", "YT2011", 3, "ch.maxant.someapp.tarifs", null);        Rule r2 = new Rule("two", "input.person.age > 59", "ST2011", 3, "ch.maxant.someapp.tarifs", null);        Rule r3 = new Rule("three", "!#one && !#two", "DT2011", 3, "ch.maxant.someapp.tarifs", null);        Rule r4 = new Rule("four", "#three && input.account.ageInMonths > 24", "LT2011", 4, "ch.maxant.someapp.tarifs", null);        // 默认规则        Rule defaultRule = new Rule("five", "true", "default", -1, "ch.maxant.someapp.tarifs", null);        List<Rule> rules = Arrays.asList(r1, r2, r3, r4, defaultRule);        // 初始化并用MVEL解析器编译规则        Engine engine = new Engine(rules, true);        TarifRequest request = new TarifRequest();        request.setPerson(new Person());        request.setAccount(new Account());        request.setDefaultRuleFlag(true);        request.getPerson().setAge(30);        request.getAccount().setAgeInMonths(5);        // 获取优先级最高的匹配规则        String tarif = engine.getBestOutcome(request);        System.out.println(tarif);    }

执行大概流程图如下:
规则解析流程图
当没有规则匹配的时候,就返回默认规则的结果。

2. 使用SubRule编写更复杂的规则
   @Test    public void testSubRules() throws Exception {        Rule rule1 = new SubRule("longdistance", "input.distance > 100", "ch.maxant.produkte", null);        Rule rule2 = new SubRule("firstclass", "input.map[\"travelClass\"] == 1", "ch.maxant.produkte", null);        Rule rule3 = new Rule("productA", "#longdistance && #firstclass", "productA", 3, "ch.maxant.produkte", null);        List<Rule> rules = Arrays.asList(rule1, rule2, rule3);        Engine e = new Engine(rules, true);        TravelRequest request = new TravelRequest(150);        request.put("travelClass", 1);        List<Rule> rs = e.getMatchingRules(request);        System.out.println(rs);    }

规则引擎在解析的时候,SubRule的规则都将被丢弃,只执行rule3的规则,rule3被替换成了:

Rule rule3 = new Rule("productA", "(input.distance > 100) && (input.map["travelClass"] == 1)", "productA", 3, "ch.maxant.produkte", null);
3. 根据规则执行具体的操作
@Test    public void testRulesAction() throws Exception {        Rule r1 = new Rule("SendEmailToUser", "input.config.sendUserEmail == true", "SendEmailToUser", 1, "ch.maxant.someapp.config", null);        Rule r2 = new Rule("SendEmailToModerator", "input.config.sendAdministratorEmail == true and input.user.numberOfPostings < 5", "SendEmailToModerator", 2, "ch.maxant.someapp.config", null);        List<Rule> rules = Arrays.asList(r1, r2);        final List<String> log = new ArrayList<>();        AbstractAction<ForumSetup, Void> a1 = new AbstractAction<ForumSetup, Void>("SendEmailToUser") {            @Override            public Void execute(ForumSetup input) {                log.add("Sending email to user!");                return null;            }        };        AbstractAction<ForumSetup, Void> a2 = new AbstractAction<ForumSetup, Void>("SendEmailToModerator") {            @Override            public Void execute(ForumSetup input) {                log.add("Sending email to moderator!");                return null;            }        };        Engine engine = new Engine(rules, true);        ForumSetup setup = new ForumSetup();        Config config = new Config();        setup.setConfig(config);        User user = new User();        setup.setUser(user);        setup.getConfig().setSendUserEmail(true);        setup.getConfig().setSendAdministratorEmail(true);        setup.getUser().setNumberOfPostings(2);        // executeBestAction() 执行优先级较高规则的action        engine.executeAllActions(setup, Arrays.asList(a1, a2));

rule和action对应关系
执行操作也挺简单的,rule的outcome和action的name是一一对应的关系,从匹配到的规则里获取outcome,然后通过outcome获取action,最后action执行具体的操作,这个逻辑没毛病,但感觉rule和action有辣么一点耦合关系,有值得改进的地方,等大伙看源码去深挖吧。

其他的规则引擎:
easy-rules
Rulette

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 小学生手册丢了怎么办 自己不会写论文怎么办 写论文很心慌怎么办 写论文没有词怎么办 亲人入了邪教怎么办 小孩脾气很倔怎么办 研究生读不下去怎么办 国外打工生活费不够怎么办 本科学位被追回怎么办 本科学位丢了怎么办 国外留学挂科怎么办 英国预科被劝退怎么办? 如果预科没合格怎么办 研究生学费太贵怎么办 澳洲移民配额用不完怎么办 去美国探亲怎么办签证 去伊朗的签证怎么办 房产证被偷了怎么办 打黑工被发现怎么办 几年前被犬咬没打针怎么办 对狂犬疫苗过敏怎么办 想去墨尔本留学怎么办 大学没交学费会怎么办 交学费收据丢了怎么办 上海浦东金科苑幼儿园统筹怎么办 红酒瓶塞掉了怎么办 红酒瓶塞丢了怎么办 收入证明没有公章怎么办 父母没工作怎么办签证 在温哥华怎么办新西兰签证 上班第一天无聊怎么办 上班紧张不自信怎么办 销售到了30岁怎么办 转行会计没经验怎么办 澳洲coe被取消怎么办 父母不同意嫁远怎么办 家人不同意我们在一起怎么办 语言课申请不到怎么办 墨尔本大学均分不够怎么办 去澳洲旅游签证怎么办 换新护照澳大利亚签证怎么办