Часто в вашей работе вы можете столкнуться с проблемами, связанными с бизнес-логикой. Предположим, что у вас есть десятки правил (на данный момент в нашем проекте их более 50, и я привык работать над проектом, в котором было сотни таких правил), которые вы должны реализовать, разделить на несколько классов, подклассов. , абстракции и конечно же юнит тест. Это может быть сложным и трудоемким как для написания, так и для поддержки. Есть много способов решения этой проблемы, и я покажу вам один из них — JBoss Drools.
Drools — это библиотека, специально созданная для таких целей, как реализация правил. Как представлено в Википедии:
«Drools — это реализация механизма правил, основанная на алгоритме Чарльза Форги Rete, специально разработанная для языка Java».
Он содержит механизм правил, который может обрабатывать правила, написанные на языке Drools (вы также можете предоставить правила в электронных таблицах Excel! — идеально подходит для поддержки и управления со стороны бизнеса).
В следующем примере мы рассмотрим способ интеграции JBoss Drools с Spring и пример решения аналогичной проблемы без Drools.
Давайте предположим, что у нас есть POJO — продукт, который может представлять медицинский или электронный продукт.
Product.java
package pl.grzejszczak.marcin.drools.springintegration.model; import pl.grzejszczak.marcin.drools.springintegration.enums.TypeEnum; /** * Created with IntelliJ IDEA. * User: mgrzejszczak * Date: 14.01.13 */ public class Product { private final TypeEnum typeEnum; private String productName; public Product(TypeEnum typeEnum) { this.typeEnum = typeEnum; productName = typeEnum.getSomeOutputString(); } public TypeEnum getTypeEnum() { return typeEnum; } public String getProductName() { return productName; } public void setProductName(String productName) { this.productName = productName; } }
Тип продукта определяется TypeEnum. Он также имеет outputString — давайте предположим, что он определяет марку продукта (или что вы хотите;))
TypeEnum.java
package pl.grzejszczak.marcin.drools.springintegration.enums; /** * Created with IntelliJ IDEA. * User: mgrzejszczak * Date: 14.01.13 */ public enum TypeEnum { MEDICAL("medical", "aaabbbccc"), ELECTRONIC("electronic", "cccbbbaaa"); private final String type; private final String someOutputString; private TypeEnum(String type, String someOutputString) { this.type = type; this.someOutputString = someOutputString; } public String getType() { return type; } public String getSomeOutputString() { return someOutputString; } }
Допустим, что логика наших рулов такова, что в зависимости от типа перечисления мы хотим выполнить некоторую обработку (в нашем случае мы будем иметь один и тот же тип обработки — преобразование каждого ‘a’ в ‘b’ в выводе строка).
NoRulesProductServiceImpl.java
package pl.grzejszczak.marcin.drools.springintegration.service.nondrools; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import pl.grzejszczak.marcin.drools.springintegration.enums.TypeEnum; import pl.grzejszczak.marcin.drools.springintegration.model.Product; import pl.grzejszczak.marcin.drools.springintegration.service.Processor; import pl.grzejszczak.marcin.drools.springintegration.service.ProductService; import java.util.List; import static com.google.common.collect.Lists.newArrayList; /** * Created with IntelliJ IDEA. * User: mgrzejszczak * Date: 14.01.13 */ @Component("NoRulesProductServiceImpl") public class NoRulesProductServiceImpl implements ProductService { private static final Logger LOGGER = LoggerFactory.getLogger(NoRulesProductServiceImpl.class); @Autowired @Qualifier("ProductProcessingService") private Processor<List<Product>> productProcessingService; @Override public void runProductLogic() { LOGGER.debug("Running product logic without Drools"); Product medicalProduct = new Product(TypeEnum.MEDICAL); Product electronicProduct = new Product(TypeEnum.ELECTRONIC); LOGGER.debug("Running rules for products..."); productProcessingService.process(newArrayList(medicalProduct, electronicProduct)); LOGGER.debug("...finished running products."); } }
Служба ProductProcessingService просматривает данные продукты, находит для них производителя и обрабатывает их.
ProductProcessingService.java
package pl.grzejszczak.marcin.drools.springintegration.service.nondrools; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import pl.grzejszczak.marcin.drools.springintegration.factory.ProcessingFactory; import pl.grzejszczak.marcin.drools.springintegration.model.Product; import pl.grzejszczak.marcin.drools.springintegration.service.Processor; import java.util.List; /** * Created with IntelliJ IDEA. * User: mgrzejszczak * Date: 14.01.13 */ @Component("ProductProcessingService") public class ProductProcessingService implements Processor<List<Product>> { @Autowired @Qualifier("NoRulesProcessingFactory") private ProcessingFactory<Processor, Product> processingFactory; @Override public void process(List<Product> input) { for(Product product : input){ Processor<Product> processor = processingFactory.createProcessingObject(product); processor.process(product); } } }
ProcessingFactory — это интерфейс, который на основе заданного ввода (Product) создает выход (Processor), который впоследствии выполняет дальнейшую обработку. В нашем случае у нас есть фабрика, которая вместо использования множества ifs (представьте, что у нас более двух типов продуктов) использует карту, которая соответствует типу продукта с реализацией процессора. Как видите, мы меняем последовательность ifs в один get.
NoRulesProcessingFactory.java
package pl.grzejszczak.marcin.drools.springintegration.factory.nondrools; import com.google.common.collect.ImmutableMap; import org.springframework.stereotype.Component; import pl.grzejszczak.marcin.drools.springintegration.enums.TypeEnum; import pl.grzejszczak.marcin.drools.springintegration.factory.ProcessingFactory; import pl.grzejszczak.marcin.drools.springintegration.model.Product; import pl.grzejszczak.marcin.drools.springintegration.service.nondrools.ElectronicProductProcessingService; import pl.grzejszczak.marcin.drools.springintegration.service.nondrools.MedicalProductProcessingService; import pl.grzejszczak.marcin.drools.springintegration.service.Processor; import java.util.Map; /** * Created with IntelliJ IDEA. * User: mgrzejszczak * Date: 14.01.13 */ @Component("NoRulesProcessingFactory") public class NoRulesProcessingFactory implements ProcessingFactory<Processor, Product> { private static final Map<TypeEnum, Processor> PROCESSOR_MAP = new ImmutableMap.Builder<TypeEnum, Processor>(). put(TypeEnum.MEDICAL, new MedicalProductProcessingService()). put(TypeEnum.ELECTRONIC, new ElectronicProductProcessingService()). build(); /** * By using the map we don't have any ifs * @param inputObject * @return */ @Override public Processor createProcessingObject(Product inputObject) { return PROCESSOR_MAP.get(inputObject.getTypeEnum()); } }
Я представлю здесь только один ProcessingService, поскольку другой точно такой же (я просто хотел показать концепцию).
ElectronicProductProcessingService.java
package pl.grzejszczak.marcin.drools.springintegration.service.nondrools; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import pl.grzejszczak.marcin.drools.springintegration.enums.TypeEnum; import pl.grzejszczak.marcin.drools.springintegration.model.Product; import pl.grzejszczak.marcin.drools.springintegration.service.Processor; import pl.grzejszczak.marcin.drools.springintegration.utils.SomeUtil; import static com.google.common.base.Preconditions.checkArgument; import static java.lang.String.format; /** * Created with IntelliJ IDEA. * User: mgrzejszczak * Date: 14.01.13 */ public class ElectronicProductProcessingService implements Processor<Product> { private static final Logger LOGGER = LoggerFactory.getLogger(ElectronicProductProcessingService.class); @Override public void process(Product input) { checkArgument(TypeEnum.ELECTRONIC.equals(input.getTypeEnum()), "This processing service works only for electronic devices"); checkArgument(!SomeUtil.replaceAWithB(input.getProductName()).equals(input.getProductName()), "The input has already been processed"); LOGGER.debug("Running processing for Electronic Product"); input.setProductName(SomeUtil.replaceAWithB(input.getProductName())); LOGGER.debug(format("ELECTRONIC rule applied without Drools, product name is now equal to [%s]", input.getProductName())); } }
Как видите, здесь есть несколько вещей, которые необходимо протестировать и поддержать. Представьте, что произошло бы, если бы у нас было 100 типов с более сложными правилами, чем просто замена одной буквы другой. Так как мы можем сделать это с Drools? Давайте начнем с рассмотрения pom.xml.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>pl.grzejszczak.marcin</groupId> <artifactId>drools-spring-integration</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.6</maven.compiler.source> <maven.compiler.target>1.6</maven.compiler.target> <spring.version>3.1.1.RELEASE</spring.version> </properties> <repositories> <repository> <id>spring-release</id> <url>http://maven.springframework.org/release</url> </repository> </repositories> <dependencies> <!-- Spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>13.0.1</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-spring</artifactId> <version>5.4.0.Final</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.6.6</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> <scope>test</scope> </dependency> </dependencies> </project>
Давайте посмотрим на applicationContext.xml и drools-context.xml. Что касается первого, то, что мы делаем на самом деле, это просто показывает, где искать классы с точки зрения Spring и откуда импортировать контекст drools.
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <import resource="classpath:drools-context.xml"/> <!-- Show Spring where to search for the beans (in which packages) --> <context:component-scan base-package="pl.grzejszczak.marcin.drools.springintegration" /> </beans>
Контекст для слюней. Посмотрите на псевдонимы для продуктовKSession. Предоставляя псевдоним, мы объединяем два потенциальных сеанса знаний в один. Один сеанс знаний определяется для одной базы знаний. Для базы знаний мы предоставляем список (в нашем случае только один ресурс) drl-файлов (мы могли бы предоставить таблицу Excel).
Drools-context.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:drools="http://drools.org/schema/drools-spring" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://drools.org/schema/drools-spring http://drools.org/schema/drools-spring.xsd"> <!-- KNOWLEDGE BASE FOR A GIVEN TYPE --> <drools:kbase id="productsKBase"> <drools:resources> <drools:resource type="DRL" source="classpath:rules/products.drl"/> </drools:resources> </drools:kbase> <drools:ksession id="productsKSession" name="productsKSession" type="stateless" kbase="productsKBase"/> <alias name="productsKSession" alias="electronicKSession"/> <alias name="productsKSession" alias="medicalKSession"/> </beans>
Давайте проверим файл drl.
Мы определяем два правила — «МЕДИЦИНСКОЕ правило» и «ЭЛЕКТРОННОЕ правило». Для каждого случая мы проверяем:
- имеет ли входной объект тип продукта
- имеет ли typeEnum медицинский или электронный
- не было ли у него изменено productName
Затем мы обращаемся к продукту с помощью переменной $ product. Мы модифицируем продукт, используя
ключевое слово modify (что означает, что все правила перепроверены — попробуйте удалить условие ‘productName! = ReplaceAWithB ($ product.typeEnum.someOutputString’ и у вас будет бесконечный цикл), установив новое productName. Посмотрите на все операции импорта и импорта функций. Вы можете выполнить статическую функцию (pl.grzejszczak.marcin.drools.springintegration.utils.SomeUtil.replaceAWithB или org.drools.core.util.StringUtils.isEmpty), импортировав ее. в файле drl.
В конце мы записываем,
что правило было применено.
products.drl
package pl.grzejszczak.marcin import org.slf4j.LoggerFactory import pl.grzejszczak.marcin.drools.springintegration.DroolsSpring import pl.grzejszczak.marcin.drools.springintegration.model.Product import pl.grzejszczak.marcin.drools.springintegration.enums.TypeEnum import function pl.grzejszczak.marcin.drools.springintegration.utils.SomeUtil.replaceAWithB import function org.drools.core.util.StringUtils.isEmpty rule "MEDICAL rule" dialect "mvel" when $product : Product( typeEnum == TypeEnum.MEDICAL, productName != replaceAWithB($product.typeEnum.someOutputString) ) then modify ($product) {productName = replaceAWithB($product.typeEnum.someOutputString)} LoggerFactory.getLogger(DroolsSpring.class).debug(String.format("MEDICAL rule applied, product name is now equal to [%s]", $product.productName)) end rule "ELECTRONIC rule" dialect "mvel" when $product : Product( typeEnum == TypeEnum.ELECTRONIC, productName != replaceAWithB($product.typeEnum.someOutputString) ) then modify ($product) {productName = replaceAWithB($product.typeEnum.someOutputString)} LoggerFactory.getLogger(DroolsSpring.class).debug(String.format("ELECTRONIC rule applied, product name is now equal to [%s]", $product.productName)) end
Мы используем фабрику, которая выбирает правильную StatelessKnowledgeSession — так как мы хотим только изменить объект ввода. Чтобы запустить правила Drools, мы запускаем метод execute со списком входных объектов.
ProductServiceImpl.java
package pl.grzejszczak.marcin.drools.springintegration.service.drools; import org.drools.runtime.StatelessKnowledgeSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import pl.grzejszczak.marcin.drools.springintegration.enums.TypeEnum; import pl.grzejszczak.marcin.drools.springintegration.factory.ProcessingFactory; import pl.grzejszczak.marcin.drools.springintegration.model.Product; import pl.grzejszczak.marcin.drools.springintegration.service.ProductService; import static com.google.common.collect.Lists.newArrayList; /** * Created with IntelliJ IDEA. * User: mgrzejszczak * Date: 14.01.13 */ @Component("ProductServiceImpl") public class ProductServiceImpl implements ProductService { private static final Logger LOGGER = LoggerFactory.getLogger(ProductServiceImpl.class); @Autowired @Qualifier("ProductProcessingFactory") ProcessingFactory<StatelessKnowledgeSession, Product> processingFactory; @Override public void runProductLogic() { LOGGER.debug("Running product logic"); Product medicalProduct = new Product(TypeEnum.MEDICAL); Product electronicProduct = new Product(TypeEnum.ELECTRONIC); StatelessKnowledgeSession statelessKnowledgeSession = processingFactory.createProcessingObject(medicalProduct); LOGGER.debug("Running rules for products..."); statelessKnowledgeSession.execute(newArrayList(medicalProduct, electronicProduct)); LOGGER.debug("...finished running products."); } }
Теперь давайте посмотрим, как реализована фабрика. Мы используем псевдонимы в applicationContext.xml
ProductProcessingFactory.java
package pl.grzejszczak.marcin.drools.springintegration.factory.drools; import org.drools.runtime.StatelessKnowledgeSession; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; import pl.grzejszczak.marcin.drools.springintegration.factory.ProcessingFactory; import pl.grzejszczak.marcin.drools.springintegration.model.Product; /** * Created with IntelliJ IDEA. * User: mgrzejszczak * Date: 14.01.13 */ @Component("ProductProcessingFactory") public class ProductProcessingFactory implements ProcessingFactory<StatelessKnowledgeSession, Product> { @Autowired private ApplicationContext applicationContext; @Override public StatelessKnowledgeSession createProcessingObject(Product inputObject) { return (StatelessKnowledgeSession)applicationContext.getBean(inputObject.getTypeEnum().getType() + "KSession"); } }
Теперь, как мы можем проверить, работает ли это? У меня есть два модульных теста, которые доказывают это (они не работают в полной изоляции, но они функциональны обоих подходов). Начиная с теста для ручного создания правил теста.
NoRulesProductServiceImplTest.java
package pl.grzejszczak.marcin.drools.springintegration.service; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import pl.grzejszczak.marcin.drools.springintegration.enums.TypeEnum; import pl.grzejszczak.marcin.drools.springintegration.model.Product; import pl.grzejszczak.marcin.drools.springintegration.utils.SomeUtil; import java.util.List; import static com.google.common.collect.Lists.newArrayList; import static java.lang.String.format; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotSame; /** * Created with IntelliJ IDEA. * User: mgrzejszczak * Date: 14.01.13 */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:applicationContext.xml"}) public class NoRulesProductServiceImplTest { @Autowired @Qualifier("ProductProcessingService") private Processor<List<Product>> productProcessingService; /** * Test is not run in perfect isolation - the purpose is to show the outcome of processing without Drools * * @throws Exception */ @Test public void testRunProductLogic() throws Exception { Product medicalProduct = new Product(TypeEnum.MEDICAL); Product electronicProduct = new Product(TypeEnum.ELECTRONIC); String initialMedicalProductName = medicalProduct.getProductName(); String initialElectronicProduct = electronicProduct.getProductName(); System.out.println(format("Initial productName for Medical [%s]", medicalProduct.getProductName())); System.out.println(format("Initial productName for Electronic [%s]", electronicProduct.getProductName())); productProcessingService.process(newArrayList(medicalProduct, electronicProduct)); String finalMedicalProduct = medicalProduct.getProductName(); String finalElectronicProduct = electronicProduct.getProductName(); assertNotSame(finalMedicalProduct, initialMedicalProductName); assertNotSame(finalElectronicProduct, initialElectronicProduct); assertEquals(SomeUtil.replaceAWithB(initialMedicalProductName), finalMedicalProduct); assertEquals(SomeUtil.replaceAWithB(initialElectronicProduct), finalElectronicProduct); System.out.println(format("Final productName for Medical [%s]", medicalProduct.getProductName())); System.out.println(format("Final productName for Electronic [%s]", electronicProduct.getProductName())); } }
И юнит-тест для подхода Drools.
ProductServiceImplTest.java
package pl.grzejszczak.marcin.drools.springintegration.service; import org.drools.runtime.StatelessKnowledgeSession; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import pl.grzejszczak.marcin.drools.springintegration.enums.TypeEnum; import pl.grzejszczak.marcin.drools.springintegration.factory.ProcessingFactory; import pl.grzejszczak.marcin.drools.springintegration.model.Product; import pl.grzejszczak.marcin.drools.springintegration.utils.SomeUtil; import static com.google.common.collect.Lists.newArrayList; import static java.lang.String.format; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertTrue; /** * Created with IntelliJ IDEA. * User: mgrzejszczak * Date: 14.01.13 */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:applicationContext.xml"}) public class ProductServiceImplTest { @Autowired @Qualifier("ProductProcessingFactory") ProcessingFactory<StatelessKnowledgeSession, Product> processingFactory; /** * Test is not run in perfect isolation - the purpose is to show the outcome of processing with Drools * @throws Exception */ @Test public void testRunProductLogic() throws Exception { Product medicalProduct = new Product(TypeEnum.MEDICAL); Product electronicProduct = new Product(TypeEnum.ELECTRONIC); String initialMedicalProductName = medicalProduct.getProductName(); String initialElectronicProduct = electronicProduct.getProductName(); System.out.println(format("Initial productName for Medical [%s]", medicalProduct.getProductName())); System.out.println(format("Initial productName for Electronic [%s]", electronicProduct.getProductName())); StatelessKnowledgeSession statelessKnowledgeSessionForMedical = processingFactory.createProcessingObject(medicalProduct); StatelessKnowledgeSession statelessKnowledgeSessionForElectronic = processingFactory.createProcessingObject(electronicProduct); assertTrue(statelessKnowledgeSessionForMedical == statelessKnowledgeSessionForElectronic); System.out.println("References for stateless sessions are the same, executing rules..."); statelessKnowledgeSessionForMedical.execute(newArrayList(medicalProduct, electronicProduct)); String finalMedicalProduct = medicalProduct.getProductName(); String finalElectronicProduct = electronicProduct.getProductName(); assertNotSame(finalMedicalProduct, initialMedicalProductName); assertNotSame(finalElectronicProduct, initialElectronicProduct); assertEquals(SomeUtil.replaceAWithB(initialMedicalProductName), finalMedicalProduct); assertEquals(SomeUtil.replaceAWithB(initialElectronicProduct), finalElectronicProduct); System.out.println(format("Final productName for Medical [%s]", medicalProduct.getProductName())); System.out.println(format("Final productName for Electronic [%s]", electronicProduct.getProductName())); } }
Теперь давайте посмотрим на журналы — посмотрим, что «Выполнение некоторой логики» происходило 6 раз для Drools, поскольку при изменении объекта правила проходят повторную проверку и повторный запуск:
org.springframework.context.support.ClassPathXmlApplicationContext:495 Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@743399: startup date [Tue Jan 15 16:32:30 CET 2013]; root of context hierarchy org.springframework.beans.factory.xml.XmlBeanDefinitionReader:315 Loading XML bean definitions from class path resource [applicationContext.xml] org.springframework.beans.factory.xml.XmlBeanDefinitionReader:315 Loading XML bean definitions from class path resource [drools-context.xml] [main] org.springframework.beans.factory.support.DefaultListableBeanFactory:557 Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@3b1d04: defining beans [productsKBase,productsKSession,ProductProcessingFactory,NoRulesProcessingFactory,ProductServiceImpl,NoRulesProductServiceImpl,ProductProcessingService,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0]; root of factory hierarchy pl.grzejszczak.marcin.drools.springintegration.service.drools.ProductServiceImpl:32 Running product logic pl.grzejszczak.marcin.drools.springintegration.service.drools.ProductServiceImpl:36 Running rules for products... pl.grzejszczak.marcin.drools.springintegration.utils.SomeUtil:19 Executing some logic pl.grzejszczak.marcin.drools.springintegration.utils.SomeUtil:19 Executing some logic pl.grzejszczak.marcin.drools.springintegration.utils.SomeUtil:19 Executing some logic pl.grzejszczak.marcin.drools.springintegration.utils.SomeUtil:19 Executing some logic pl.grzejszczak.marcin.drools.springintegration.DroolsSpring:? ELECTRONIC rule applied, product name is now equal to [cccbbbbbb] pl.grzejszczak.marcin.drools.springintegration.utils.SomeUtil:19 Executing some logic pl.grzejszczak.marcin.drools.springintegration.utils.SomeUtil:19 Executing some logic pl.grzejszczak.marcin.drools.springintegration.DroolsSpring:? MEDICAL rule applied, product name is now equal to [bbbbbbccc] pl.grzejszczak.marcin.drools.springintegration.service.drools.ProductServiceImpl:38 ...finished running products. pl.grzejszczak.marcin.drools.springintegration.service.nondrools.NoRulesProductServiceImpl:33 Running product logic without Drools pl.grzejszczak.marcin.drools.springintegration.service.nondrools.NoRulesProductServiceImpl:36 Running rules for products... pl.grzejszczak.marcin.drools.springintegration.utils.SomeUtil:19 Executing some logic pl.grzejszczak.marcin.drools.springintegration.service.nondrools.MedicalProductProcessingService:26 Running processing for Medical Product pl.grzejszczak.marcin.drools.springintegration.utils.SomeUtil:19 Executing some logic pl.grzejszczak.marcin.drools.springintegration.service.nondrools.MedicalProductProcessingService:28 MEDICAL rule applied without Drools, product name is now equal to [bbbbbbccc] pl.grzejszczak.marcin.drools.springintegration.utils.SomeUtil:19 Executing some logic pl.grzejszczak.marcin.drools.springintegration.service.nondrools.ElectronicProductProcessingService:26 Running processing for Electronic Product pl.grzejszczak.marcin.drools.springintegration.utils.SomeUtil:19 Executing some logic pl.grzejszczak.marcin.drools.springintegration.service.nondrools.ElectronicProductProcessingService:28 ELECTRONIC rule applied without Drools, product name is now equal to [cccbbbbbb] pl.grzejszczak.marcin.drools.springintegration.service.nondrools.NoRulesProductServiceImpl:38 ...finished running products.
Виола! Таким образом, вы можете написать некоторые правила для Drools, которые могут сэкономить много времени и усилий применительно к бизнес-логике. Вы можете найти источники здесь в моем
хранилище BitBucket .