Introduction to the use of java lightweight rule engine easy rules

We often need a lot of if/else when writing business code, which will greatly reduce the readability of the code. Is there a way to avoid a large number of judgment statements in the code?

The answer is to use a rule engine, but traditional rule engines are heavy, such as open source Drools, which is not suitable for small requirements. Recently, I saw a fool like Java rule engine easy rules on github. Here, combined with my demo, I will introduce how to use this rule engine. I hope it will be helpful to you.

Features of easy rules

1 Lightweight class libraries and easy to use
2 be based on POJO Development and annotation of programming model
3 be based on MVEL Programming model of expression (applicable to very simple rules, generally not recommended)
4 Support the creation of composite rules based on simple rules
5 Convenient and suitable for java Abstract business model rules

 

concept

To understand the rule engine, let's first understand several concepts, as shown in the figure

 

We see

1) facts indicates the parameters of the key:value structure currently passed in

2) A rule is a whole rule

3) Condition is the judgment condition of rule

4) Action is the action that needs to be triggered after the Condition is met

The whole logic is to traverse the rules when a facts parameter object is passed in. Each rule judges the condition of the rule. If the condition is met, it triggers the execution of the corresponding business logic.

In fact, the overall logic is still a concept similar to if/else

 

It mainly includes several main classes or interfaces: Rule,RulesEngine,RuleListener,Facts

There are also several main comments: @ Action,@Condition,@Fact,@Priority,@Rule

 

Implementation methods of easy rules (2 kinds)

  1. Implement the Rule interface and its evaluate and execute methods.
  2. Decorate POJO s with @ Rule annotation

 

actual combat

Example 1: programming model based on POJO development and annotation: judge the number divided by 3 or 8 in 1-50

Write rule POJO:

 1 @Rule(name = "Divided by 3", description = "number If divided by 3, print: number is three")
 2 public class ThreeRule {
 3   /**
 4    * Condition:Condition judgment comment: if return true, execute Action
 5    *
 6    * @param number
 7    * @return
 8    */
 9   @Condition
10   public boolean isThree(@Fact("number") int number) {
11     return number % 3 == 0;
12   }
13 
14   /**
15    * Action Execution method annotation
16    *
17    * @param number
18    */
19   @Action
20   public void threeAction(@Fact("number") int number) {
21     System.out.println(number + " is three");
22   }
23 
24   /**
25    * Priority:Priority note: the smaller the return value, the higher the priority
26    *
27    * @return
28    */
29   @Priority
30   public int getPriority() {
31     return 1;
32   }
33 }
 1 @Rule(name = "Divided by 8")
 2 public class EightRule {
 3 
 4   /**
 5    * condition
 6    *
 7    * @param number
 8    * @return
 9    */
10   @Condition
11   public boolean isEight(@Fact("number") int number) {
12     return number % 8 == 0;
13   }
14 
15   /**
16    * Actions that meet conditions
17    *
18    * @param number
19    */
20   @Action
21   public void eightAction(@Fact("number") int number) {
22     System.out.println(number + " is eight");
23   }
24 
25   /**
26    * Priority of conditional judgment
27    *
28    * @return
29    */
30   @Priority
31   public int getPriority() {
32     return 2;
33   }
34 }
 1 @Rule(name = "Divided by 3 and 8 at the same time", description = "This is a combination rule")
 2 public class ThreeEightRuleUnitGroup extends UnitRuleGroup {
 3 
 4   public ThreeEightRuleUnitGroup(Object... rules) {
 5     for (Object rule : rules) {
 6       addRule(rule);
 7     }
 8   }
 9 
10   @Override
11   public int getPriority() {
12     return 0;
13   }
14 }
 1 @Rule(name = "Neither divisible by 3 nor divisible by 8", description = "Print number own")
 2 public class OtherRule { 
 3   @Condition
 4   public boolean isOther(@Fact("number") int number){
 5     return number % 3 != 0 || number % 8 != 0;
 6   }
 7 
 8   @Action
 9   public void printSelf(@Fact("number") int number){
10     System.out.print(number);
11   }
12 
13   @Priority
14   public int getPriority(){
15     return 3;
16   }
17 }
 1 public class ThreeEightRuleLauncher {
 2 
 3   public static void main(String[] args) {
 4     /**
 5      * Create rule execution engine
 6      * Note: skiponfirstapplied rule means that as long as the first rule is matched, the following rule matching will be skipped
 7      */
 8     RulesEngineParameters parameters = new 
 9     RulesEngineParameters().skipOnFirstAppliedRule(true);
10     RulesEngine rulesEngine = new DefaultRulesEngine(parameters);
11     //Create rule
12     Rules rules = new Rules();
13     rules.register(new EightRule());
14     rules.register(new ThreeRule());
15     rules.register(new ThreeEightRuleUnitGroup(new EightRule(), new ThreeRule()));
16     rules.register(new OtherRule());
17     Facts facts = new Facts();
18     for (int i=1 ; i<=50 ; i++){
19       //Rule factor, corresponding name,And the rules@Fact agreement
20       facts.put("number", i);
21       //Execution rules
22       rulesEngine.fire(rules, facts);
23       System.out.println();
24     }
25   }
26 }

