Drools规则引擎接入详解

Drools是Jboss开源的一个规则引擎,简单来说就是一种运算速度极快且配置非常灵活的计算工具,这篇博客不分析底层实现了,因为互联网上面随便一搜就能发现很多介绍,但是真正去使用的博客却太少了,也许真正用的很深的不多大家都只是抄来抄去那些原理

公司最近正好需要这么一个服务我们便开始研究起来并最终上线,其实在实践过程中遇到很多的坑,并且由于网上解决资料非常少导致耽误了不少时间,在这里写出来也是为了帮助后续的小伙伴排雷,Jboss官方文档中提到得接入方式其实分为2种:

1.离线接入(下载Drools官方jar使用内部jar得API进行)

2.Kie-Server接入(搭建官方集群,作为client接入Drools服务)

 

两种做法都有优缺点:

离线/Kie接入对比
  离线 Kie
接入难度
分布式集群 官方jar支持很弱,需要自己二次开发 支持
性能 极高,因为本地内存直接运算 较高,有了网络交互得消耗,损失部分性能
扩展性 低,基本都需要自己二次开发

 

从上面这个表格可以看出初学者入门使用离线方式是最好得,不过即使使用这种方式由于中文文档得缺失其实也是比较复杂得,我们公司当时前期使用得是第一种方式

那么开始进入主题,如何快速搭建Drools并且使用,公司使用的是Drools 7.7版本

POM文件配置加入:

        
            org.drools
            drools-core
            7.7.0.Final
            
                
                    mvel2
                    org.mvel
                
            
        
        
            org.drools
            drools-compiler
            7.7.0.Final
            
                
                    protobuf-java
                    com.google.protobuf
                
            
        
        
            org.drools
            drools-decisiontables
            7.7.0.Final
        
        
            org.drools
            drools-templates
            7.7.0.Final
        

Drools有动态和静态规则两种,我们公司采用的是动态规则,利用Drools的API进行开发将规则原始数据存储到Mysql中,然后动态加入Drools的工作内存并计算,其实原理是一样得,都是采用DRL规则语法,只是一个是静态加载DRL文件一个是动态内存中生成DRL规范得字符串

Drools 中文文档网站:http://www.drools.org.cn/category/use   (版本比较老了,但是是为数不多得中文文档)

Drools 官方网站:https://www.drools.org/    (可以下载最新版官方接入document,但是是全英语版本得)

 

公司存放规则得数据库sql如下:

/*
 Navicat Premium Data Transfer

 Source Server         : wms4-test-shard
 Source Server Type    : MySQL
 Source Server Version : 50718
 Source Host           : 10.88.27.117:3306
 Source Schema         : drools

 Target Server Type    : MySQL
 Target Server Version : 50718
 File Encoding         : 65001

 Date: 18/06/2019 15:14:41
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for factremarks
-- ----------------------------
DROP TABLE IF EXISTS `factremarks`;
CREATE TABLE `factremarks` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `attribute` varchar(200) NOT NULL,
  `remarks` varchar(200) NOT NULL,
  `type` varchar(200) NOT NULL,
  `create_time` date DEFAULT NULL,
  `create_by` varchar(50) DEFAULT NULL,
  `update_by` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for rulecondition
-- ----------------------------
DROP TABLE IF EXISTS `rulecondition`;
CREATE TABLE `rulecondition` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `ruleInfo_id` bigint(20) NOT NULL,
  `conditionKey` varchar(200) DEFAULT NULL,
  `op` varchar(200) NOT NULL,
  `conditionValue` varchar(200) DEFAULT NULL,
  `associationType` varchar(200) DEFAULT NULL,
  `create_time` date DEFAULT NULL,
  `create_by` varchar(50) DEFAULT NULL,
  `update_by` varchar(50) DEFAULT NULL,
  `paramType` varchar(200) DEFAULT NULL,
  `type` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `ruleInfo_id` (`ruleInfo_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=404 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for ruleglobal
-- ----------------------------
DROP TABLE IF EXISTS `ruleglobal`;
CREATE TABLE `ruleglobal` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `rule_id` bigint(20) NOT NULL,
  `globalName` varchar(40) NOT NULL,
  `globalType` varchar(40) NOT NULL,
  `create_time` date DEFAULT NULL,
  `create_by` varchar(50) DEFAULT NULL,
  `update_by` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=125 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for rulegroup
-- ----------------------------
DROP TABLE IF EXISTS `rulegroup`;
CREATE TABLE `rulegroup` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `groupCode` varchar(40) NOT NULL,
  `groupName` varchar(40) DEFAULT '',
  `description` varchar(200) DEFAULT '',
  `create_time` date DEFAULT NULL,
  `create_by` varchar(50) DEFAULT NULL,
  `update_by` varchar(50) DEFAULT NULL,
  `ou_id` varchar(30) DEFAULT NULL,
  `type` int(11) DEFAULT NULL COMMENT '规则组属于什么模块  1-上架',
  `groupType` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `groupCode` (`groupCode`) USING BTREE,
  KEY `ouid` (`ou_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=108 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for rulegroupref
-- ----------------------------
DROP TABLE IF EXISTS `rulegroupref`;
CREATE TABLE `rulegroupref` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `rule_id` bigint(20) NOT NULL,
  `ruleGroup_id` bigint(20) NOT NULL,
  `orderNo` int(11) DEFAULT NULL,
  `state` int(11) DEFAULT NULL,
  `create_time` date DEFAULT NULL,
  `create_by` varchar(50) DEFAULT NULL,
  `update_by` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `ruleGroup_id` (`ruleGroup_id`),
  KEY `rule_Id` (`rule_id`),
  KEY `state` (`state`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=151 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for rulehead
-- ----------------------------
DROP TABLE IF EXISTS `rulehead`;
CREATE TABLE `rulehead` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `ruleName` varchar(100) NOT NULL,
  `packageName` varchar(40) NOT NULL,
  `remarks` varchar(200) DEFAULT NULL,
  `ruleString` varchar(60) DEFAULT NULL,
  `create_time` date DEFAULT NULL,
  `create_by` varchar(50) DEFAULT NULL,
  `update_by` varchar(50) DEFAULT NULL,
  `rule_str` varchar(500) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `ruleString` (`ruleString`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=122 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for ruleinfo
-- ----------------------------
DROP TABLE IF EXISTS `ruleinfo`;
CREATE TABLE `ruleinfo` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `rule_id` bigint(20) NOT NULL,
  `type` varchar(40) NOT NULL,
  `parent` varchar(200) DEFAULT NULL,
  `obj` varchar(200) NOT NULL,
  `calculation` varchar(200) DEFAULT NULL,
  `attribute` varchar(200) DEFAULT NULL,
  `create_time` date DEFAULT NULL,
  `create_by` varchar(50) DEFAULT NULL,
  `update_by` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `rule_id` (`rule_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=374 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for ruleop
-- ----------------------------
DROP TABLE IF EXISTS `ruleop`;
CREATE TABLE `ruleop` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `rule_id` bigint(20) NOT NULL,
  `objName` varchar(200) NOT NULL,
  `attribute` varchar(200) NOT NULL,
  `value` varchar(200) NOT NULL,
  `create_time` date DEFAULT NULL,
  `create_by` varchar(50) DEFAULT NULL,
  `update_by` varchar(50) DEFAULT NULL,
  `type` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `rule_id` (`rule_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=223 DEFAULT CHARSET=utf8;


ALTER TABLE `drools`.`rulecondition`
ADD COLUMN `brackets` varchar(200) NULL AFTER `type`;

ALTER TABLE `drools`.`ruleinfo`
ADD COLUMN `associationType` varchar(30) NULL AFTER `update_by`;


ALTER TABLE `drools`.`rulehead`
ADD COLUMN `frontEndData` text NULL AFTER `rule_str`;
SET FOREIGN_KEY_CHECKS = 1;

表结构说明文档下载地址:https://download.csdn.net/download/wmq880204/11665077    

 

公司离线方式流程图如下:

Drools规则引擎接入详解_第1张图片

 

整个流程还是比较简单易懂得,核心加载代码如下

@Autowired
private RuleLoadManager ruleLoadManager;

@Autowired
private KnowLedgeBaseManger knowLedgeBaseManger;

//查出数据库所有启用状态得规则并且装载到Map结构中
Map> map = ruleLoadManager.loadAllRules();
//开始循环所有规则数据加载至工作内存中
map.forEach((group, resourceList) -> knowLedgeBaseManger.createKnowledgeBase(resourceList, group));


KnowLedgeBaseManager 类实现方法

@Autowired
    private DroolsServicesBuilderFactory droolsServicesBuilderFactory;

    @Autowired
    private RuleLoadManager ruleLoadManager;

    @Autowired
    private KnowledgeBaseLib knowledgeBaseLib;

    /**
     * 根据传入规则创建知识库
     *
     * @param resources         规则
     * @param knowLedgeBaseName 知识库名称
     * @return
     */
    @Override
    public InternalKnowledgeBase createKnowledgeBase(List resources, String knowLedgeBaseName) {
        KnowledgeBuilder knowledgeBuilder = droolsServicesBuilderFactory.createKnowledgeBuilder();
        InternalKnowledgeBase internalKnowledgeBase = droolsServicesBuilderFactory.createInternalKnowledgeBase();
        droolsServicesBuilderFactory.addRules( knowledgeBuilder, resources, ResourceType.DRL );
        BiConsumer baseBuilder = droolsServicesBuilderFactory::buliderBase;
        baseBuilder.accept( internalKnowledgeBase, knowledgeBuilder );
        return internalKnowledgeBase;
    }

    /**
     * 测试规则
     *
     * @param resources
     */
    @Override
    public KnowledgeMessage testRule(List resources) {
        KnowledgeBuilder knowledgeBuilder = droolsServicesBuilderFactory.createKnowledgeBuilder();
        KnowledgeMessage knowledgeMessage = null;
        try {
            droolsServicesBuilderFactory.addRules( knowledgeBuilder, resources, ResourceType.DRL );
            knowledgeBuilder.undo();
            knowledgeMessage = new KnowledgeMessage( "", SUCCESS, null );
        } catch (KnowLedgeBuilderException ruleException) {
            knowledgeMessage = new KnowledgeMessage( "", FAILED, ruleException.toString() );
        }
        return knowledgeMessage;
    }

    /**
     * 重载全部知识库
     */
    @Override
    public void reloadRules() {
        knowledgeBaseLib.getAllInternalKnowledgeBase().forEach( (name, internalKnowledgeBase) -> internalKnowledgeBase.getKieSessions().forEach( kieSession -> kieSession.destroy() ) );
        knowledgeBaseLib.clearAllInternalKnowledgeBase();
        ruleLoadManager.loadAllRules().forEach( (knowledgeBaseName, resources) -> createKnowledgeBase( resources, knowledgeBaseName ) );
    }

    @Override
    public void reloadRulesByName(String knowLedgeBaseName) {
        knowledgeBaseLib.removeInternalKnowledgeBase( knowLedgeBaseName );
        reloadRules();
    }

    /**
     * 重载特定知识库规则
     *
     * @param knowLedgeBaseName
     */
    @Override
    public InternalKnowledgeBase reloadRule(String knowLedgeBaseName) {
        knowledgeBaseLib.getInternalKnowledgeBase( knowLedgeBaseName ).getKieSessions().forEach( kiesession -> kiesession.destroy() );
        knowledgeBaseLib.removeInternalKnowledgeBase( knowLedgeBaseName );
        createKnowledgeBase( ruleLoadManager.loadRule( knowLedgeBaseName ), knowLedgeBaseName );
        return knowledgeBaseLib.getInternalKnowledgeBase( knowLedgeBaseName );
    }

    /**
     * 释放session资源
     *
     * @param kieSession
     */
    @Override
    public void disposeKieSession(KieSession kieSession) {
        kieSession.dispose();
    }

    /**
     * 销毁session
     *
     * @param kieSession
     */
    @Override
    public void destoryKieSession(KieSession kieSession) {
        kieSession.destroy();
    }

   DroolsServicesBuilderFactory 类实现方法

