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

xiaoxiao2021-02-28  29

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

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

转载请注明原文地址: https://www.6miu.com/read-1100005.html

最新回复(0)