使用数据库存储drools规则

部分内容参考此文章

config
package com.kittlen.cloud.config;

import com.kittlen.cloud.entities.DroolsInfo;
import com.kittlen.cloud.service.DroolsInfoService;
import lombok.extern.slf4j.Slf4j;
import org.drools.compiler.kie.builder.impl.KieFileSystemImpl;
import org.drools.core.io.impl.InputStreamResource;
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.KieRepository;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.internal.io.ResourceFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.util.List;

/**
 * @author kittlen
 * @version 1.0
 * @date 2021/9/3 0003
 */
@Configuration
@Slf4j
public class KieConfig {

    @Autowired
    DroolsInfoService droolsInfoService;

    protected KieFileSystem kieFileSystem() {
        KieFileSystem kieFileSystem = getKieServices().newKieFileSystem();
        List<DroolsInfo> all = droolsInfoService.getAll();
        all.forEach(a -> {
            //该目录文件为虚拟目录,不需要实际存在,**后缀一定要带.drl**
            String path="src/main/resources/rules/" + a.getId() + ".drl";
            kieFileSystem.write(path, a.getContent().getBytes());
        });
        return kieFileSystem;
    }

    public KieContainer kieContainer() {
        final KieRepository kieRepository = getKieServices().getRepository();
        kieRepository.addKieModule(() -> kieRepository.getDefaultReleaseId());
        KieBuilder kieBuilder = getKieServices().newKieBuilder(kieFileSystem());
        kieBuilder.buildAll();
        return getKieServices().newKieContainer(kieRepository.getDefaultReleaseId());
    }

    private KieServices getKieServices() {
        return KieServices.Factory.get();
    }


}

package com.kittlen.cloud.config;

import org.kie.api.KieBase;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;

/**
 * @author kittlen
 * @version 1.0
 * @date 2021/9/22 0022
 */
@Configuration
public class KieBeanConfig {

    @Resource
    KieConfig kieConfig;

    @Bean
    public MyKieContext myKieContext() {
        KieContainer kieContainer = kieConfig.kieContainer();
        return new MyKieContext(kieContainer);
    }
}

bean
package com.kittlen.cloud.config;

import lombok.extern.slf4j.Slf4j;
import myException.KTNException;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.FactHandle;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author kittlen
 * @version 1.0
 * @date 2021/9/7 0007
 */
@Slf4j
public class MyKieContext {
    private KieSession kieSession;

    private KieBase kieBase;

    private KieContainer kieContainer;

    private List<FactHandle> factHandleRecord = new ArrayList<>();

    public MyKieContext(KieSession kieSession, KieBase kieBase, KieContainer kieContainer) {
        this.kieSession = kieSession;
        this.kieBase = kieBase;
        this.kieContainer = kieContainer;
    }

    public MyKieContext(KieContainer kieContainer) {
        if (kieContainer != null) {
            this.kieContainer = kieContainer;
            this.kieSession = kieContainer.newKieSession();
            this.kieBase = kieContainer.getKieBase();
        }
    }

    public KieSession getKieSession() {
        return kieSession;
    }

    private void setKieSession(KieSession kieSession) {
        this.kieSession = kieSession;
    }

    public KieBase getKieBase() {
        return kieBase;
    }

    private void setKieBase(KieBase kieBase) {
        this.kieBase = kieBase;
    }

    public KieContainer getKieContainer() {
        return kieContainer;
    }

    private void setKieContainer(KieContainer kieContainer) {
        this.kieContainer = kieContainer;
    }

    public FactHandle insert(Object o) {
        FactHandle insert = this.kieSession.insert(o);
        factHandleRecord.add(insert);
        return insert;
    }

    public void delete(FactHandle factHandle) {
        try {
            this.kieSession.delete(factHandle);
            factHandleRecord.remove(factHandle);
        } catch (Exception e) {
            log.error("移除FactHandle时出现异常,异常为:{}", e.getMessage());
        }
    }

    public void clean() {
        if (this.kieSession != null) {
            factHandleRecord.forEach(f -> {
                try {
                    this.kieSession.delete(f);
                } catch (Exception e) {
                    log.error("移除FactHandle时出现异常,异常为:{}", e.getMessage());
                }
            });
            factHandleRecord.clear();
        }
    }

    /**
     * 匹配规则
     *
     * @return
     */
    public int fireAllRules() {
        return this.kieSession.fireAllRules();
    }

