小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

規(guī)則引擎Drools動(dòng)態(tài)加載規(guī)則

 瘋子V587 2019-05-13

背景

最近,因工作需要做了規(guī)則引擎的調(diào)研,對(duì)比了多個(gè)規(guī)則引擎后,最終選擇開源規(guī)則引擎Drools。

Drools的優(yōu)點(diǎn)很多,而我決定使用Drools的原因主要是:

  • 非?;钴S的社區(qū)支持(JBoss支持);
  • 快速的執(zhí)行速度;
  • 完善的功能;
  • 國(guó)外金融領(lǐng)域使用比較多;

當(dāng)然,Drools也有很多缺點(diǎn):

  • 復(fù)雜(功能越多也意味著越復(fù)雜);
  • 文檔欠缺(官方文檔混亂、缺少中文文檔);
  • 學(xué)習(xí)成本高;

為了能完全掌控Drools,最近一直在學(xué)習(xí),使用各種方法學(xué)習(xí)Drools,通過(guò)在線文章、官方文檔、官方API、視頻教程等學(xué)習(xí),并且有潛伏進(jìn)一個(gè)Drools學(xué)習(xí)交流群,發(fā)現(xiàn)群里同學(xué)問(wèn)的最多的一個(gè)問(wèn)題就是:怎么樣通過(guò)數(shù)據(jù)庫(kù)動(dòng)態(tài)加載規(guī)則?正好,我們也打算采用從數(shù)據(jù)庫(kù)動(dòng)態(tài)加載規(guī)則,并且我正好解決了這個(gè)問(wèn)題,現(xiàn)在寫篇文章分享出來(lái)給大家,希望能幫助到大家。

事例

事例說(shuō)明

首先,通過(guò)代碼生成規(guī)則模擬從數(shù)據(jù)庫(kù)查詢規(guī)則,每條規(guī)則記錄包含:id(規(guī)則id,全局唯一)、sceneId(場(chǎng)景id,一個(gè)場(chǎng)景對(duì)應(yīng)多個(gè)規(guī)則)、content(規(guī)則內(nèi)容,既drl文件內(nèi)容)。

然后,按場(chǎng)景動(dòng)態(tài)加載規(guī)則,每個(gè)場(chǎng)景對(duì)應(yīng)一個(gè)實(shí)際的業(yè)務(wù)場(chǎng)景,通過(guò)場(chǎng)景隔離不同的業(yè)務(wù)。

最后,執(zhí)行應(yīng)用指定場(chǎng)景規(guī)則,模擬不同業(yè)務(wù)場(chǎng)景下的規(guī)則應(yīng)用。

事例實(shí)現(xiàn)

1. 創(chuàng)建Maven項(xiàng)目,引入依賴
    <properties>
        <drools.version>7.20.0.Final</drools.version>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.kie</groupId>
            <artifactId>kie-api</artifactId>
            <version>${drools.version}</version>
        </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.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
2. 創(chuàng)建規(guī)則記錄結(jié)構(gòu)
package com.loujinhe.droolsdynamicloading.model;

import lombok.Data;
import lombok.ToString;

/**
 * 規(guī)則信息
 *
 * @author loujinhe
 * @date 2019/4/14 00:13
 */
@Data
@ToString
public class RuleInfo {

    /**
     * 規(guī)則id,全局唯一
     */
    private Long id;

    /**
     * 場(chǎng)景id,一個(gè)場(chǎng)景對(duì)應(yīng)多個(gè)規(guī)則,一個(gè)場(chǎng)景對(duì)應(yīng)一個(gè)業(yè)務(wù)場(chǎng)景,一個(gè)場(chǎng)景對(duì)應(yīng)一個(gè)kmodule
     */
    private Long sceneId;

    /**
     * 規(guī)則內(nèi)容,既drl文件內(nèi)容
     */
    private String content;

}
3. 創(chuàng)建規(guī)則查詢接口

這里通過(guò)代碼生成規(guī)則記錄模擬從數(shù)據(jù)庫(kù)查詢規(guī)則記錄。

package com.loujinhe.droolsdynamicloading.service;

import com.loujinhe.droolsdynamicloading.model.RuleInfo;
import org.springframework.stereotype.Service;

