1.简述
业务需求总是千变万化,如何把业务需求中的业务规则给抽取出来;如何让技术和决策分开来,规则引擎的动态加载为我们提供了一个方案;drools从6.0版本开始提供动态加载规则,6.4.0.Final版本改变了很多API;
本期的方案将把drools的规则放置到数据库中,并动态生成规则:demo中第一次不命中规则,中间动态增加一个规则文件,第二次再次匹配则命中;
2.代码
核心工具类 :DroolsUtils.java
package com.caicongyang.drools.utils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.drools.compiler.kie.builder.impl.InternalKieModule;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.ReleaseId;
import org.kie.api.builder.model.KieBaseModel;
import org.kie.api.builder.model.KieModuleModel;
import org.kie.api.builder.model.KieSessionModel;
import org.kie.api.conf.EqualityBehaviorOption;
import org.kie.api.conf.EventProcessingOption;
import org.kie.internal.io.ResourceFactory;
/**
* 动态生成kjar工具类
* @author caicongyang1
* @version id: DroolsUtils, v 0.1 16/10/26 下午1:58 caicongyang1 Exp $$
*/
public class DroolsUtils {
/**
* 默认规则文件所在路径
*/
private static final String RULES_PATH = "rules";
/**
* 获取规定目录下的规则文件
*
* @return
* @throws IOException
*/
private static List<File> getRuleFiles() throws IOException {
List<File> list = new ArrayList<File>();
String filePath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
File rootDir = new File(filePath);
File[] files = rootDir.listFiles();
for (File itemFile : files) {
if (itemFile.isDirectory() && itemFile.getName().equals(RULES_PATH)) {
for (File f : itemFile.listFiles()) {
if (f.getName().endsWith(".drl")) {
list.add(f);
}
}
}
}
return list;
}
/**
* 初始化一个kjar:把原有的drl包含进新建的kjar中
*
* @param ks
* @param releaseId
* @return
* @throws IOException
*/
public static InternalKieModule initKieJar(KieServices ks, ReleaseId releaseId) throws IOException {
KieFileSystem kfs = createKieFileSystemWithKProject(ks, true);
kfs.writePomXML(getPom(releaseId));
for (File file : getRuleFiles()) {
kfs.write("src/main/resources/" + file.getName(),
ResourceFactory.newClassPathResource(RULES_PATH + File.separator + file.getName(), "UTF-8"));
}
KieBuilder kieBuilder = ks.newKieBuilder(kfs);
if (!kieBuilder.buildAll().getResults().getMessages().isEmpty()) {
throw new IllegalStateException("Error creating KieBuilder.");
}
return (InternalKieModule) kieBuilder.getKieModule();
}
public static InternalKieModule createKieJar(KieServices ks, ReleaseId releaseId, ResourceWrapper resourceWrapper) {
KieFileSystem kfs = createKieFileSystemWithKProject(ks, true);
kfs.writePomXML(getPom(releaseId));
kfs.write("src/main/resources/" + resourceWrapper.getTargetResourceName(), resourceWrapper.getResource());
KieBuilder kieBuilder = ks.newKieBuilder(kfs);
if (!kieBuilder.getResults().getMessages().isEmpty()) {
System.out.println(kieBuilder.getResults().getMessages());
throw new IllegalStateException("Error creating KieBuilder.");
}
return (InternalKieModule) kieBuilder.getKieModule();
}
/**
* 创建默认的kbase和stateful的kiesession
*
* @param ks
* @param isdefault
* @return
*/
public static KieFileSystem createKieFileSystemWithKProject(KieServices ks, boolean isdefault) {
KieModuleModel kproj = ks.newKieModuleModel();
KieBaseModel kieBaseModel1 = kproj.newKieBaseModel("KBase").setDefault(isdefault)
.setEqualsBehavior(EqualityBehaviorOption.EQUALITY).setEventProcessingMode(EventProcessingOption.STREAM);
// Configure the KieSession.
kieBaseModel1.newKieSessionModel("KSession").setDefault(isdefault)
.setType(KieSessionModel.KieSessionType.STATEFUL);
KieFileSystem kfs = ks.newKieFileSystem();
kfs.writeKModuleXML(kproj.toXML());
return kfs;
}
/**
* 创建kjar的pom
*
* @param releaseId
* @param dependencies
* @return
*/
public static String getPom(ReleaseId releaseId, ReleaseId... dependencies) {
String pom = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+ " xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n"
+ " <modelVersion>4.0.0</modelVersion>\n" + "\n" + " <groupId>" + releaseId.getGroupId()
+ "</groupId>\n" + " <artifactId>" + releaseId.getArtifactId() + "</artifactId>\n" + " <version>"
+ releaseId.getVersion() + "</version>\n" + "\n";
if (dependencies != null && dependencies.length > 0) {
pom += "<dependencies>\n";
for (ReleaseId dep : dependencies) {
pom += "<dependency>\n";
pom += " <groupId>" + dep.getGroupId() + "</groupId>\n";
pom += " <artifactId>" + dep.getArtifactId() + "</artifactId>\n";
pom += " <version>" + dep.getVersion() + "</version>\n";
pom += "</dependency>\n";
}
pom += "</dependencies>\n";
}
pom += "</project>";
return pom;
}
}
资源包装类:ResourceWrapper.java
package com.caicongyang.drools.utils;
import org.kie.api.io.Resource;
/**
* 资源包装类
* @author caicongyang1
* @version id: ResourceWrapper, v 0.1 16/10/26 下午2:15 caicongyang1 Exp $$
*/
public class ResourceWrapper {
private Resource resource;
private String targetResourceName;
public ResourceWrapper(Resource resource, String targetResourceName) {
this.resource = resource;
this.targetResourceName = targetResourceName;
}
public Resource getResource() {
return resource;
}
public String getTargetResourceName() {
return targetResourceName;
}
public void setResource(Resource resource) {
this.resource = resource;
}
public void setTargetResourceName(String targetResourceName) {
this.targetResourceName = targetResourceName;
}
}
fact类:Message.java
package com.caicongyang.drools.fact;
import java.io.Serializable;
/**
* bean
* @author caicongyang1
* @version id: Message, v 0.1 16/10/26 下午2:49 caicongyang1 Exp $$
*/
public class Message implements Serializable {
private static final long serialVersionUID = 1L;
private String status;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
主测试类:dynamicDrlTest.java
package com.caicongyang.drools.test;
import org.drools.compiler.kie.builder.impl.InternalKieModule;
import org.kie.api.KieServices;
import org.kie.api.builder.KieRepository;
import org.kie.api.builder.ReleaseId;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.internal.io.ResourceFactory;
import com.caicongyang.drools.fact.Message;
import com.caicongyang.drools.utils.DroolsUtils;
import com.caicongyang.drools.utils.ResourceWrapper;
/**
*
* drools6.4动态加载规则文件:第一次不命中,动态增加规则以后,命中
*
* @author caicongyang1
* @version id: dynamicDrlTest, v 0.1 16/10/26 下午2:00 caicongyang1 Exp $$
*/
public class dynamicDrlTest {
private static final String RULESFILE_NAME = "rules.drl";
/**
* 规则文件内容(可以从数据库中加载)
*/
private static final String rules = "package com.caicongyang.drools.test; import com.caicongyang.drools.fact.Message; rule \"Hello World \" when message:Message (status == \"0\") then System.out.println(\"hello, Drools!\"); end";
public static void main(String[] args) throws Exception {
KieServices kieServices = KieServices.Factory.get();
/**
* 指定kjar包
*/
final ReleaseId releaseId = kieServices.newReleaseId("com", "caicongyang", "1.0.0");
// 创建初始化的kjar
InternalKieModule kJar = DroolsUtils.initKieJar(kieServices, releaseId);
KieRepository repository = kieServices.getRepository();
repository.addKieModule(kJar);
KieContainer kieContainer = kieServices.newKieContainer(releaseId);
KieSession session = kieContainer.newKieSession();
Message message = new Message();
message.setStatus("0");
//同一个fact第一次不命中
try {
session.insert(message);
session.fireAllRules();
} catch (Exception e) {
} finally {
session.dispose();
}
System.out.println("-----first fire end-------");
//新增一个规则文件
kJar = DroolsUtils.createKieJar(kieServices, releaseId,
new ResourceWrapper(ResourceFactory.newByteArrayResource(rules.getBytes()), RULESFILE_NAME));
repository.addKieModule(kJar);
kieContainer.updateToVersion(releaseId);
//同一个fact再次过滤规则:命中
session = kieContainer.newKieSession();
try {
session.insert(message);
session.fireAllRules();
} catch (Exception e) {
} finally {
session.dispose();
}
System.out.println("-----senond fire end-------");
}
}
上一篇:Drools6.4动态加载规则之(一)模板的简单应用 :http://blog.csdn.net/caicongyang/article/details/52702628
更多精彩内容请继续关注我的博客:http://blog.csdn.NET/caicongyang
记录与分享,你我共成长 -from
caicongyang