private static final Logger log = LoggerFactory.getLogger(DroolsServicesBuilderFactory.class);

    @Autowired
    private CustomKieBaseConfiguration customKieBaseConfiguration;

    @Autowired
    private RuleHeadDao ruleHeadDao;

    /**
     * 知识规则的构建器
     *
     * @return
     */
    public KnowledgeBuilder createKnowledgeBuilder() {
        return KnowledgeBuilderFactory.newKnowledgeBuilder();
    }

    /**
     * 添加规则
     * @param knowledgeBuilder
     * @param resources
     * @param type
     */
    public void addRules(KnowledgeBuilder knowledgeBuilder, List resources,
                                    ResourceType type) {
        resources.forEach(resource -> {
            try {
                log.info( new String( resource.getBytes(), StandardCharsets.UTF_8 ) );
                knowledgeBuilder.add(resource,type);
            } catch (Exception e) {
                log.error( "addRuleError exction is {}",e );
            }
        });
        if(knowledgeBuilder.hasErrors()){
            log.error( "addRuleError is {}",knowledgeBuilder.getErrors().toString() );
        }
    }

    /**
    * @author QIQI
    * @Description: 根据ruleId删除规则
    * @params [ruleId]
    * @return void
    * @throws 
    * @date 2019-06-21 21:37 

    @LmisDataSource( "ds4" )
    public void removeRule(Long ruleId){
        RuleSaveModel groupCode = ruleHeadDao.getRuleInfoById(Integer.parseInt( String.valueOf( ruleId ) ));
        KnowledgeBuilder knowledgeBuilder = createKnowledgeBuilder();
        knowledgeBuilder.newKieBase().removeRule( FinalArgs.RULE_PACKAGE,groupCode.getRuleName() );
    }*/

    /**
     * 创建内部支持库
     * @return
     */
    public InternalKnowledgeBase createInternalKnowledgeBase(){
        KieBaseConfiguration kbc = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
        customKieBaseConfiguration.getKieBaseconfiguration().forEach((key,value)->kbc.setProperty(key,value));
        return KnowledgeBaseFactory.newKnowledgeBase(kbc);
    }

    /**
     * 构建基础库
     * @param internalKnowledgeBase
     * @param knowledgeBuilder
     */
    public void buliderBase(InternalKnowledgeBase internalKnowledgeBase,KnowledgeBuilder knowledgeBuilder){
        internalKnowledgeBase.addPackages(knowledgeBuilder.getKnowledgePackages());
    }

    /**
     * 创建有状态session
     * @param internalKnowledgeBase
     * @return
     */
    public KieSession createKieSession(InternalKnowledgeBase internalKnowledgeBase){
        Supplier kieSessionSupplier = internalKnowledgeBase::newKieSession;
        return kieSessionSupplier.get();
    }

    /**
     * 创建无状态session
     * @param internalKnowledgeBase
     * @return
     */
    public StatelessKieSession createStatelessKieSession(InternalKnowledgeBase internalKnowledgeBase){
        Supplier kieSessionSupplier = internalKnowledgeBase::newStatelessKieSession;
        return kieSessionSupplier.get();
    }

    /**
     * 释放session
     * @param kieSession
     */
    public void disposeKieSession(KieSession kieSession){
        kieSession.dispose();
    }


    /**
     * 销毁Kiession
     * @param kieSession
     */
    public void destroyKiession(KieSession kieSession){
        kieSession.destroy();
    }

