Перейти к основному содержимому

Интеграция Drools Spring

· 4 мин. чтения

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 .