前言

本文重点讲解Drools与Spring进行整合的过程。

添加Maven依赖

在pom.xml中添加如下依赖,进行Drools的集成。

<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>

根据版本不同,某些版本可能还需要引入其他的依赖,比如较高版本中mvel被拆分成独立的类库时,可能需要单独引入。

对于上面的最新版本,可以在maven仓库中获取。

初始化数据

先来定义一下业务数据和场景,比如根据行车距离和是否是夜间行车来计算费用。

Fact对象定义如下:

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
}

定义计算费用的drl规则:

global com.baeldung.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数据来进行打车费用的计算。上述实例中先检查是否为夜间行车,距离是否小于10英里,只有在满足条件时才会进行RideFare的设置和计算。

与Spring的整合

现在开始进行Spring框架的整合。首先定义Spring的Bean配置类,用来初始化TaxiFareCalculatorService

@Configuration
@ComponentScan("com.baeldung.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()进行创建。

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

KieContainer需要在KieFileSystem, KieBuilderKieModule的协助下进行创建。

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

KieModule kieModule = kieBuilder.getKieModule();

KieBase 是一个存储库,其中包含与应用程序相关的所有知识,例如规则、流程、功能、类型模型,并且它隐藏在 KieModule 中。 KieBase 可以从 KieContainer 中获得。

创建 KieModule 后,我们可以继续创建 KieContainer——其中包含 KieModule,其中 KieBase 已被定义。 KieContainer 是使用模块创建的:

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

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 与引擎交互以根据插入的事实处理规则中定义的实际业务逻辑。

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

规则需要对数据进行操作。可以使用 kieSession.insert(taxiRide) 将事实插入到会话中。

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

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

事例

下面基于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);
}

小结

在本文中,我们通过一个简单的用例了解了 Drools Spring 集成。



Drools与Spring的整合插图

关注公众号:程序新视界,一个让你软实力、硬技术同步提升的平台

除非注明,否则均为程序新视界原创文章,转载必须以链接形式标明本文链接

本文链接:http://www.choupangxia.com/2021/06/06/drools-spring-integration/