import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 規(guī)則信息業(yè)務(wù)
 *
 * @author loujinhe
 * @date 2019/4/14 00:20
 */
@Service
public class RuleInfoService {

    /**
     * 獲取給定場(chǎng)景下的規(guī)則信息列表
     *
     * @param sceneId 場(chǎng)景ID
     * @return 規(guī)則列表
     */
    public List<RuleInfo> getRuleInfoListBySceneId(Long sceneId) {
        Map<Long, List<RuleInfo>> sceneId2RuleInfoListMap = getRuleInfoListMap();
        return sceneId2RuleInfoListMap.get(sceneId);
    }

    /**
     * 獲取場(chǎng)景與規(guī)則信息列表的Map
     *
     * @return 場(chǎng)景規(guī)則信息列表Map,Map(sceneId : List < RuleInfo >)
     */
    public Map<Long, List<RuleInfo>> getRuleInfoListMap() {
        Map<Long, List<RuleInfo>> sceneId2RuleInfoListMap = new HashMap<>();
        List<RuleInfo> allRuleInfos = generateRuleInfoList();
        for (RuleInfo ruleInfo : allRuleInfos) {
            List<RuleInfo> ruleInfos = sceneId2RuleInfoListMap.computeIfAbsent(ruleInfo.getSceneId(), k -> new ArrayList<>());
            ruleInfos.add(ruleInfo);
        }
        return sceneId2RuleInfoListMap;
    }

    /**
     * 生成規(guī)則信息列表,注意場(chǎng)景id和規(guī)則id的對(duì)應(yīng)關(guān)系
     *
     * @return 規(guī)則信息列表
     */
    private List<RuleInfo> generateRuleInfoList() {
        int sceneNum = 5;
        int ruleNumPerScene = 3;
        int sceneFactor = 10000;

        List<RuleInfo> ruleInfos = new ArrayList<>(sceneNum * ruleNumPerScene);
        for (int i = 0; i < sceneNum; i++) {
            long sceneId = sceneFactor * (i + 1);
            for (int j = 0; j < ruleNumPerScene; j++) {
                long id = sceneId + (j + 1);
                ruleInfos.add(generateRuleInfo(sceneId, id));
            }
        }

        return ruleInfos;
    }

    /**
     * 生成規(guī)則信息
     *
     * @param sceneId 場(chǎng)景ID
     * @param id      規(guī)則ID
     * @return 規(guī)則信息
     */
    private RuleInfo generateRuleInfo(long sceneId, long id) {
        RuleInfo ruleInfo = new RuleInfo();
        ruleInfo.setId(id);
        ruleInfo.setSceneId(sceneId);
        ruleInfo.setContent(generateRuleContent(sceneId, id));
        return ruleInfo;
    }

    /**
     * 生成規(guī)則內(nèi)容,每個(gè)場(chǎng)景id對(duì)應(yīng)一個(gè)package,每個(gè)規(guī)則對(duì)應(yīng)一個(gè)唯一的規(guī)則名
     *
     * 每次生成規(guī)則時(shí)記錄時(shí)間戳,用來(lái)驗(yàn)證動(dòng)態(tài)加載效果
     *
     * @param sceneId 場(chǎng)景ID
     * @param id      規(guī)則ID
     * @return 規(guī)則內(nèi)容
     */
    private String generateRuleContent(long sceneId, long id) {
        String sceneIdStr = String.valueOf(sceneId);
        String idStr = String.valueOf(id);
        String nowStr = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());

        String content = "package rules.scene_{0};\n" +
                "\n" +
                "rule \"rule_{1}\"\n" +
                "    when\n" +
                "        eval(true);\n" +
                "    then\n" +
                "        System.out.println(\"{2} [{3}, {4}]\");\n" +
                "end\n";
        return MessageFormat.format(content, sceneIdStr, idStr, nowStr, sceneIdStr, idStr);
    }
}
4. 創(chuàng)建規(guī)則加載器

可以加載全部場(chǎng)景下的規(guī)則,也可以加載指定場(chǎng)景下的規(guī)則。

package com.loujinhe.droolsdynamicloading.drools;

