一.前言
網上規則引擎drools介紹很多,并且有很多細緻的說明,作者也不敢托大說自己的好用,但作者經過2個項目使用過規則引擎後,自己對規則引擎的了解并進行封裝,對規則内容及如何使用,有自己的一番實踐,并提供源代碼,供大家參考
二.設計思路及具體代碼
首先我希望是輕量級的使用drools,不希望使用太過複雜的架構,以這種思路入手,就可以與任何項目輕易融入,這樣就需要能夠将drools規則的來源,從規則檔案(drl)中可以從maven和自己的資料庫中擷取,腳本是動态的,配合drools6.5支援通過maven接入的規則的API,就可以做到從任何處擷取規則内容
一個工具類DroolsUtils
- package com.vip.jie.rule.util;
- 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 java.io.IOException;
- /**
- * 動态生成kjar
- * @author jie01.zhu
- * @DateTime 2018/3/19 22:14
- */
- public class DroolsUtils {
- /**
- * 建立預設的kbase和stateful的kiesession
- *
- * @param ks
- * @param isdefault
- * @return
- */
- private 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
- */
- private 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;
- }
- /**
- * 初始化一個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));
- 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, DroolsResource droolsResource) {
- KieFileSystem kfs = createKieFileSystemWithKProject(ks, true);
- kfs.writePomXML(getPom(releaseId));
- kfs.write("src/main/resources/" + droolsResource.getTargetResourceName(), droolsResource.getResource());
- KieBuilder kieBuilder = ks.newKieBuilder(kfs);
- if (!kieBuilder.getResults().getMessages().isEmpty()) {
- throw new IllegalStateException(
- "Error creating KieBuilder. errorMsg:" + kieBuilder.getResults().getMessages());
- }
- return (InternalKieModule) kieBuilder.getKieModule();
- }
- }
重點調用參考:
- String fileName = "jie-" + group + "-rules";
- /**
- * 指定kjar包
- */
- final ReleaseId releaseId = kieServices.newReleaseId("com.vip.jie", fileName, "1.0.0");
- log.info("DroolsGetKieSession fileName:{}", fileName);
- log.info("[DroolsGetKieSession] drlStr:{}", drlStr);
- // 建立初始化的kjar
- InternalKieModule kJar = DroolsUtils.createKieJar(kieServices, releaseId,
- new DroolsResource(ResourceFactory.newByteArrayResource(drlStr.getBytes()),
- fileName + ".drl"));
其次再将如何讓使用者可以很靈活的接入,利用可變參數類型,将入參對象無限制傳入,由規則腳本去決定入參的變化,通過此種方式可以比較好的實作業務靈活接入
如下單元測試類:
- package com.vip.jie.rule.service.impl;
- import com.vip.jie.rule.object.User;
- import com.vip.jie.rule.service.RuleManager;
- import lombok.extern.slf4j.Slf4j;
- import org.junit.Test;
- import static junit.framework.TestCase.fail;
- /**
- * 規則測試
- * @author jie01.zhu
- * @DateTime 2018/3/19 21:17
- *
- */
- @Slf4j
- public class RuleManagerImplTest {
- private RuleManager ruleManager = new RuleManagerImpl();
- private String getRuleContent() {
- StringBuilder stringBuilder = new StringBuilder();
- stringBuilder.append("import com.vip.jie.rule.object.User;\n");
- stringBuilder.append("rule test1 when\n");
- stringBuilder.append("user : User(age==20)\n");
- stringBuilder.append("then\n");
- stringBuilder.append("user.setName(\"張三\");\n");
- stringBuilder.append("end\n");
- return stringBuilder.toString();
- }
- @Test
- public void executeRule1() throws Exception {
- User user = new User();
- user.setAge(20);
- //調用規則
- ruleManager.executeRule("test1", getRuleContent(), user);
- log.info("test result:{}", user.toString());
- if (!"張三".equals(user.getName())) {
- fail("error rule");
- }
- }
- @Test
- public void executeRule2() throws Exception {
- User user = new User();
- user.setAge(21);
- //調用規則
- ruleManager.executeRule("test1", getRuleContent(), user);
- log.info("test result:{}", user.toString());
- if ("張三".equals(user.getName())) {
- fail("error rule");
- }
- }
- }
三.對應示例源代碼擷取方式
githup:
https://github.com/jie01/drools-demo
csdn資源下載下傳位址:
https://download.csdn.net/download/vipshop_fin_dev/10296393
還有一些關于安全性及與spring的封裝思路,作者表示還會繼續完善,并還不是最終版本,有需要可以持續關注-_-!
與目前文章有關聯的連結
業務架構之個性化監控方案
vipshop_ebs/朱傑
2018-03-19
原文位址:https://blog.csdn.net/vipshop_fin_dev/article/details/79618067