Example 2: programming model based on MVEL expression

This example demonstrates how to use MVEL expressions to define rules. MVEL is provided through the easy rules MVEL module. This module contains an API for defining rules using MVEL. We will use these APIs here. The goal is to implement a simple store application. The requirements are as follows: children are prohibited from buying alcohol, and the minimum legal age for adults is 18. Store customers are defined by the Person class:

 1 @Data
 2 @AllArgsConstructor
 3 @NoArgsConstructor
 4 public class Person {
 5   private String name;
 6 
 7   private boolean adult;
 8 
 9   private int age;
10   //getter, setter ellipsis
11 
12 
13   public Person(String name, int age) {
14     this.name = name;
15     this.age = age;
16   }

We define two rules:

  • Rule 1: you can update the Person instance, judge whether the age is greater than 18, and set the adult flag.
  • Rule 2: judge whether the person is an adult and refuse children (i.e. non adults) to buy alcohol.

Obviously, the Priority of rule 1 is greater than that of rule 2. We can set the Priority of rule 1 to 1 and the Priority of rule 2 to 2, so as to ensure that the rule engine executes the rules in the order of Priority.

 Rule ageRule = new MVELRule()
        .name("age rule")
        .description("Check if person"s age is > 18 and marks the person as adult")
        .priority(1)
        .when("person.age > 18")
        .then("person.setAdult(true);");
1 The definition of rule 2, we put alcohol-rule.yml In the file
2 
3 name: "alcohol rule" 
4 description: "children are not allowed to buy alcohol" 
5 priority: 2 
6 condition: "person.isAdult() == false" 
7 actions: 
8  - "System.out.println("Shop: Sorry, you are not allowed to buy alcohol");"
 1 public class ShopLauncher {
 2   public static void main(String[] args) throws Exception {
 3     //Create a Person example(Fact)
 4     Person tom = new Person("Tom", 19);
 5     Facts facts = new Facts();
 6     facts.put("person", tom);
 7 
 8     //Create rule 1
 9     Rule ageRule = new MVELRule()
10         .name("age rule")
11         .description("Check if person"s age is > 18 and marks the person as adult")
12         .priority(1)
13         .when("person.age > 18")
14         .then("person.setAdult(true);");
15     //Create rule 2
16     Rule alcoholRule = new MVELRuleFactory(new YamlRuleDefinitionReader()).
17         createRule(new FileReader(ResourceUtils.getFile("classpath:alcohol-rule.yml")));
18 
19     Rules rules = new Rules();
20     rules.register(ageRule);
21     rules.register(alcoholRule);
22 
23     //Create a rule execution engine and execute rules
24     RulesEngine rulesEngine = new DefaultRulesEngine();
25     System.out.println("Tom: Hi! can I have some Vodka please?");
26     rulesEngine.fire(rules, facts);
27     System.out.println(JSON.toJSONString(tom));
28   }
29 }

The results are as follows:

 

 

 

Source code analysis

 https://www.cnblogs.com/lay2017/p/12591966.html

To learn more about the principle, you can view the github source code:

https://github.com/j-easy/easy-rules

https://gitcode.net/mirrors/j-easy/easy-rules

 

Turn:

 https://segmentfault.com/a/1190000022939252

 

 

Added by jwk811 on Tue, 04 Jan 2022 11:26:11 +0200