import com.loujinhe.droolsdynamicloading.model.RuleInfo;
import com.loujinhe.droolsdynamicloading.service.RuleInfoService;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.Message;
import org.kie.api.builder.Results;
import org.kie.api.builder.model.KieBaseModel;
import org.kie.api.builder.model.KieModuleModel;
import org.kie.api.runtime.KieContainer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.text.MessageFormat;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 規(guī)則加載器
 *
 * @author loujinhe
 * @date 2019/4/14 00:06
 */
@Component
public class RuleLoader implements ApplicationRunner {

    /**
     * key:kcontainerName,value:KieContainer,每個(gè)場(chǎng)景對(duì)應(yīng)一個(gè)KieContainer
     */
    private final ConcurrentMap<String, KieContainer> kieContainerMap = new ConcurrentHashMap<>();

    @Autowired
    private RuleInfoService ruleInfoService;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        reloadAll();
    }

    /**
     * 構(gòu)造kcontainerName
     *
     * @param sceneId 場(chǎng)景ID
     * @return kcontainerName
     */
    private String buildKcontainerName(long sceneId) {
        return "kcontainer_" + sceneId;
    }

    /**
     * 構(gòu)造kbaseName
     *
     * @param sceneId 場(chǎng)景ID
     * @return kbaseName
     */
    private String buildKbaseName(long sceneId) {
        return "kbase_" + sceneId;
    }

    /**
     * 構(gòu)造ksessionName
     *
     * @param sceneId 場(chǎng)景ID
     * @return ksessionName
     */
    private String buildKsessionName(long sceneId) {
        return "ksession_" + sceneId;
    }

    KieContainer getKieContainerBySceneId(long sceneId) {
        return kieContainerMap.get(buildKcontainerName(sceneId));
    }

    /**
     * 重新加載所有規(guī)則
     */
    public void reloadAll() {
        Map<Long, List<RuleInfo>> sceneId2RuleInfoListMap = ruleInfoService.getRuleInfoListMap();
        for (Map.Entry<Long, List<RuleInfo>> entry : sceneId2RuleInfoListMap.entrySet()) {
            long sceneId = entry.getKey();
            reload(sceneId, entry.getValue());
        }
        System.out.println("reload all success");
    }

    /**
     * 重新加載給定場(chǎng)景下的規(guī)則
     *
     * @param sceneId 場(chǎng)景ID
     */
    public void reload(Long sceneId) {
        List<RuleInfo> ruleInfos = ruleInfoService.getRuleInfoListBySceneId(sceneId);
        reload(sceneId, ruleInfos);
        System.out.println("reload success");
    }

    /**
     * 重新加載給定場(chǎng)景給定規(guī)則列表,對(duì)應(yīng)一個(gè)kmodule
     *
     * @param sceneId   場(chǎng)景ID
     * @param ruleInfos 規(guī)則列表
     */
    private void reload(long sceneId, List<RuleInfo> ruleInfos) {
        KieServices kieServices = KieServices.get();
        KieModuleModel kieModuleModel = kieServices.newKieModuleModel();
        KieBaseModel kieBaseModel = kieModuleModel.newKieBaseModel(buildKbaseName(sceneId));
        kieBaseModel.setDefault(true);
        kieBaseModel.addPackage(MessageFormat.format("rules.scene_{0}", String.valueOf(sceneId)));
        kieBaseModel.newKieSessionModel(buildKsessionName(sceneId));

        KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
        for (RuleInfo ruleInfo : ruleInfos) {
            String fullPath = MessageFormat.format("src/main/resources/rules/scene_{0}/rule_{1}.drl", String.valueOf(sceneId), String.valueOf(ruleInfo.getId()));
            kieFileSystem.write(fullPath, ruleInfo.getContent());
        }
        kieFileSystem.writeKModuleXML(kieModuleModel.toXML());

        KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem).buildAll();
        Results results = kieBuilder.getResults();
        if (results.hasMessages(Message.Level.ERROR)) {
            System.out.println(results.getMessages());
            throw new IllegalStateException("rule error");
        }

        KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());
        kieContainerMap.put(buildKcontainerName(sceneId), kieContainer);
    }
}
5. 創(chuàng)建KieSession輔助類

通過(guò)該輔助類可以獲取指定場(chǎng)景下的KieSession,通過(guò)該KieSession可以與指定場(chǎng)景規(guī)則交互。

package com.loujinhe.droolsdynamicloading.drools;

