在本教程中,我们将了解 Drools Rule Engine 与 Spring Boot 的集成,展示如何使用 Decision Tables 和 Rules 来压缩业务逻辑。
决策表是一种表示条件逻辑的紧凑方式,它们可以在 Drools 中用于定义业务规则。在 Drools 中,决策表是一种从输入电子表格的数据生成规则的方法。电子表格可以是标准 Excel (XLS) 或 CSV 文件。
在决策表中,每一行都是一个规则,该行中的每一列都是该规则的条件或操作。理想情况下,规则是在不考虑行顺序的情况下编写的;这使得维护更容易,因为不需要一直移动行。当规则引擎处理事实时,任何匹配的规则都会触发。
让我们创建一个 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
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
让我们看另一个使用 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
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
内容来源于网络,如有侵权,请联系作者删除!