Spring Boot Drools入门

x33g5p2x  于2022-09-28 转载在 Spring  
字(10.1k)|赞(0)|评价(0)|浏览(715)

在本教程中,我们将了解 Drools Rule Engine 与 Spring Boot 的集成,展示如何使用 Decision TablesRules 来压缩业务逻辑。

使用 Drools 决策表编写 Spring Boot 应用程序

决策表是一种表示条件逻辑的紧凑方式,它们可以在 Drools 中用于定义业务规则。在 Drools 中,决策表是一种从输入电子表格的数据生成规则的方法。电子表格可以是标准 Excel (XLS) 或 CSV 文件。

在决策表中,每一行都是一个规则,该行中的每一列都是该规则的条件或操作。理想情况下,规则是在不考虑行顺序的情况下编写的;这使得维护更容易,因为不需要一直移动行。当规则引擎处理事实时,任何匹配的规则都会触发。

创建 Spring Boot 项目规则引擎示例

让我们创建一个 Spring Boot 规则引擎示例:

$ spring init -dweb drools-demo

接下来,我们将向项目添加 drools 依赖项。这是完整的 pom.xml 文件:

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      
   <modelVersion>4.0.0</modelVersion>
      
   <artifactId>drools-demo-springboot</artifactId>
      
   <name>drools</name>
       
   <parent>
           
      <groupId>org.springframework.boot</groupId>
           
      <artifactId>spring-boot-starter-parent</artifactId>
           
      <version>2.1.1.RELEASE</version>
           
      <relativePath/>
       
      <!-- lookup parent from repository -->
         
   </parent>
      
   <properties>
           
      <drools-version>7.15.0.Final</drools-version>
           
      <apache-poi-version>3.13</apache-poi-version>
          
   </properties>
      
   <dependencies>
            
      <dependency>
                
         <groupId>org.springframework.boot</groupId>
                
         <artifactId>spring-boot-starter-web</artifactId>
              
      </dependency>
            
      <dependency>
                
         <groupId>org.springframework.boot</groupId>
                
         <artifactId>spring-boot-starter-test</artifactId>
                
         <scope>test</scope>
              
      </dependency>
             
      <dependency>
                
         <groupId>org.drools</groupId>
                
         <artifactId>drools-decisiontables</artifactId>
                
         <version>${drools-version}</version>
              
      </dependency>
             
      <dependency>
                
         <groupId>org.drools</groupId>
                
         <artifactId>drools-core</artifactId>
                
         <version>${drools-version}</version>
              
      </dependency>
           
      <dependency>
                
         <groupId>org.drools</groupId>
                
         <artifactId>drools-compiler</artifactId>
                
         <version>${drools-version}</version>
              
      </dependency>
            
      <dependency>
                
         <groupId>junit</groupId>
                
         <artifactId>junit</artifactId>
                
         <version>4.12</version>
                
         <scope>test</scope>
              
      </dependency>
         
   </dependencies>
        
   <build>
           
      <plugins>
                
         <plugin>
                     
            <groupId>org.springframework.boot</groupId>
                     
            <artifactId>spring-boot-maven-plugin</artifactId>
                   
         </plugin>
              
      </plugins>
         
   </build>
    
</project>

伟大的。我们将使用的规则基于一个简单的决策表:

在这个电子表格中包含一个简单的规则:如果客户对象的年龄参数等于“1”,则允许客户享受 15% 的折扣。如果客户的年龄更大,则允许 25% 的折扣。

为了在 Spring Boot 中使用 Drools 对象,我们将创建一个 DroolsConfiguration 类,该类将提供所需的 KieSession、KieContainer 和 KieFileSystem 对象:

package com.example.droolsdemo;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.KieModule;
import org.kie.api.builder.KieRepository;
import org.kie.api.builder.ReleaseId;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.internal.io.ResourceFactory;

public class DroolsConfiguration {
  private static final String RULES_PATH = "com/example/droolsdemo/";
  private KieServices kieServices = KieServices.Factory.get();

  private KieFileSystem getKieFileSystem() throws IOException {
    KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
    List rules = Arrays.asList("rules.xls");
    for (String rule : rules) {
      kieFileSystem.write(ResourceFactory.newClassPathResource(rule));
    }
    return kieFileSystem;
  }

  public KieContainer getKieContainer() throws IOException {
    getKieRepository();
    KieBuilder kb = kieServices.newKieBuilder(getKieFileSystem());
    kb.buildAll();
    KieModule kieModule = kb.getKieModule();
    KieContainer kContainer = kieServices.newKieContainer(kieModule.getReleaseId());
    return kContainer;
  }

  private void getKieRepository() {
    final KieRepository kieRepository = kieServices.getRepository();
    kieRepository.addKieModule(
        new KieModule() {
          public ReleaseId getReleaseId() {
            return kieRepository.getDefaultReleaseId();
          }
        });
  }

  public KieSession getKieSession() {
    getKieRepository();
    KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
    kieFileSystem.write(ResourceFactory.newClassPathResource(RULES_PATH + "rules.xls"));
    KieBuilder kb = kieServices.newKieBuilder(kieFileSystem);
    kb.buildAll();
    KieModule kieModule = kb.getKieModule();
    KieContainer kContainer = kieServices.newKieContainer(kieModule.getReleaseId());
    return kContainer.newKieSession();
  }
}

要将我们的 Facts 插入 Kie Session,我们将创建一个使用 DroolsConfiguration 的 Service 类:

package com.example.droolsdemo;

import org.kie.api.runtime.KieSession;
import org.springframework.stereotype.Service;
import com.mastertheboss.drools.config.DroolsConfiguration;
import com.mastertheboss.model.Customer;

@Service
public class CustomerService {
  private KieSession kieSession = new DroolsConfiguration().getKieSession();

  public Customer insertCustomer(Customer customer) {
    kieSession.insert(customer);
    kieSession.fireAllRules();
    return customer;
  }
}

Customer 对象只是一个 POJO:

package com.example.droolsdemo;

public class Customer {
  private int age;
  private int discount;
  private String name;

  public Customer(String name) {
    super();
    this.name = name;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public int getAge() {
    return age;
  }

  public void setAge(int age) {
    this.age = age;
  }

  public int getDiscount() {
    return discount;
  }

  public void setDiscount(int discount) {
    this.discount = discount;
  }
}

就这样。现在我们可以在主应用程序中自动装配 CustomerService 类并使用它来插入一些 Customer 对象:

package com.example.droolsdemo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.mastertheboss.drools.service.CustomerService;
import com.mastertheboss.model.Customer;

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
  @Autowired CustomerService service;

  public void run(String... args) {
    Customer customer1 = new Customer("Frank");
    customer1.setAge(4);
    Customer customer2 = new Customer("John");
    customer2.setAge(1);
    service.insertCustomer(customer1);
    service.insertCustomer(customer2);
    System.out.println("Allowed discount John: " + customer1.getDiscount());
    System.out.println("Allowed discount Frank: " + customer2.getDiscount());
  }

  public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
  }
}

如果您运行 Spring Boot 应用程序,预期的输出是:

Allowed discount John: 25 Allowed discount Frank: 15

为你的 Drool 规则添加一个测试类

Spring Boot 规则引擎示例也可以使用简单的 @SpringBootTest 类进行测试:

package com.example.droolsdemo;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.assertEquals;

@SpringBootTest
public class DemoApplicationTest {
  @Autowired CustomerService service;

  @Test
  public void testDiscount() {
    Customer customer1 = new Customer("Frank");
    customer1.setAge(4);
    Customer customer2 = new Customer("John");
    customer2.setAge(1);
    service.insertCustomer(customer1);
    service.insertCustomer(customer2);
    assertEquals(25, customer1.getDiscount());
    assertEquals(15, customer2.getDiscount());
  }
}

您显然可以使用以下命令运行它:

mvn clean test

这是我们的 Spring Boot 规则引擎示例的完整视图,其中包括主类、配置类、服务和测试类:

src
├── main
│   ├── java
│   │   └── com
│   │       └── example
│   │           └── droolsdemo
│   │               ├── Customer.java
│   │               ├── CustomerService.java
│   │               ├── DemoApplication.java
│   │               └── DroolsConfiguration.java
│   └── resources
│       ├── application.properties
│       ├── com
│       │   └── example
│       │       └── droolsdemo
│       │           └── rules.xls
│       ├── static
│       └── templates
└── test
    └── java
        └── com
            └── example
                └── droolsdemo
                    └── DemoApplicationTest.java

您可以运行示例应用程序:

$ mvn spring-boot:run
INFO 17999 --- [           main] c.e.droolsdemo.DemoApplicationTest       : Started DemoApplicationTest in 2.684 seconds (JVM running for 3.584) 
Allowed discount John: 25 Allowed discount Frank: 15

源代码:https://github.com/fmarchioni/masterspringboot/tree/master/drools/drools-demo

使用 Drool 规则创建 Spring Boot 项目

让我们看另一个使用 Drools Rule 文件并从类路径中注入标准 KieContainer 的示例:

package com.example.droolsdemo;

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
  @Autowired CustomerService service;

  @Bean
  public KieContainer kieContainer() {
    return KieServices.Factory.get().getKieClasspathContainer();
  }

  public void run(String... args) {
    Server s1 = new Server("rhel7", 2, 1024, 2048);
    service.addServerFacts(s1);
    Server s2 = new Server("rhel8", 2, 2048, 4096);
    service.addServerFacts(s2);
    System.out.println("Server is valid: " + s1.isValid());
    System.out.println("Server is valid: " + s2.isValid());
  }

  public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
  }
}

服务器类绑定到以下规则:

package rules 
import com.example.droolsdemo.Server 

rule "Check Server Configuration" 

   when $server : Server( processors < 2 || memory<=1024 || diskspace <= 2048) 
      then $server.setValid(false); 
      System.out.println("Server "+ $server.getName() + " configuration does not meet requirements!"); 
end

最后,将事实注入 KieSession 的 CustomerService 类与我们的第一个示例基本没有变化:

package com.example.droolsdemo;

import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class CustomerService {
  private final KieContainer kieContainer;

  @Autowired
  public CustomerService(KieContainer kieContainer) {
    this.kieContainer = kieContainer;
  }

  public Server addServerFacts(Server product) {
    KieSession kieSession = kieContainer.newKieSession("rulesSession");
    kieSession.insert(product);
    kieSession.fireAllRules();
    kieSession.dispose();
    return product;
  }
}

如果您运行应用程序类,您将看到规则将为注入的事实触发:

Server rhel7 configuration does not meet requirements! Server is valid: false Server is valid: true

第二个示例的源代码可在此处获得:https://github.com/fmarchioni/masterspringboot/tree/master/drools/drools-demo2

相关文章