import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * KieSession助手類
 *
 * @author loujinhe
 * @date 2019/4/15 22:29
 */
@Component
public class KieSessionHelper {

    @Autowired
    private RuleLoader ruleLoader;

    /**
     * 獲取KieSession
     *
     * @param sceneId 場(chǎng)景ID
     * @return KieSession
     */
    public KieSession getKieSessionBySceneId(long sceneId) {
        return ruleLoader.getKieContainerBySceneId(sceneId).getKieBase().newKieSession();
    }
}
6. 創(chuàng)建業(yè)務(wù)入口

包含動(dòng)態(tài)加載指定場(chǎng)景規(guī)則功能,以及觸發(fā)指定場(chǎng)景下的規(guī)則功能。

package com.loujinhe.droolsdynamicloading.controller;

import com.loujinhe.droolsdynamicloading.drools.KieSessionHelper;
import com.loujinhe.droolsdynamicloading.drools.RuleLoader;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 規(guī)則測(cè)試
 *
 * @author loujinhe
 * @date 2019/4/14 01:35
 */
@RequestMapping("rule")
@RestController
public class RuleController {

    @Autowired
    private RuleLoader ruleLoader;

    @Autowired
    private KieSessionHelper kieSessionHelper;

    @GetMapping("/")
    public String index() {
        System.out.println("index");
        return "success";
    }

    /**
     * 重新加載所有規(guī)則
     */
    @GetMapping("reload")
    public String reload() {
        System.out.println("reload all");
        ruleLoader.reloadAll();
        return "success";
    }

    /**
     * 重新加載給定場(chǎng)景下的規(guī)則
     *
     * @param sceneId 場(chǎng)景ID
     */
    @GetMapping("reload/{sceneId}")
    public String reload(@PathVariable("sceneId") Long sceneId) {
        System.out.println("reload scene:" + sceneId);
        ruleLoader.reload(sceneId);
        return "success";
    }

    /**
     * 觸發(fā)給定場(chǎng)景規(guī)則
     *
     * @param sceneId 場(chǎng)景ID
     */
    @GetMapping("fire/{sceneId}")
    public String fire(@PathVariable("sceneId") Long sceneId) {
        System.out.println("fire scene:" + sceneId);
        KieSession kieSession = kieSessionHelper.getKieSessionBySceneId(sceneId);
        kieSession.fireAllRules();
        kieSession.dispose();
        return "success";
    }

}
7. 啟動(dòng)服務(wù)

默認(rèn)加載所有場(chǎng)景下的規(guī)則,啟動(dòng)時(shí)日志如下:

/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/bin/java -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=54524 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=127.0.0.1 -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true "-javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=54525:/Applications/IntelliJ IDEA.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/tools.jar:/Users/loujinhe/project/IdeaProjects/drools-dynamic-loading/target/classes:/Users/loujinhe/.m2/repository/org/kie/kie-api/7.20.0.Final/kie-api-7.20.0.Final.jar:/Users/loujinhe/.m2/repository/org/kie/soup/kie-soup-maven-support/7.20.0.Final/kie-soup-maven-support-7.20.0.Final.jar:/Users/loujinhe/.m2/repository/org/slf4j/slf4j-api/1.7.26/slf4j-api-1.7.26.jar:/Users/loujinhe/.m2/repository/org/drools/drools-core/7.20.0.Final/drools-core-7.20.0.Final.jar:/Users/loujinhe/.m2/repository/org/mvel/mvel2/2.4.4.Final/mvel2-2.4.4.Final.jar:/Users/loujinhe/.m2/repository/org/kie/kie-internal/7.20.0.Final/kie-internal-7.20.0.Final.jar:/Users/loujinhe/.m2/repository/org/kie/soup/kie-soup-commons/7.20.0.Final/kie-soup-commons-7.20.0.Final.jar:/Users/loujinhe/.m2/repository/org/kie/soup/kie-soup-project-datamodel-commons/7.20.0.Final/kie-soup-project-datamodel-commons-7.20.0.Final.jar:/Users/loujinhe/.m2/repository/org/kie/soup/kie-soup-project-datamodel-api/7.20.0.Final/kie-soup-project-datamodel-api-7.20.0.Final.jar:/Users/loujinhe/.m2/repository/commons-codec/commons-codec/1.11/commons-codec-1.11.jar:/Users/loujinhe/.m2/repository/org/drools/drools-compiler/7.20.0.Final/drools-compiler-7.20.0.Final.jar:/Users/loujinhe/.m2/repository/org/antlr/antlr-runtime/3.5.2/antlr-runtime-3.5.2.jar:/Users/loujinhe/.m2/repository/org/eclipse/jdt/core/compiler/ecj/4.6.1/ecj-4.6.1.jar:/Users/loujinhe/.m2/repository/com/thoughtworks/xstream/xstream/1.4.10/xstream-1.4.10.jar:/Users/loujinhe/.m2/repository/xmlpull/xmlpull/1.1.3.1/xmlpull-1.1.3.1.jar:/Users/loujinhe/.m2/repository/xpp3/xpp3_min/1.1.4c/xpp3_min-1.1.4c.jar:/Users/loujinhe/.m2/repository/com/google/protobuf/protobuf-java/3.6.1/protobuf-java-3.6.1.jar:/Users/loujinhe/.m2/repository/org/projectlombok/lombok/1.18.6/lombok-1.18.6.jar:/Users/loujinhe/.m2/repository/org/springframework/boot/spring-boot-starter-web/2.1.4.RELEASE/spring-boot-starter-web-2.1.4.RELEASE.jar:/Users/loujinhe/.m2/repository/org/springframework/boot/spring-boot-starter/2.1.4.RELEASE/spring-boot-starter-2.1.4.RELEASE.jar:/Users/loujinhe/.m2/repository/org/springframework/boot/spring-boot/2.1.4.RELEASE/spring-boot-2.1.4.RELEASE.jar:/Users/loujinhe/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.1.4.RELEASE/spring-boot-autoconfigure-2.1.4.RELEASE.jar:/Users/loujinhe/.m2/repository/org/springframework/boot/spring-boot-starter-logging/2.1.4.RELEASE/spring-boot-starter-logging-2.1.4.RELEASE.jar:/Users/loujinhe/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar:/Users/loujinhe/.m2/repository/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar:/Users/loujinhe/.m2/repository/org/apache/logging/log4j/log4j-to-slf4j/2.11.2/log4j-to-slf4j-2.11.2.jar:/Users/loujinhe/.m2/repository/org/apache/logging/log4j/log4j-api/2.11.2/log4j-api-2.11.2.jar:/Users/loujinhe/.m2/repository/org/slf4j/jul-to-slf4j/1.7.26/jul-to-slf4j-1.7.26.jar:/Users/loujinhe/.m2/repository/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2.jar:/Users/loujinhe/.m2/repository/org/yaml/snakeyaml/1.23/snakeyaml-1.23.jar:/Users/loujinhe/.m2/repository/org/springframework/boot/spring-boot-starter-json/2.1.4.RELEASE/spring-boot-starter-json-2.1.4.RELEASE.jar:/Users/loujinhe/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.9.8/jackson-databind-2.9.8.jar:/Users/loujinhe/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.9.0/jackson-annotations-2.9.0.jar:/Users/loujinhe/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.9.8/jackson-core-2.9.8.jar:/Users/loujinhe/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.9.8/jackson-datatype-jdk8-2.9.8.jar:/Users/loujinhe/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.9.8/jackson-datatype-jsr310-2.9.8.jar:/Users/loujinhe/.m2/repository/com/fasterxml/jackson/module/jackson-module-parameter-names/2.9.8/jackson-module-parameter-names-2.9.8.jar:/Users/loujinhe/.m2/repository/org/springframework/boot/spring-boot-starter-tomcat/2.1.4.RELEASE/spring-boot-starter-tomcat-2.1.4.RELEASE.jar:/Users/loujinhe/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/9.0.17/tomcat-embed-core-9.0.17.jar:/Users/loujinhe/.m2/repository/org/apache/tomcat/embed/tomcat-embed-el/9.0.17/tomcat-embed-el-9.0.17.jar:/Users/loujinhe/.m2/repository/org/apache/tomcat/embed/tomcat-embed-websocket/9.0.17/tomcat-embed-websocket-9.0.17.jar:/Users/loujinhe/.m2/repository/org/hibernate/validator/hibernate-validator/6.0.16.Final/hibernate-validator-6.0.16.Final.jar:/Users/loujinhe/.m2/repository/javax/validation/validation-api/2.0.1.Final/validation-api-2.0.1.Final.jar:/Users/loujinhe/.m2/repository/org/jboss/logging/jboss-logging/3.3.2.Final/jboss-logging-3.3.2.Final.jar:/Users/loujinhe/.m2/repository/com/fasterxml/classmate/1.4.0/classmate-1.4.0.jar:/Users/loujinhe/.m2/repository/org/springframework/spring-web/5.1.6.RELEASE/spring-web-5.1.6.RELEASE.jar:/Users/loujinhe/.m2/repository/org/springframework/spring-beans/5.1.6.RELEASE/spring-beans-5.1.6.RELEASE.jar:/Users/loujinhe/.m2/repository/org/springframework/spring-webmvc/5.1.6.RELEASE/spring-webmvc-5.1.6.RELEASE.jar:/Users/loujinhe/.m2/repository/org/springframework/spring-aop/5.1.6.RELEASE/spring-aop-5.1.6.RELEASE.jar:/Users/loujinhe/.m2/repository/org/springframework/spring-context/5.1.6.RELEASE/spring-context-5.1.6.RELEASE.jar:/Users/loujinhe/.m2/repository/org/springframework/spring-expression/5.1.6.RELEASE/spring-expression-5.1.6.RELEASE.jar:/Users/loujinhe/.m2/repository/org/springframework/spring-core/5.1.6.RELEASE/spring-core-5.1.6.RELEASE.jar:/Users/loujinhe/.m2/repository/org/springframework/spring-jcl/5.1.6.RELEASE/spring-jcl-5.1.6.RELEASE.jar com.loujinhe.droolsdynamicloading.DroolsDynamicLoadingApplication

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.4.RELEASE)

