Contents

Spring 集成 Drools

1. 简介

在这个快速教程中,我们将把 Drools 与 Spring 集成。如果您刚刚开始使用 Drools,请查看这篇文章

2. Maven依赖

让我们首先将以下依赖项添加到我们的pom.xml文件中:

<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-core</artifactId>
    <version>7.0.0.Final</version>
</dependency>
<dependency>
    <groupId>org.kie</groupId>
    <artifactId>kie-spring</artifactId>
    <version>7.0.0.Final</version>
</dependency>

最新版本可以在这里找到drools-core 和这里kie-spring

3. 初始数据

现在让我们定义将在我们的示例中使用的数据。我们将根据行驶距离和夜间附加费标志来计算乘车费用。

这是一个将用作事实的简单对象:

public class TaxiRide {
    private Boolean isNightSurcharge;
    private Long distanceInMile;
    
    // standard constructors, getters/setters
}

我们还定义另一个用于表示票价的业务对象:

public class Fare {
    private Long nightSurcharge;
    private Long rideFare;
    
    // standard constructors, getters/setters
}

现在,让我们定义一个计算出租车费用的业务规则:

global com.blogdemo.spring.drools.model.Fare rideFare;
dialect  "mvel"
rule "Calculate Taxi Fare - Scenario 1"
    when
        taxiRideInstance:TaxiRide(isNightSurcharge == false && distanceInMile < 10);
    then
      	rideFare.setNightSurcharge(0);
       	rideFare.setRideFare(70);
end

正如我们所见,定义了一条规则来计算给定TaxiRide的总票价。

此规则接受TaxiRide对象并检查isNightSurcharge属性是否为falsedistanceInMile属性值是否小于 10,然后将票价计算为 70 并将nightSurcharge属性设置为 0。

计算的输出设置为Fare对象以供进一步使用。

4. Spring集成

4.1. Spring Bean 配置

现在,让我们继续讨论 Spring 集成。

我们将定义一个 Spring bean 配置类——它将负责实例化TaxiFareCalculatorService bean 及其依赖项:

@Configuration
@ComponentScan("com.blogdemo.spring.drools.service")
public class TaxiFareConfiguration {
    private static final String drlFile = "TAXI_FARE_RULE.drl";
    @Bean
    public KieContainer kieContainer() {
        KieServices kieServices = KieServices.Factory.get();
        KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
        kieFileSystem.write(ResourceFactory.newClassPathResource(drlFile));
        KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem);
        kieBuilder.buildAll();
        KieModule kieModule = kieBuilder.getKieModule();
        return kieServices.newKieContainer(kieModule.getReleaseId());
    }
}

KieServices是一个单例,它作为一个单点入口来获取 Kie 提供的所有服务。使用KieServices.Factory.get *()*检索KieServices。

接下来,我们需要获取KieContainer,它是我们运行规则引擎所需的所有对象的占位符。

KieContainer是在其他 bean 的帮助下构建的,包括KieFileSystem、KieBuilderKieModule

让我们继续创建一个KieModule,它是定义称为KieBase 的规则知识所需的所有资源的容器。

KieModule kieModule = kieBuilder.getKieModule();

KieBase是一个存储库,其中包含与应用程序相关的所有知识,例如规则、流程、功能、类型模型,它隐藏在KieModule中。KieBase可以从KieContainer中获得。 创建KieModule后,我们可以继续创建KieContainer——它包含定义KieBaseKieModuleKieContainer是使用一个模块创建的:

KieContainer kContainer = kieServices.newKieContainer(kieModule.getReleaseId());

4.2. Spring 服务

让我们定义一个服务类,它通过将Fact对象传递给引擎来处理结果来执行实际的业务逻辑:

@Service
public class TaxiFareCalculatorService {
    @Autowired
    private KieContainer kieContainer;
    public Long calculateFare(TaxiRide taxiRide, Fare rideFare) {
        KieSession kieSession = kieContainer.newKieSession();
        kieSession.setGlobal("rideFare", rideFare);
        kieSession.insert(taxiRide);
        kieSession.fireAllRules();
        kieSession.dispose();
        return rideFare.getTotalFare();
    }
}

最后,使用KieContainer实例创建一个KieSession 。KieSession实例是可以插入输入数据的地方KieSession与引擎交互,根据插入的 Facts 处理规则中定义的实际业务逻辑。

全局(就像全局变量一样)用于将信息传递给引擎。我们可以使用setGlobal(“key”, value);设置全局。在本例中,我们将Fare对象设置为 Global 来存储计算的出租车费用。

正如我们在第 4 节中讨论的那样,规则需要对数据进行操作。我们使用kieSession.insert(taxiRide);Fact插入到会话中;

一旦我们完成了输入Fact 的设置,我们可以通过调用*fireAllRules()*请求引擎执行业务逻辑。

最后,我们需要通过调用*dispose()*方法清理会话以避免内存泄漏。

5. 实例

现在,我们可以连接一个 Spring 上下文并查看 Drools 是否按预期工作:

@Test
public void whenNightSurchargeFalseAndDistLessThan10_thenFixWithoutNightSurcharge() {
    TaxiRide taxiRide = new TaxiRide();
    taxiRide.setIsNightSurcharge(false);
    taxiRide.setDistanceInMile(9L);
    Fare rideFare = new Fare();
    Long totalCharge = taxiFareCalculatorService.calculateFare(taxiRide, rideFare);
 
    assertNotNull(totalCharge);
    assertEquals(Long.valueOf(70), totalCharge);
}