    /**
     * 更新规则
     *
     * @param kieSession
     * @param kieBase
     * @param kieContainer
     */
    public void update(KieSession kieSession, KieBase kieBase, KieContainer kieContainer) {
        dispose();
        this.kieSession = kieSession;
        this.kieBase = kieBase;
        this.kieContainer = kieContainer;
    }

    /**
     * 更新规则
     *
     * @param kieContainer
     */
    public void update(KieContainer kieContainer) {
        if (kieContainer == null) {
            throw new KTNException("kieContainer 不能为空");
        }
        update(kieContainer.newKieSession(), kieContainer.getKieBase(), kieContainer);
    }

    /**
     * 清除规则
     */
    public void dispose() {
        if (this.kieSession != null) {
            this.clean();
            this.kieSession.dispose();
        }
        if (this.kieContainer != null) {
            this.kieContainer.dispose();
        }
    }

    public boolean isNullDrools() {
        return kieBase == null;
    }

    /**
     * 获取当前规则中所有的包和方法
     *
     * @return key 包名,value 方法名
     */
    public Map<String, List<String>> droolsBaseInfo() {
        Map<String, List<String>> map = new HashMap<>();
        if (isNullDrools()) {
            return map;
        }
        this.kieBase.getKiePackages().forEach(c -> {
            String packageName = c.getName();
            List<String> list = new ArrayList<>();
            c.getRules().forEach(r -> list.add(r.getName()));
            if (!list.isEmpty()) {
                map.put(packageName, list);
            }
        });
        return map;
    }
}

注意insert时产生的FactHandle 不会被gc释放,在规则使用完毕时需释放规则,可通过delete(FactHandle factHandle)||clean()释放

entity
package com.kittlen.cloud.entities;

import lombok.Data;

import java.io.Serializable;

/**
 * @author kittlen
 * @version 1.0
 * @date 2021/9/3 0003
 */
@Data
public class DroolsInfo implements Serializable {

    private String id;

    private String content;
}

重新加载规则
package com.kittlen.cloud.controller;

import com.kittlen.cloud.config.KieConfig;
import com.kittlen.cloud.config.MyKieContext;
import com.kittlen.cloud.service.DroolsInfoService;
import entities.Result;
import lombok.extern.slf4j.Slf4j;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 重新加载规则
 *
 * @author kittlen
 * @version 1.0
 * @date 2021/9/1 0001
 */
@Slf4j
@RestController
@RequestMapping("/kieReloading")
public class KieReloadingController {

    @Autowired
    MyKieContext myKieContext;

    @Autowired
    DroolsInfoService droolsInfoService;

    @Autowired
    KieConfig kieConfig;

    /**
     * 重新加载规则
     *
     * @return
     */
    @RequestMapping("/reloading")
    public Result reloading() {
        try {
            KieContainer kieContainer = kieConfig.kieContainer();
            myKieContext.update(kieContainer);
            return Result.ok();
        } catch (Exception e) {
            log.error("重载kie异常,异常为:{}", e.getMessage());
            return Result.error("重新加载规则失败");
        }
    }
}


规则添加分类,不同的分类执行不同规则

在原基础上添加MyKieContexts

bean
package com.kittlen.cloud.config;

import org.kie.api.runtime.rule.FactHandle;

import java.io.Serializable;
import java.util.Map;
import java.util.Objects;

/**
 * @author kittlen
 * @version 1.0
 * @date 2021/9/7 0007
 */
public class MyKieContexts implements Serializable {
    private Map<String, MyKieContext> contexts;

    public MyKieContexts(Map<String, MyKieContext> contexts) {
        this.contexts = contexts;
    }

    public MyKieContexts() {
    }

    public Map<String, MyKieContext> getContexts() {
        return contexts;
    }

    public void setContexts(Map<String, MyKieContext> contexts) {
        this.contexts = contexts;
    }

    public MyKieContext get(String key) {
        return this.contexts.get(key);
    }

    public FactHandle insert(String key, Object o) {
        MyKieContext myKieContext = get(key);
        return myKieContext == null ? null : myKieContext.insert(o);
    }

    public int fireAllRules(String key) {
        MyKieContext myKieContext = get(key);
        return myKieContext == null ? 0 : myKieContext.fireAllRules();
    }

    public void cover(String key, MyKieContext myKieContext) {
        MyKieContext oldMyKieContext = this.contexts.get(key);
        if (oldMyKieContext != null) {
            oldMyKieContext.dispose();
        }
        this.contexts.put(key, myKieContext);
    }
}