2019-05-11 01:26:16.189  INFO 5866 --- [           main] c.l.d.DroolsDynamicLoadingApplication    : Starting DroolsDynamicLoadingApplication on loujinhedeMacBook-Pro.local with PID 5866 (/Users/loujinhe/project/IdeaProjects/drools-dynamic-loading/target/classes started by loujinhe in /Users/loujinhe/project/IdeaProjects/drools-dynamic-loading)
2019-05-11 01:26:16.191  INFO 5866 --- [           main] c.l.d.DroolsDynamicLoadingApplication    : No active profile set, falling back to default profiles: default
2019-05-11 01:26:16.836  INFO 5866 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2019-05-11 01:26:16.851  INFO 5866 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2019-05-11 01:26:16.851  INFO 5866 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.17]
2019-05-11 01:26:16.910  INFO 5866 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2019-05-11 01:26:16.910  INFO 5866 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 696 ms
2019-05-11 01:26:17.052  INFO 5866 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2019-05-11 01:26:17.203  INFO 5866 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2019-05-11 01:26:17.206  INFO 5866 --- [           main] c.l.d.DroolsDynamicLoadingApplication    : Started DroolsDynamicLoadingApplication in 1.224 seconds (JVM running for 1.626)
2019-05-11 01:26:17.220  INFO 5866 --- [           main] o.k.a.i.utils.ServiceDiscoveryImpl       : Loading kie.conf from  jar:file:/Users/loujinhe/.m2/repository/org/drools/drools-core/7.20.0.Final/drools-core-7.20.0.Final.jar!/META-INF/kie.conf in classloader sun.misc.Launcher$AppClassLoader@18b4aac2
2019-05-11 01:26:17.221  INFO 5866 --- [           main] o.k.a.i.utils.ServiceDiscoveryImpl       : Adding Service org.drools.core.io.impl.ResourceFactoryServiceImpl

2019-05-11 01:26:17.222  INFO 5866 --- [           main] o.k.a.i.utils.ServiceDiscoveryImpl       : Adding Service org.drools.core.marshalling.impl.MarshallerProviderImpl

2019-05-11 01:26:17.222  INFO 5866 --- [           main] o.k.a.i.utils.ServiceDiscoveryImpl       : Adding Service org.drools.core.concurrent.ExecutorProviderImpl