KnowledgeBaseLib 类实现方法

private Logger logger = LogManager.getLogger(KnowledgeBaseLib.class);

    private Map internalKnowledgeBaseMap = new ConcurrentHashMap<>();

    private static final String NORULEEXCEPTION = "not found any rule exception";

    @Autowired
    private RuleLoadManager ruleLoadManager;

    @Autowired
    private KnowLedgeBaseManger knowLedgeBaseManger;

    /**
     * 添加知识库到容器
     * @param knowLedgeBaseName
     * @param internalKnowledgeBase
     */
    public void addInternalKnowledgeBase(String knowLedgeBaseName,InternalKnowledgeBase internalKnowledgeBase){
        this.internalKnowledgeBaseMap.put(knowLedgeBaseName,internalKnowledgeBase);
    }

    /**
     * 获得知识库
     * @param knowLedgeBaseName
     * @return
     */
    public InternalKnowledgeBase getInternalKnowledgeBase(String knowLedgeBaseName){
        if(hasInternalKnowledgeBase(knowLedgeBaseName)){
            return this.internalKnowledgeBaseMap.get(knowLedgeBaseName);
        }else{
            List resourceList = ruleLoadManager.loadRule(knowLedgeBaseName);
            if(resourceList.isEmpty()){
                logger.warn(NORULEEXCEPTION);
                throw new KnowLedgeBuilderException(NORULEEXCEPTION);
            }
            knowLedgeBaseManger.createKnowledgeBase(resourceList,knowLedgeBaseName);
            return this.internalKnowledgeBaseMap.get(knowLedgeBaseName);
        }
    }

    /**
     * 检测是否存在知识库
     * @param knowLedgeBaseName
     * @return
     */
    public boolean hasInternalKnowledgeBase(String knowLedgeBaseName){
        return this.internalKnowledgeBaseMap.containsKey(knowLedgeBaseName);
    }

    public Map getAllInternalKnowledgeBase(){
        return this.internalKnowledgeBaseMap;
    }

    public void clearAllInternalKnowledgeBase(){
        this.internalKnowledgeBaseMap.clear();
    }

    public void removeInternalKnowledgeBase(String knowLedgeBaseName){
        this.internalKnowledgeBaseMap.remove(knowLedgeBaseName);
    }

CustomKieBaseConfiguration 类代码

@Component
@ConfigurationProperties(prefix = "droolsconfig")
public class CustomKieBaseConfiguration {

    private Map kieBaseconfiguration = new HashMap<>();

    public Map getKieBaseconfiguration() {
        return kieBaseconfiguration;
    }

    public void setKieBaseconfiguration(Map kieBaseconfiguration) {
        this.kieBaseconfiguration = kieBaseconfiguration;
    }
}

KnowLedgeBaseHandlerProxyConfig 知识库初始化使用

@EnableAspectJAutoProxy
@Configuration
public class KnowLedgeBaseHandlerProxyConfig {

    /**
     * 用于添加知识库
     * @return
     */
    @Bean
    public KnowLedgeBaseHandler knowLedgeBaseHandler(){
        return new KnowLedgeBaseHandler();
    }

}

KnowLedgeBaseHandler 知识库切面,拦截知识库进行存储

/**
 * 用于拦截添加知识库,将知识库进行存储
 */
@Aspect
@Order(2)
@Component
public class KnowLedgeBaseHandler {

    @Autowired
    private KnowledgeBaseLib knowledgeBaseLib;

    @Pointcut("execution(public * com.lmis.manager.knowledge.KnowLedgeBaseMangerImpl.*(..))")
    public void pointCut() {};

    @AfterReturning(value = "pointCut()", returning = "result")
    public void storeInternalKnowledgeBase(JoinPoint joinPoint, InternalKnowledgeBase result) {
        String name = "";
        try{
            name = joinPoint.getArgs()[1].toString();
        }catch(Exception e){
            name = joinPoint.getArgs()[0].toString();
        }
        if(!knowledgeBaseLib.hasInternalKnowledgeBase(name)){
            knowledgeBaseLib.addInternalKnowledgeBase(name,result);
        }
    }

}

