参考原文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)
        String rule2 = 
"input.person.name == 'tom'"
        boolean res1 = (boolean) MVEL
.executeExpression(MVEL
.compileExpression(rule2), vars)
        System
.out.println(res1)
        String rule3 = 
"['jack', 'tom', 'hanson'].contains(input.person.name)"
        boolean res2 = (boolean) MVEL
.executeExpression(MVEL
.compileExpression(rule3), vars)
        System
.out.println(res2)
        // MVEL
.eval() 直接计算出表达式的值 
        System
.out.println(MVEL
.eval(rule2, vars))
    } 
基于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);
        
        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);
        
        engine
.executeAllActions(setup, Arrays
.asList(a1, a2)); 
  执行操作也挺简单的,rule的outcome和action的name是一一对应的关系,从匹配到的规则里获取outcome,然后通过outcome获取action,最后action执行具体的操作,这个逻辑没毛病,但感觉rule和action有辣么一点耦合关系,有值得改进的地方,等大伙看源码去深挖吧。
 
其他的规则引擎:  easy-rules  Rulette