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.foreach.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
ложным
и значение
атрибута DistanceInMile меньше 10, затем вычисляет стоимость проезда как 70 и устанавливает для свойства nightSurcharge
значение 0.
Рассчитанный выход устанавливается в объект Fare для дальнейшего использования.
4. Весенняя интеграция
4.1. Конфигурация Spring Bean
Теперь давайте перейдем к интеграции Spring.
Мы собираемся определить класс конфигурации компонента Spring, который будет отвечать за создание экземпляра компонента TaxiFareCalculatorService
и его зависимостей:
@Configuration
@ComponentScan("com.foreach.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
извлекается с помощью KieServices.Factory.get().
Затем нам нужно получить KieContainer
, который является заполнителем для всех объектов, необходимых для запуска механизма правил.
KieContainer создается
с помощью других компонентов, включая KieFileSystem, KieBuilder
и KieModule.
Давайте приступим к созданию KieModule
, который является контейнером всех ресурсов, необходимых для определения знаний о правилах, известных как KieBase.
KieModule kieModule = kieBuilder.getKieModule();
KieBase
— это репозиторий, который содержит все знания, связанные с приложением, такие как правила, процессы, функции, модели типов, и он скрыт внутриKieModule
. KieBase можно получить изKieContainer
.
После создания KieModule
мы можем приступить к созданию KieContainer
, который содержит KieModule
, в котором была определена KieBase .
KieContainer создается
с помощью модуля:
KieContainer kContainer = kieServices.newKieContainer(kieModule.getReleaseId());
4.2. Весенняя служба
Давайте определим сервисный класс, который выполняет реальную бизнес-логику, передавая объект 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();
}
}
Наконец, KieSession
создается с использованием экземпляра KieContainer
. Экземпляр KieSession
— это место, куда можно вставлять входные данные. KieSession взаимодействует с механизмом
для обработки фактической бизнес-логики, определенной в правиле на основе вставленных фактов.
Global (как и глобальная переменная) используется для передачи информации в движок. Мы можем установить Global, используя setGlobal("key", value);
в этом примере мы установили объект Fare
как глобальный для хранения рассчитанной стоимости проезда на такси.
Как мы обсуждали в разделе 4, правило требует
данных для работы с . Мы вставляем факт
в сеанс, используя kieSession
.insert(taxiRide);
Как только мы закончим настройку входного факта,
мы можем запросить движок для выполнения бизнес-логики, вызвав 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);
}
6. Заключение
В этой статье мы узнали об интеграции Drools Spring с простым вариантом использования.
Как всегда, реализация примера и фрагменты кода доступны на GitHub .