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

参考原文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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值