DroolsConvertToResource 将数据库查询得数据转换成Drools可认得Resource使用(这个类中包含了很多规则模板类,因为是内存拼接DRL语句,所以肯定会制作很多DRL模板,这里就不放出来了,有需要得可以去下载资源,资源地址:https://download.csdn.net/download/wmq880204/11665278)

/**
 * Created with IntelliJ IDEA.
 * User: Dean Lu
 * Date: 9/18/18
 * Time: 9:52 AM
 * 

* 用于将当前数据结构转换为Resource */ public final class DroolsConvertToResource { private DroolsConvertToResource(){} public static Map> getResourceMap(List ruleCommands) { Map> map = new HashMap<>(); for (RuleCommand ruleCommand : ruleCommands) { configRule(map, ruleCommand); } return map; } public static void configRule(Map> map, RuleCommand ruleCommand) { ruleCommand.getRuleGroupRefList().forEach(ruleGroupRef -> configRuleHead(map, ruleCommand, ruleGroupRef)); } public static void configRuleHead(Map> map, RuleCommand ruleCommand, RuleGroupRef ruleGroupRef) { ruleGroupRef.getRuleHeadList().forEach(ruleHead -> { ByteArrayResource byteArrayResource = null; if (null != ruleHead.getRuleString()) { CEDescrBuilder ceDescrBuilder = configRuleHeaderTemplate(ruleCommand, ruleGroupRef, ruleHead); configRuleInfo(ruleHead, ceDescrBuilder); byteArrayResource = configRuleEndTemplate(ruleHead, ceDescrBuilder); } else { byteArrayResource = configRuleWithRuleString(ruleHead); } configResourceMap(map, byteArrayResource, ruleCommand.getGroupCode()); }); } public static ByteArrayResource configRuleWithRuleString(RuleHead ruleHead) { ByteArrayResource byteArrayResource; StringTemplate stringTemplate = new StringTemplate(); byteArrayResource = stringTemplate.setStringTemplate(ruleHead.getRuleString()); return byteArrayResource; } public static ByteArrayResource configRuleEndTemplate(RuleHead ruleHead, CEDescrBuilder ceDescrBuilder) { ByteArrayResource byteArrayResource; StringBuilder op = configRuleOp(ruleHead); EndTemplate endTemplate = new EndTemplate(ceDescrBuilder, op.toString()); byteArrayResource = endTemplate.returnRuleString(); return byteArrayResource; } public static CEDescrBuilder configRuleHeaderTemplate(RuleCommand ruleCommand, RuleGroupRef ruleGroupRef, RuleHead ruleHead) { Map ruleGlobals = configRuleGlobal(ruleHead); HanderTemplate handerTemplate = new HanderTemplate(ruleHead.getPackageName(), ruleHead.getRuleName(), ruleGlobals, ruleCommand.getGroupCode(), String.valueOf(ruleGroupRef.getOrderNo())); return handerTemplate.getCeDescrBuilder(); } public static StringBuilder configRuleOp(RuleHead ruleHead) { StringBuilder op = new StringBuilder(); ruleHead.getRuleOpList().forEach(ruleOp -> { if (BaseOperationTemplate.SIMPLEOPERATIONTYPE.equals(ruleOp.getType())) { SimpleOperationTemplate simpleOperationTemplate = new SimpleOperationTemplate(); op.append(simpleOperationTemplate.opTemplate(ruleOp.getObjName(), ruleOp.getAttribute(), ruleOp.getValue())); } if (BaseOperationTemplate.STRINGYPE.equals(ruleOp.getType())) { StringOperationTemplate stringOperationTemplate = new StringOperationTemplate(); op.append(stringOperationTemplate.opTemplate(null, null, ruleOp.getValue())); } }); return op; } public static void configRuleInfo(RuleHead ruleHead, CEDescrBuilder ceDescrBuilder) { List ruleInfos = ruleHead.getRuleInfoList(); for (RuleInfo ruleInfo : ruleInfos) { configRuleInfo(ceDescrBuilder, ruleInfo); } } public static Map configRuleGlobal(RuleHead ruleHead) { Map ruleGlobals = new HashMap<>(); ruleHead.getRuleGlobalList().forEach(ruleGlobal -> ruleGlobals.put(ruleGlobal.getGlobalName(), ruleGlobal.getGlobalType())); return ruleGlobals; } public static void configResourceMap(Map> map, ByteArrayResource byteArrayResource, String ruleGroupCode) { List list = map.get(ruleGroupCode); if (null == list) { list = new ArrayList<>(); list.add(byteArrayResource); map.put(ruleGroupCode, list); } else { list.add(byteArrayResource); } } public static void configRuleInfo(CEDescrBuilder ceDescrBuilder, RuleInfo ruleInfo) { //各种主模板的判断加入 List conditionList = buildCondition(ruleInfo); if (SimpleRuleTemplate.TYPE.equals(ruleInfo.getType())) { configSimpleRuleTemplate(ceDescrBuilder, ruleInfo, conditionList); } else if (NestingCountTemplate.TYPE.equals(ruleInfo.getType())) { configNestingCountTemplate(ceDescrBuilder, ruleInfo, conditionList); } else if (NestingExistsTemplate.TYPE.equals(ruleInfo.getType())) { configNestingExistsTemplate(ceDescrBuilder, ruleInfo, conditionList); } else if (NestingCalculationTemplate.TYPE.equals(ruleInfo.getType())) { configNestingCalculationTemplate(ceDescrBuilder, ruleInfo, conditionList); } else if (NestingAllTemplate.TYPE.equals(ruleInfo.getType())) { configNestingAllTemplate(ceDescrBuilder, ruleInfo, conditionList); } else if (NestingAccumulateTemplate.TYPE.equals(ruleInfo.getType())) { configNestingAccumulateTemplate(ceDescrBuilder, ruleInfo, conditionList); } else if (NestingMatchesTemplate.TYPE.equals(ruleInfo.getType())) { configNestingMatchesTemplate(ceDescrBuilder, ruleInfo, conditionList); } } public static void configNestingAccumulateTemplate(CEDescrBuilder ceDescrBuilder, RuleInfo ruleInfo, List conditionList) { NestingAccumulateTemplate nestingAccumulateTemplate = new NestingAccumulateTemplate(); nestingAccumulateTemplate.setObjName(ruleInfo.getObj()); nestingAccumulateTemplate.setAttribute(ruleInfo.getAttribute()); nestingAccumulateTemplate.setConditionList(conditionListFilter(conditionList, BaseConditionTemplate.CONDITIONPARAM)); nestingAccumulateTemplate.setParentName(ruleInfo.getParent()); nestingAccumulateTemplate.setDescrBuilder(ceDescrBuilder); nestingAccumulateTemplate.setNestingAccumulateTemplate(); } public static void configNestingCalculationTemplate(CEDescrBuilder ceDescrBuilder, RuleInfo ruleInfo, List conditionList) { NestingCalculationTemplate nestingCalculationTemplate = new NestingCalculationTemplate(ceDescrBuilder); nestingCalculationTemplate.setObjName(ruleInfo.getObj()); nestingCalculationTemplate.setAttribute(ruleInfo.getAttribute()); nestingCalculationTemplate.setConditionList(conditionListFilter(conditionList, BaseConditionTemplate.CONDITIONPARAM)); nestingCalculationTemplate.setCalConditionList(conditionListFilter(conditionList, BaseConditionTemplate.CALPARAM)); nestingCalculationTemplate.setParentName(ruleInfo.getParent()); nestingCalculationTemplate.setCalculation(ruleInfo.getCalculation()); nestingCalculationTemplate.setDescrBuilder(ceDescrBuilder); nestingCalculationTemplate.setNestingCalculationTemplate(); } public static void configNestingAllTemplate(CEDescrBuilder ceDescrBuilder, RuleInfo ruleInfo, List conditionList) { NestingAllTemplate nestingAllTemplate = new NestingAllTemplate(ceDescrBuilder); nestingAllTemplate.setObjName(ruleInfo.getObj()); nestingAllTemplate.setAttribute(ruleInfo.getAttribute()); nestingAllTemplate.setConditionList(conditionListFilter(conditionList, BaseConditionTemplate.CONDITIONPARAM)); nestingAllTemplate.setParentName(ruleInfo.getParent()); nestingAllTemplate.setDescrBuilder(ceDescrBuilder); nestingAllTemplate.setNestingAllTemplate(); } public static void configNestingExistsTemplate(CEDescrBuilder ceDescrBuilder, RuleInfo ruleInfo, List conditionList) { NestingExistsTemplate nestingExistsTemplate = new NestingExistsTemplate(); nestingExistsTemplate.setObjName(ruleInfo.getObj()); nestingExistsTemplate.setAttribute(ruleInfo.getAttribute()); nestingExistsTemplate.setConditionList(conditionListFilter(conditionList, BaseConditionTemplate.CONDITIONPARAM)); nestingExistsTemplate.setParentName(ruleInfo.getParent()); nestingExistsTemplate.setDescrBuilder(ceDescrBuilder); nestingExistsTemplate.setNestingExistsTemplate(); } public static void configNestingMatchesTemplate(CEDescrBuilder ceDescrBuilder, RuleInfo ruleInfo, List conditionList) { NestingMatchesTemplate nestingMatchesTemplate = new NestingMatchesTemplate(); nestingMatchesTemplate.setObjName(ruleInfo.getObj()); nestingMatchesTemplate.setAttribute(ruleInfo.getAttribute()); nestingMatchesTemplate.setConditionList(conditionListFilter(conditionList, BaseConditionTemplate.CONDITIONPARAM)); nestingMatchesTemplate.setParentName(ruleInfo.getParent()); nestingMatchesTemplate.setDescrBuilder(ceDescrBuilder); nestingMatchesTemplate.setNestingExistsTemplate(); } public static void configNestingCountTemplate(CEDescrBuilder ceDescrBuilder, RuleInfo ruleInfo, List conditionList) { NestingCountTemplate nestingCountTemplate = new NestingCountTemplate(); nestingCountTemplate.setObjName(ruleInfo.getObj()); nestingCountTemplate.setAttribute(ruleInfo.getAttribute()); nestingCountTemplate.setConditionList(conditionListFilter(conditionList, BaseConditionTemplate.CONDITIONPARAM)); nestingCountTemplate.setCalConditionList(conditionListFilter(conditionList, BaseConditionTemplate.CALPARAM)); nestingCountTemplate.setParentName(ruleInfo.getParent()); nestingCountTemplate.setDescrBuilder(ceDescrBuilder); nestingCountTemplate.setCalculation(ruleInfo.getCalculation()); nestingCountTemplate.setNestingCountTemplate(); } public static void configSimpleRuleTemplate(CEDescrBuilder ceDescrBuilder, RuleInfo ruleInfo, List conditionList) { SimpleRuleTemplate simpleRuleTemplate = new SimpleRuleTemplate(); simpleRuleTemplate.setRuleInfo(ruleInfo); simpleRuleTemplate.setConditionList(conditionListFilter(conditionList, BaseConditionTemplate.CONDITIONPARAM)); simpleRuleTemplate.setDescrBuilder(ceDescrBuilder); simpleRuleTemplate.setSimpleRuleTemplate(); } public static List conditionListFilter(List baseConditionTemplates, String filter) { return baseConditionTemplates.stream().filter(baseConditionTemplate -> filter.equals(baseConditionTemplate.getParamType())).collect(Collectors.toList()); } /** * @author QIQI * @Description: 子模板的判断加入 * @params [ruleInfo] * @return java.util.List * @throws * @date 2019-06-20 09:56 */ public static List buildCondition(RuleInfo ruleInfo) { List conditionList = new ArrayList<>(); ruleInfo.getRuleConditions().forEach(ruleCondition -> { if (ruleCondition.getType().equals(BaseConditionTemplate.CONTAINSTYPE)) { ContainsConditionTemplate containsConditionTemplate = new ContainsConditionTemplate(ruleCondition.getConditionKey(), ruleCondition.getOp(), ruleCondition.getConditionValue(), ruleCondition.getAssociationType()); containsConditionTemplate.setParamType(ruleCondition.getParamType()); conditionList.add(containsConditionTemplate); } else if (ruleCondition.getType().equals(BaseConditionTemplate.EQUALTYPE)) { EqualConditionTemplate equalConditionTemplate = new EqualConditionTemplate(ruleCondition.getConditionKey(), ruleCondition.getOp(), ruleCondition.getConditionValue(), ruleCondition.getAssociationType()); equalConditionTemplate.setParamType(ruleCondition.getParamType()); conditionList.add(equalConditionTemplate); } else if (ruleCondition.getType().equals(BaseConditionTemplate.MEMBEROFTYPE)) { MemberOfConditionTemplate memberOfConditionTemplate = new MemberOfConditionTemplate(ruleCondition.getConditionKey(), ruleCondition.getOp(), ruleCondition.getConditionValue(), ruleCondition.getAssociationType()); memberOfConditionTemplate.setParamType(ruleCondition.getParamType()); conditionList.add(memberOfConditionTemplate); } else if (ruleCondition.getType().equals(BaseConditionTemplate.RANGETYPE)) { RangeConditionTemplate rangeConditionTemplate = new RangeConditionTemplate(ruleCondition.getConditionKey(), ruleCondition.getOp(), ruleCondition.getConditionValue(), ruleCondition.getAssociationType()); rangeConditionTemplate.setParamType(ruleCondition.getParamType()); conditionList.add(rangeConditionTemplate); } else if (ruleCondition.getType().equals(BaseConditionTemplate.MATCHESTYPE)) { MatchesConditionTemplate matchesConditionTemplate = new MatchesConditionTemplate(ruleCondition.getConditionKey(), ruleCondition.getOp(), ruleCondition.getConditionValue(), ruleCondition.getAssociationType()); matchesConditionTemplate.setParamType(ruleCondition.getParamType()); conditionList.add(matchesConditionTemplate); } else if (ruleCondition.getType().equals(BaseConditionTemplate.ACCUMULATETYPE)) { AccumulateConditionTemplate accumulateConditionTemplate = new AccumulateConditionTemplate(ruleCondition.getConditionKey(), ruleCondition.getOp(), ruleCondition.getConditionValue(), ruleCondition.getAssociationType()); accumulateConditionTemplate.setParamType(ruleCondition.getParamType()); conditionList.add(accumulateConditionTemplate); } }); return conditionList; } public static boolean checkRuleId(CEDescrBuilder ceDescrBuilder, String objName) { boolean flag = true; List patternDescrList = ceDescrBuilder.getDescr().getAllPatternDescr(); if (patternDescrList.isEmpty()) { return flag; } for (PatternDescr patternDescr : patternDescrList) { if (objName.equals(patternDescr.getIdentifier())) { flag = false; } } return flag; } }

 

QueryManagerImpl 实现类(这个类主要用作规则数据匹配打标使用,分为无状态session和有状态session,差异就不详细介绍了,小伙伴可以自行百度)

@Service
public class QueryManagerImpl implements QueryManager {
    private static Logger log = LogManager.getLogger("QueryManagerImpl");
    @Autowired
    private KnowledgeBaseLib knowledgeBaseLib;

    /**
     * 使用有状态SESSION进行请求
     *
     * @param knowLedgeBaseName
     * @param data
     * @return T
     */
    @Override
    public T queryCommandWithKieSessionAsList(String knowLedgeBaseName, V data) {
        Function internalKnowledgeBaseFunction = knowledgeBaseLib::getInternalKnowledgeBase;
        Supplier kieSessionSupplier = internalKnowledgeBaseFunction.apply(knowLedgeBaseName)::newKieSession;
        KieSession kieSession = kieSessionSupplier.get();
        List resultList = new ArrayList();
        if (data instanceof List) {
            List dataList = (List) data;
            //kieSession.setGlobal(FinalArgs.DROOLS_GLOBAL_TYPE, resultList);
            dataList.forEach(dataInfo->{
                kieSession.insert(dataInfo);
                kieSession.getAgenda().getAgendaGroup( knowLedgeBaseName ).setFocus();
                kieSession.fireAllRules();
            });
        }
        kieSession.dispose();
        return (T) resultList;
    }

    /**
    * @author QIQI
    * @Description: 使用无状态SESSION进行请求
    * @params [knowLedgeBaseName, dataTmp]
    * @return T
    * @throws 
    * @date 2019-06-17 14:17 
    */
    @Override
    public T queryCommandWithStatelessKieSessionAsList(String knowLedgeBaseName, V data) {
        Function internalKnowledgeBaseFunction = knowledgeBaseLib::getInternalKnowledgeBase;
        Supplier statelessKieSessionSupplier = internalKnowledgeBaseFunction.apply(knowLedgeBaseName)::newStatelessKieSession;
        StatelessKieSession statelessKieSession = statelessKieSessionSupplier.get();
        if (data instanceof List) {
            ((List) data).parallelStream().forEach(datainfo->statelessKieSession.execute(datainfo));
        }
        return (T) data;
    }

    /**
     * 使用有状态SESSION进行请求,返回具体请求规则的结果
     *
     * @param knowLedgeBaseName
     * @param ruleMap
     * @param data
     * @return T
     */
    @Override
    public T queryCommandWithKieSession(String knowLedgeBaseName, Map>> ruleMap, V data) {
        Function internalKnowledgeBaseFunction = knowledgeBaseLib::getInternalKnowledgeBase;
        Supplier kieSessionSupplier = internalKnowledgeBaseFunction.apply(knowLedgeBaseName)::newKieSession;
        KieSession kieSession = kieSessionSupplier.get();
        List list = new ArrayList<>();
        if (data instanceof List) {
            List dataList = (List) data;
            int dataSize = dataList.size();
            for (int i = 0; i < dataSize; i++) {
                list.add(CommandFactory.newInsert(dataList.get(i)));
            }
            list.add(CommandFactory.newFireAllRules());
            list.add(CommandFactory.newGetObjects());
            ruleMap.forEach((ruleName, queryNames) -> queryNames.forEach((queryName, args) -> list.add(CommandFactory.newQuery(ruleName, queryName, args.toArray()))));
        }
        return (T) kieSession.execute(CommandFactory.newBatchExecution(list));
    }

    /**
     * 使用无状态SESSION进行请求,返回具体请求规则的结果
     *
     * @param knowLedgeBaseName
     * @param ruleMap
     * @param data
     * @return T
     */
    @Override
    public T queryCommandWithStatelessKieSession(String knowLedgeBaseName, Map>> ruleMap, V data) {
        Function internalKnowledgeBaseFunction = knowledgeBaseLib::getInternalKnowledgeBase;
        Supplier statelessKieSessionSupplier = internalKnowledgeBaseFunction.apply(knowLedgeBaseName)::newStatelessKieSession;
        StatelessKieSession statelessKieSession = statelessKieSessionSupplier.get();
        List list = new ArrayList<>();
        if (data instanceof List) {
            List dataList = (List) data;
            int dataSize = dataList.size();
            for (int i = 0; i < dataSize; i++) {
                list.add(CommandFactory.newInsert(dataList.get(i)));
            }
            list.add(CommandFactory.newFireAllRules());
            list.add(CommandFactory.newGetObjects());
            ruleMap.forEach((ruleName, queryNames) -> queryNames.forEach((queryName, args) -> list.add(CommandFactory.newQuery(ruleName, queryName, args.toArray()))));
        }
        return (T) statelessKieSession.execute(CommandFactory.newBatchExecution(list));
    }
}

 

通过上面得一系列代码,已经完成了流程图中得功能,当然对于规则保存等Action接口实现需要自己完成,细心得小伙伴会发现上面得流程图中有个很严重得问题那就是如果规则应用多实例部署得话就会出现问题,因为规则是在单个实例得工作内存中,这个也是离线模式得重要问题,不过作者通过简单得乐观锁解决了这个问题,没有选择去接入Kie因为改动成本太大了,并且我们公司对于规则也没有更重得需求迭代了,乐观锁流程图如下

Drools规则引擎接入详解_第2张图片

你可能感兴趣的:(编程技术,架构设计,Drools)