2019-05-11 01:26:17.222  INFO 5866 --- [           main] o.k.a.i.utils.ServiceDiscoveryImpl       : Loading kie.conf from  jar:file:/Users/loujinhe/.m2/repository/org/kie/kie-internal/7.20.0.Final/kie-internal-7.20.0.Final.jar!/META-INF/kie.conf in classloader sun.misc.Launcher$AppClassLoader@18b4aac2
2019-05-11 01:26:17.223  INFO 5866 --- [           main] o.k.a.i.utils.ServiceDiscoveryImpl       : Adding Service org.kie.internal.services.KieAssemblersImpl

2019-05-11 01:26:17.223  INFO 5866 --- [           main] o.k.a.i.utils.ServiceDiscoveryImpl       : Adding Service org.kie.internal.services.KieRuntimesImpl

2019-05-11 01:26:17.224  INFO 5866 --- [           main] o.k.a.i.utils.ServiceDiscoveryImpl       : Adding Service org.kie.internal.services.KieWeaversImpl

2019-05-11 01:26:17.224  INFO 5866 --- [           main] o.k.a.i.utils.ServiceDiscoveryImpl       : Adding Service org.kie.internal.services.KieBeliefsImpl

2019-05-11 01:26:17.224  INFO 5866 --- [           main] o.k.a.i.utils.ServiceDiscoveryImpl       : Loading kie.conf from  jar:file:/Users/loujinhe/.m2/repository/org/drools/drools-compiler/7.20.0.Final/drools-compiler-7.20.0.Final.jar!/META-INF/kie.conf in classloader sun.misc.Launcher$AppClassLoader@18b4aac2
2019-05-11 01:26:17.225  INFO 5866 --- [           main] o.k.a.i.utils.ServiceDiscoveryImpl       : Adding Service org.drools.compiler.kie.builder.impl.KieServicesImpl

2019-05-11 01:26:17.226  INFO 5866 --- [           main] o.k.a.i.utils.ServiceDiscoveryImpl       : Adding Service org.drools.compiler.builder.impl.KnowledgeBuilderFactoryServiceImpl

2019-05-11 01:26:17.778  INFO 5866 --- [           main] o.d.c.k.builder.impl.KieRepositoryImpl   : KieModule was added: MemoryKieModule[releaseId=org.default:artifact:1.0.0]
2019-05-11 01:26:17.800  INFO 5866 --- [           main] o.d.c.k.builder.impl.KieRepositoryImpl   : KieModule was added: MemoryKieModule[releaseId=org.default:artifact:1.0.0]
2019-05-11 01:26:17.816  INFO 5866 --- [           main] o.d.c.k.builder.impl.KieRepositoryImpl   : KieModule was added: MemoryKieModule[releaseId=org.default:artifact:1.0.0]
2019-05-11 01:26:17.831  INFO 5866 --- [           main] o.d.c.k.builder.impl.KieRepositoryImpl   : KieModule was added: MemoryKieModule[releaseId=org.default:artifact:1.0.0]
2019-05-11 01:26:17.846  INFO 5866 --- [           main] o.d.c.k.builder.impl.KieRepositoryImpl   : KieModule was added: MemoryKieModule[releaseId=org.default:artifact:1.0.0]
reload all success
8. 驗(yàn)證

8.1 首先,分別觸發(fā)場(chǎng)景10000、20000、30000下的規(guī)則,訪問(wèn)url及日志如下:
http://localhost:8080/rule/fire/10000
http://localhost:8080/rule/fire/20000
http://localhost:8080/rule/fire/30000

2019-05-11 01:32:01.844  INFO 5866 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2019-05-11 01:32:01.844  INFO 5866 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2019-05-11 01:32:01.851  INFO 5866 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 7 ms

fire scene:10000
20190511012617 [10000, 10002]
20190511012617 [10000, 10003]
20190511012617 [10000, 10001]

fire scene:20000
20190511012617 [20000, 20001]
20190511012617 [20000, 20003]
20190511012617 [20000, 20002]

fire scene:30000
20190511012617 [30000, 30001]
20190511012617 [30000, 30002]
20190511012617 [30000, 30003]

通過(guò)分析日志發(fā)現(xiàn),規(guī)則是按場(chǎng)景隔離的,并且規(guī)則的生成時(shí)間戳都是:20190511012617。