config
package com.kittlen.cloud.config;

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.KieRepository;
import org.kie.api.internal.utils.ServiceRegistryImpl;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @author kittlen
 * @version 1.0
 * @date 2021/9/22 0022
 */

@Component
public class KieConfig {
    private KieServices kieServices;

    public KieConfig() {
        kieServices = KieServices.Factory.get();
    }

    protected KieFileSystem kieFileSystem(List<String> drools) {
        KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
        for (int i = 0; i < drools.size(); i++) {
            //该目录文件为虚拟目录,不需要实际存在,**后缀一定要带.drl**
            String path = "src/main/resources/rules/" + i + ".drl";
            kieFileSystem.write(path, drools.get(i).getBytes());
        }
        return kieFileSystem;
    }

    protected KieContainer kieContainer(List<String> drools) {
        final KieRepository kieRepository = kieServices.getRepository();
        kieRepository.addKieModule(() -> kieRepository.getDefaultReleaseId());
        KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem(drools));
        kieBuilder.buildAll();
        return kieServices.newKieContainer(kieRepository.getDefaultReleaseId());
    }

    public MyKieContext myKieContext(List<String> drools) {
        KieContainer kieContainer = kieContainer(drools);
        return new MyKieContext(kieContainer);
    }
}

package com.kittlen.cloud.config;

import com.kittlen.cloud.entities.DroolsInfo;
import com.kittlen.cloud.service.DroolsInfoService;
import lombok.extern.slf4j.Slf4j;
import myException.KTNException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author kittlen
 * @version 1.0
 * @date 2021/9/3 0003
 */
@Slf4j
@Configuration
public class KieBeanConfig {

    @Autowired
    DroolsInfoService droolsInfoService;

    @Resource
    KieConfig KieConfig;

    @Bean
    public MyKieContexts myKieContexts() {
        try {
            List<DroolsInfo> allDrools = droolsInfoService.getAll();
            Map<String, List<String>> mapDrools = new HashMap<>();
            allDrools.forEach(p -> {
                List<String> drools = mapDrools.get(p.getType());
                if (drools == null) {
                    List<String> list = new ArrayList<>();
                    list.add(p.getContent());
                    mapDrools.put(p.getType(), list);
                } else {
                    drools.add(p.getContent());
                }
            });
            Map<String, MyKieContext> map = new HashMap<>();
            for (String key : mapDrools.keySet()) {
                log.info("添加type为:{}的规则",key);
                map.put(key, KieConfig.myKieContext(mapDrools.get(key)));
            }
            return new MyKieContexts(map);
        } catch (Exception e) {
            log.error("初始化MyKieContexts时异常,异常为:{}", e.getMessage());
            throw new KTNException(e);
        }
    }
}
重新加载规则
package com.kittlen.cloud.controller;

import com.kittlen.cloud.config.MyKieContexts;
import com.kittlen.cloud.config.KieConfig;
import com.kittlen.cloud.entities.DroolsInfo;
import com.kittlen.cloud.service.DroolsInfoService;
import entities.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

/**
 * 重新加载规则
 *
 * @author kittlen
 * @version 1.0
 * @date 2021/9/1 0001
 */
@Slf4j
@RestController
@RequestMapping("/kieReloading")
public class KieReloadingController {

    @Autowired
    MyKieContexts myKieContexts;

    @Autowired
    DroolsInfoService droolsInfoService;

    @Autowired
    KieConfig KieConfig;

    /**
     * 重新加载规则
     *
     * @return
     */
    @RequestMapping("/reloading")
    public Result reloading(String type) {
        try {
            List<DroolsInfo> byType = droolsInfoService.getByType(type);
            List<String> drools = new ArrayList<>();
            byType.forEach(d -> drools.add(d.getContent()));
            myKieContexts.cover(type, KieConfig.myKieContext(drools));
            return Result.ok();
        } catch (Exception e) {
            log.error("重载kie异常,异常为:{}", e.getMessage());
            return Result.error("重新加载规则失败");
        }
    }
}
entity
package com.kittlen.cloud.entities;

import lombok.Data;

import java.io.Serializable;

/**
 * @author kittlen
 * @version 1.0
 * @date 2021/9/3 0003
 */
@Data
public class DroolsInfo implements Serializable {

    private String id;

    private String content;

    private String type;
}

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