1. Introduction
1.介绍
In this quick tutorial, we’re going to integrate Drools with Spring. If you’re just getting started with Drools, check out this intro article.
在这个快速教程中,我们将把Drools与Spring整合起来。如果你刚刚开始使用Drools,请查看这篇介绍文章。
2. Maven Dependencies
2.Maven的依赖性
Let’s start by adding the following dependencies to our pom.xml file:
让我们先把以下依赖项添加到我们的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>
The latest versions can be found here for drools-core and here for kie-spring.
最新的版本可以在这里找到drools-core和kie-spring的版本。
3. Initial Data
3.初始数据
Let’s now define the data which will be used in our example. We’re going to calculate the fare of a ride based on the distance traveled and the night surcharge flag.
现在让我们定义将在我们的例子中使用的数据。我们将根据行驶的距离和夜间附加费标志来计算乘车费用。
Here’s a simple object which will be used as a Fact:
这里有一个简单的对象,将被用作事实:。
public class TaxiRide {
private Boolean isNightSurcharge;
private Long distanceInMile;
// standard constructors, getters/setters
}
Let’s also define another business object which will be used for representing fares:
让我们也定义另一个业务对象,它将被用来代表票价。
public class Fare {
private Long nightSurcharge;
private Long rideFare;
// standard constructors, getters/setters
}
Now, let’s define a business rule for calculating taxi fares:
现在,让我们定义一个计算出租车票价的业务规则。
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
As we can see, a rule is defined to calculate the total fare of the given TaxiRide.
正如我们所看到的,定义了一条规则来计算给定TaxiRide的总票价。
This rule accepts a TaxiRide object and checks if the isNightSurcharge attribute is false and the distanceInMile attribute value is less than 10, then calculate the fare as 70 and sets the nightSurcharge property to 0.
这个规则接受一个TaxiRide对象,并检查isNightSurcharge属性是否为false和distanceInMile属性值是否小于10,然后计算出票价为70,并将nightSurcharge属性设置为0。
The calculated output is set to Fare object for further use.
计算出的输出被设置为Fare对象,以便进一步使用。
4. Spring Integration
4.Spring集成
4.1. Spring Bean Configuration
4.1.Spring Bean配置
Now, let’s move on to the Spring integration.
现在,让我们继续讨论Spring的整合问题。
We’re going to define a Spring bean configuration class – which will be responsible for instantiating the TaxiFareCalculatorService bean and its dependencies:
我们将定义一个Spring Bean配置类–它将负责实例化TaxiFareCalculatorService Bean和它的依赖项。
@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 is a singleton which acts as a single point entry to get all services provided by Kie. KieServices is retrieved using KieServices.Factory.get().
KieServices是一个单子,它作为一个单点入口来获取所有由Kie提供的服务。KieServices使用KieServices.Factory.get().进行检索。
Next, we need to get the KieContainer which is a placeholder for all the object that we need to run the rule engine.
接下来,我们需要获得KieContainer,它是我们运行规则引擎所需的所有对象的占位符。
KieContainer is built with the help of other beans including KieFileSystem, KieBuilder, and KieModule.
KieContainer是在其他Bean的帮助下建立的,包括KieFileSystem、KieBuilder和KieModule。
Let’s proceed to create a KieModule which is a container of all the resources which are required to define rule knowledge known as KieBase.
让我们继续创建一个KieModule,它是定义规则知识所需的所有资源的容器,称为KieBase。
KieModule kieModule = kieBuilder.getKieModule();
KieBase is a repository which contains all knowledge related to the application such as rules, processes, functions, type models and it is hidden inside KieModule. The KieBase can be obtained from the KieContainer.
KieBase是一个存储库,它包含所有与应用程序相关的知识,如规则、流程、函数、类型模型,它隐藏在KieModule内。KieBase可以从KieContainer获得。
Once KieModule is created, we can proceed to create KieContainer – which contains the KieModule where the KieBase has been defined. The KieContainer is created using a module:
一旦KieModule被创建,我们就可以继续创建KieContainer–,它包含KieModule,其中KieBase已经被定义。KieContainer是用一个模块创建的。
KieContainer kContainer = kieServices.newKieContainer(kieModule.getReleaseId());
4.2. Spring Service
4.2.Spring服务
Let’s define a service class which executes the actual business logic by passing the Fact object to the engine for processing the result:
让我们定义一个服务类,通过将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();
}
}
Finally, a KieSession is created using KieContainer instance. A KieSession instance is a place where input data can be inserted. The KieSession interacts with the engine to process the actual business logic defined in rule based on inserted Facts.
最后,使用KieContainer实例创建一个KieSession。KieSession实例是一个可以插入输入数据的地方。KieSession与引擎互动,根据插入的事实来处理规则中定义的实际业务逻辑。
Global (just like a global variable) is used to pass information into the engine. We can set the Global using setGlobal(“key”, value); in this example, we have set Fare object as Global to store the calculated taxi fare.
全局(就像一个全局变量)被用来向引擎传递信息。我们可以使用setGlobal(“key”, value)来设置全局;在这个例子中,我们将Fare对象设置为全局,以存储计算的出租车费用。
As we discussed in Section 4, a Rule requires data to operate on. We’re inserting the Fact into session using kieSession.insert(taxiRide);
正如我们在第4节所讨论的,一个Rule需要数据来操作。我们使用kieSession.insert(taxiRide);将Fact插入会话。
Once we are done with setting up the input Fact, we can request engine to execute the business logic by calling fireAllRules().
一旦我们完成了对输入事实的设置,我们就可以通过调用fireAllRules()请求引擎执行业务逻辑。
Finally, we need to clean up the session to avoid memory leak by calling the dispose() method.
最后,我们需要通过调用dispose()方法来清理会话以避免内存泄漏。
5. Example in Action
5 行动中的例子
Now, we can wire up a Spring context and see in action that Drools works as expected:
现在,我们可以连接一个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);
}
6. Conclusion
6.结论
In this article, we learned about Drools Spring integration with a simple use case.
在这篇文章中,我们通过一个简单的用例了解了Drools Spring的集成。
As always, the implementation of the example and code snippets are available over on GitHub.
一如既往,该示例的实现和代码片段可在GitHub上获得。