8.2 然后,加載場(chǎng)景20000下的規(guī)則,訪問(wèn)url及日志如下:
http://localhost:8080/rule/reload/20000

reload scene:20000
2019-05-11 01:34:45.988  INFO 5866 --- [nio-8080-exec-9] o.d.c.k.builder.impl.KieRepositoryImpl   : KieModule was added: MemoryKieModule[releaseId=org.default:artifact:1.0.0]
reload success

通過(guò)分析日志發(fā)現(xiàn),規(guī)則加載成功(應(yīng)該)。

8.3 最后,分別觸發(fā)場(chǎng)景10000、20000、30000下的規(guī)則,訪問(wèn)url及日志如下:
http://localhost:8080/rule/fire/10000
http://localhost:8080/rule/fire/20000
http://localhost:8080/rule/fire/30000

fire scene:10000
20190511012617 [10000, 10002]
20190511012617 [10000, 10003]
20190511012617 [10000, 10001]

fire scene:20000
20190511013445 [20000, 20001]
20190511013445 [20000, 20002]
20190511013445 [20000, 20003]

fire scene:30000
20190511012617 [30000, 30001]
20190511012617 [30000, 30002]
20190511012617 [30000, 30003]

通過(guò)分析日志發(fā)現(xiàn),場(chǎng)景10000、30000的時(shí)間戳是一樣的,跟第一次加載時(shí)的時(shí)間戳是一樣的,而場(chǎng)景20000的時(shí)間戳不一樣,為20190511013445正好是我們剛才手動(dòng)動(dòng)態(tài)加載時(shí)的時(shí)間戳,說(shuō)明動(dòng)態(tài)加載指定場(chǎng)景規(guī)則成功。

事例總結(jié)

整個(gè)動(dòng)態(tài)加載規(guī)則的核心代碼就幾行,核心代碼如下:

/**
     * 重新加載給定場(chǎng)景給定規(guī)則列表,對(duì)應(yīng)一個(gè)kmodule
     *
     * @param sceneId   場(chǎng)景ID
     * @param ruleInfos 規(guī)則列表
     */
    private void reload(long sceneId, List<RuleInfo> ruleInfos) {
        KieServices kieServices = KieServices.get();
        KieModuleModel kieModuleModel = kieServices.newKieModuleModel();
        KieBaseModel kieBaseModel = kieModuleModel.newKieBaseModel(buildKbaseName(sceneId));
        kieBaseModel.setDefault(true);
        kieBaseModel.addPackage(MessageFormat.format("rules.scene_{0}", String.valueOf(sceneId)));
        kieBaseModel.newKieSessionModel(buildKsessionName(sceneId));

        KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
        for (RuleInfo ruleInfo : ruleInfos) {
            String fullPath = MessageFormat.format("src/main/resources/rules/scene_{0}/rule_{1}.drl", String.valueOf(sceneId), String.valueOf(ruleInfo.getId()));
            kieFileSystem.write(fullPath, ruleInfo.getContent());
        }
        kieFileSystem.writeKModuleXML(kieModuleModel.toXML());

        KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem).buildAll();
        Results results = kieBuilder.getResults();
        if (results.hasMessages(Message.Level.ERROR)) {
            System.out.println(results.getMessages());
            throw new IllegalStateException("rule error");
        }

        KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());
        kieContainerMap.put(buildKcontainerName(sceneId), kieContainer);
    }

通過(guò)分析代碼發(fā)現(xiàn),動(dòng)態(tài)加載規(guī)則的方式跟通過(guò)kmodule.xml配置文件加載規(guī)則的方式是對(duì)應(yīng)的,如:KieModuleModel 對(duì)應(yīng)kmodule節(jié)點(diǎn),KieBaseModel對(duì)應(yīng)kbase節(jié)點(diǎn),并且最終也是通過(guò)轉(zhuǎn)換成kmodule.xml配置文件的方式加載規(guī)則的,如:kieFileSystem.writeKModuleXML(kieModuleModel.toXML())。

總結(jié)

Drools很好很強(qiáng)大,文檔很爛很差勁,希望我的綿薄之力可以節(jié)省大家的寶貴時(shí)間。

備注
代碼已提交到碼云:https:///loujinhe/drools-dynamic-loading

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多