[Drools Demos] 其 (四) : SpringBoot-Drools模板
程序员文章站
2022-05-28 11:37:29
...
前言
前几节我们说了Drools的快速启动、数据传递和动态加载.本章我们提供一个简单的 Drools-SpringBoot实例模板.
本章主要对应项目内的drools-springboot-dynamic
内容.
基础配置: JDK 1.7 + Eclipse Mar + Maven
依赖: Drools插件(非必须)
本章主要对应项目内的drools-quickstart
子模块.
Github地址: https://github.com/SeanYanxml/drools-train
详细内容(Demos-1-模板基础)
pom.xml(导入相关Jar包)
<!-- drools jars -->
<properties>
<drools-version>6.5.0.Final</drools-version>
<springboot.version>1.5.13.RELEASE</springboot.version>
</properties>
<dependencies>
<!-- spring boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${springboot.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- spring boot log4j2 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<version>${springboot.version}</version>
</dependency>
<!--spring-boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${springboot.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- <dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>${drools-version}</version>
</dependency> -->
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>${drools-version}</version>
</dependency>
<!-- <dependency>
<groupId>org.drools</groupId>
<artifactId>knowledge-api</artifactId>
<version>${drools-version}</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-decisiontables</artifactId>
<version>${drools-version}</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-templates</artifactId>
templates 模板
<version>${drools-version}</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
<version>${drools-version}</version>
</dependency> -->
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-spring</artifactId>
<version>${drools-version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- other jars -->
<!-- test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
<scope>compile</scope>
</dependency>
<!--log4j-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
DroolsConfig.java(Drools动态加载配置类)
package com.yanxml.drools.springboot.config;
import java.io.IOException;
import org.kie.api.KieBase;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.KieModule;
import org.kie.api.builder.KieRepository;
import org.kie.api.builder.Message;
import org.kie.api.builder.ReleaseId;
import org.kie.api.builder.Results;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.internal.io.ResourceFactory;
import org.kie.spring.KModuleBeanFactoryPostProcessor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
@Configuration
public class DroolsConfig {
private static final String RULES_PATH = "rules/";
@Bean
@ConditionalOnMissingBean(KieFileSystem.class)
public KieFileSystem kieFileSystem() throws IOException {
KieFileSystem kieFileSystem = getKieServices().newKieFileSystem();
for (Resource file : getRuleFiles()) {
// ((org.kie.api.io.Resource) file).setResourceType(ResourceType.DRL);
kieFileSystem.write(ResourceFactory.newClassPathResource(
RULES_PATH + file.getFilename(), "UTF-8"));
// FileInputStream fis = new FileInputStream( "src/main/resources/"+RULES_PATH + file.getFilename() );
// kieFileSystem.write( "src/main/resources/"+RULES_PATH + file.getFilename(),
// getKieServices().getResources().newInputStreamResource( fis ) );
}
return kieFileSystem;
}
private Resource[] getRuleFiles() throws IOException {
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
return resourcePatternResolver
.getResources("classpath*:" + RULES_PATH + "**/*.*");
}
@Bean
@ConditionalOnMissingBean(KieContainer.class)
public KieContainer kieContainer() throws IOException {
KieServices kieServices = getKieServices();
final KieRepository kieRepository = kieServices.getRepository();
// 这边出了问题
kieRepository.addKieModule(new KieModule() {
public ReleaseId getReleaseId() {
return kieRepository.getDefaultReleaseId();
}
});
KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem());
Results results = kieBuilder.getResults();
if (results.hasMessages(Message.Level.ERROR)) {
System.out.println(results.getMessages());
throw new IllegalStateException("### errors ###");
}
kieBuilder.buildAll();
// return getKieServices()
// .newKieContainer(getKieServices().getRepository().getDefaultReleaseId());
KieContainer kieContainer = kieServices.newKieContainer(kieRepository.getDefaultReleaseId());
return kieContainer;
}
private KieServices getKieServices() {
return KieServices.Factory.get();
}
@Bean
@ConditionalOnMissingBean(KieBase.class)
public KieBase kieBase() throws IOException {
return kieContainer().getKieBase();
}
@Bean
@ConditionalOnMissingBean(KieSession.class)
public KieSession kieSession() throws IOException {
return kieContainer().newKieSession();
}
@Bean
@ConditionalOnMissingBean(KModuleBeanFactoryPostProcessor.class)
public KModuleBeanFactoryPostProcessor kiePostProcessor() {
return new KModuleBeanFactoryPostProcessor();
}
}
Application(SpringBoot启动类)
package com.yanxml.drools.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
*
* 主程序的入口
*
*/
@ComponentScan(basePackages={
"com.yanxml.drools.springboot"
})
@SpringBootApplication
public class Application {
public static Logger log = LogManager.getLogger(Application.class);
public static void main(String[] args) {
try {
SpringApplication app = new SpringApplication(Application.class);
app.setWebEnvironment(true);
app.run(args);
log.info("application started successfully");
} catch (Exception e) {
log.error("application main exception", e);
}
}
}
Message(POJO)
package com.yanxml.drools.springboot.beans.pojo;
public class Message {
// status 4 种状态
public static final int STATUS_1 = 1;
public static final int STATUS_2 = 2;
public static final int STATUS_3 = 3;
public static final int STATUS_4 = 4;
private String message;
private int status;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
}
HelloWorld.drl
package com.yanxml.drools.springboot
import com.yanxml.drools.springboot.beans.pojo.Message;
no-loop true
rule "TransmitHelloworldRule"
when
$m : Message( status == Message.STATUS_1, myMessage:message)
then
System.out.println("Hit Transmit HelloWorld Rule.");
$m.setMessage("STATUS_2");
$m.setStatus(Message.STATUS_2);
// update($m);
// update(m);
end
HelloworldController
package com.yanxml.drools.springboot.controller;
import javax.annotation.Resource;
import org.drools.core.base.RuleNameStartsWithAgendaFilter;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.yanxml.drools.springboot.beans.pojo.Message;
@RequestMapping("/test")
@Controller
public class HelloworldController {
@Resource
private KieContainer kieContainer;
// @Resource
// private KieSession kieSession;
@ResponseBody
@RequestMapping("/helloworld")
public void test(){
// newKieSession with name will be NullPointerException.(Bug)
// KieSession kieSession = kieContainer.newKieSession("kSessionHelloWorld");
KieSession kieSession = kieContainer.newKieSession();
Message message = new Message();
message.setMessage("STATUS_1");
message.setStatus(Message.STATUS_1);
System.out.println("Rule Before - Message: "+message.getMessage()+" status:"+message.getStatus());
// hit rule
kieSession.insert(message);
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("Transmit"));
// 同步等待 - 等待rule执行完毕后 后面的语句才被执行。
System.out.println("Rule After - Message: "+message.getMessage()+" status:"+message.getStatus());
}
}
测试结果:
[1] localhost:8080/test/helloworld
# output
Rule Before - Message: STATUS_1 status:1
Hit Transmit HelloWorld Rule.
Rule After - Message: STATUS_2 status:2
RELATING-CLASS:HelloworldController
详细内容(Demos-2-方法回调)
MessageServiceService
package com.yanxml.drools.springboot.service;
import org.springframework.stereotype.Service;
import com.yanxml.drools.springboot.beans.pojo.Message;
@Service
public class MessageServiceService {
public void insert(Message message){
// 数据库 Insert语句
System.out.println("Message Service Insert SQL.");
}
}
HelloWorld.drl 规则补充
rule "InvokeHelloWorldRule"
when
$m : Message()
$messageServiceService : MessageServiceService()
then
System.out.println("Hit Invoke HelloWorld Rule.");
$messageServiceService.insert($m);
end
MessageServiceController(新Controller)
package com.yanxml.drools.springboot.controller;
import javax.annotation.Resource;
import org.drools.core.base.RuleNameStartsWithAgendaFilter;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.yanxml.drools.springboot.beans.pojo.Message;
import com.yanxml.drools.springboot.service.MessageServiceService;
@Controller
@RequestMapping("/message")
public class MessageServiceController {
@Resource
KieContainer kieContainer;
@Autowired
MessageServiceService messageServiceService;
@ResponseBody
@RequestMapping("/insert")
public void insert(){
KieSession kieSession = kieContainer.newKieSession();
// insert Facts
Message message = new Message();
message.setMessage("Insert-0-Message");
message.setStatus(Message.STATUS_1);
kieSession.insert(message);
// insert Service
kieSession.insert(messageServiceService);
kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("Invoke"));
}
}
测试结果:
[2] http://localhost:8080/message/insert
# output
Hit Invoke HelloWorld Rule.
Message Service Insert SQL.
RELATING-CLASS:MessageServiceController
Reference
[1] 《Drools7.0.0.Final规则引擎教程》Springboot+规则重新加载
[2] Drools入门系列