• Drools规则引擎讲解


    学前

    有这样一串代码,代表着积分策略业务,计算额外积分金额:

    1. 100 以下, 不加分;
    2. 100-500 加100分;
    3. 500-1000 加500分;
    4. 1000 以上 加1000分;
    public class JavaScoreExample {
          
        public static void main(String[] args) throws Exception {  
              
            List<Order> orderList = getInitData();
            for (int i=0; i<orderList.size(); i++){  
                Order order = orderList.get(i);  
                if (order.getAmout() <= 100){  
                    order.setScore(0);  
                    addScore(order);  
                }else if(order.getAmout() > 100 && order.getAmout() <= 500){  
                    order.setScore(100);  
                    addScore(order);  
                }else if(order.getAmout() > 500 && order.getAmout() <= 1000){  
                    order.setScore(500);  
                    addScore(order);  
                }else{  
                    order.setScore(1000);  
                    addScore(order);  
                }  
            }  
              
        }  
          
        private static void addScore(Order o){  
            System.out.println("用户" + o.getUser().getName() + "享受额外增加积分: " + o.getScore());  
        }  
          
        private static List<Order> getInitData() throws Exception {  
            List<Order> orderList = new ArrayList<Order>();
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            {
                Order order = new Order();  
                order.setAmout(80);  
                order.setBookingDate(df.parse("2015-07-01"));  
                User user = new User();
                user.setLevel(1);  
                user.setName("Name1");  
                order.setUser(user);  
                orderList.add(order);  
            }
            {
                Order order = new Order();  
                order.setAmout(200);  
                order.setBookingDate(df.parse("2015-07-02"));  
                User user = new User();
                user.setLevel(2);  
                user.setName("Name2");  
                order.setUser(user);  
                orderList.add(order);  
            }  
           
            return orderList;  
        }  
    }  
    

    综上,如果这时由于市场需求变化,又要调整规则时候,则又要进行业务层面的代码修改、部署,十分麻烦

    那该怎么办呢?

    规则引擎

    作用

    我们可以把决策规则从应用程序中分离出来,将对系统提供很大的便利

    在这里插入图片描述

    优势

    1. 简化系统架构,优化应用
    2. 提高系统的可维护性和维护成本
    3. 减少编写“硬代码”业务规则的成本和风险

    Drools

    Drools是一个基于java的规则引擎,它是开源的,可以将复杂多变的规则从硬编码中解放出来,以规则脚本的形式存放在文件中,使得规则的变更不需要修正代码重启机器就可以立即在线上环境生效。具有易于访问企业策略、易于调整以及易于管理的特点,作为开源业务规则引擎,符合业内标准,速度快、效率高。

    项目搭建流程

    以下项目基于Springboot搭建

    在这里插入图片描述

    项目结构

    项目存放:image/drool.rar

    在这里插入图片描述

    pom.xml
    
    <dependency>
        <groupId>org.droolsgroupId>
        <artifactId>drools-coreartifactId>
        <version>7.6.0.Finalversion>
    dependency>
    <dependency>
        <groupId>org.droolsgroupId>
        <artifactId>drools-compilerartifactId>
        <version>7.6.0.Finalversion>
    dependency>
    <dependency>
        <groupId>org.droolsgroupId>
        <artifactId>drools-templatesartifactId>
        <version>7.6.0.Finalversion>
    dependency>
    <dependency>
        <groupId>org.kiegroupId>
        <artifactId>kie-apiartifactId>
        <version>7.6.0.Finalversion>
    dependency>
    <dependency>
        <groupId>org.kiegroupId>
        <artifactId>kie-springartifactId>
        <version>7.6.0.Finalversion>
    dependency>
    
    配置文件
    @Configuration
    public class RuleEngineConfig {
        private static final Logger LOGGER = LoggerFactory.getLogger(RuleEngineConfig.class) ;
        private static final String RULES_PATH = "droolRule/";
        private final KieServices kieServices = KieServices.Factory.get();
        @Bean
        public KieFileSystem kieFileSystem() throws IOException {
            KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
            ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
            Resource[] files = resourcePatternResolver.getResources("classpath*:" + RULES_PATH + "*.*");
            String path = null;
            for (Resource file : files) {
                path = RULES_PATH + file.getFilename();
                LOGGER.info("path="+path);
                kieFileSystem.write(ResourceFactory.newClassPathResource(path, "UTF-8"));
            }
            return kieFileSystem;
        }
        @Bean
        public KieContainer kieContainer() throws IOException {
            KieRepository kieRepository = kieServices.getRepository();
            kieRepository.addKieModule(kieRepository::getDefaultReleaseId);
            KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem());
            kieBuilder.buildAll();
            return kieServices.newKieContainer(kieRepository.getDefaultReleaseId());
        }
        @Bean
        public KieBase kieBase() throws IOException {
            return kieContainer().getKieBase();
        }
        @Bean
        public KieSession kieSession() throws IOException {
            return kieContainer().newKieSession();
        }
        @Bean
        public KModuleBeanFactoryPostProcessor kiePostProcessor() {
            return new KModuleBeanFactoryPostProcessor();
        }
    }
    
    规则文件
    语法说明
    1. 文件格式:可以 .drl、xml文件,也可以Java代码块硬编码
    2. package:规则文件中,package是必须定义的,必须放在规则文件第一行
    3. import:规则文件使用到的外部变量,可以是一个类,也可以是类中的可访问的静态方法
    4. rule:定义一个规则。paramcheck1规则名。规则通常包含三个部分:属性、条件、结果
    规则说明
    1. salience 的值越大,越优先执行
    2. 规则流程:如果paramId不为null,参数标识是+号,执行添加规则,-号,执行移除规则操作
    dialect  "java"
    rule "paramcheck1"
        salience 99
        when queryParam : QueryParam(paramId != null && paramSign.equals("+"))
            resultParam : RuleResult()
        then
            final Logger LOGGER = LoggerFactory.getLogger("param-check-one 规则引擎") ;
            LOGGER.info("参数:getParamId="+queryParam.getParamId()+";getParamSign="+queryParam.getParamSign());
            RuleEngineServiceImpl ruleEngineService = new RuleEngineServiceImpl() ;
            ruleEngineService.executeAddRule(queryParam);
            resultParam.setPostCodeResult(true);
    end
    
    dialect  "java"
    rule "paramcheck2"
        salience 88
        when queryParam : QueryParam(paramId != null && paramSign.equals("-"))
            resultParam : RuleResult()
        then
            final Logger LOGGER = LoggerFactory.getLogger("param-check-two 规则引擎") ;
            LOGGER.info("参数:getParamId="+queryParam.getParamId()+";getParamSign="+queryParam.getParamSign());
            RuleEngineServiceImpl ruleEngineService = new RuleEngineServiceImpl() ;
            ruleEngineService.executeRemoveRule(queryParam);
            resultParam.setPostCodeResult(true);
    end
    
    规则执行代码
    @Service
    public class RuleEngineServiceImpl implements RuleEngineService {
        private static final Logger LOGGER = LoggerFactory.getLogger(RuleEngineServiceImpl.class) ;
        @Override
        public void executeAddRule(QueryParam param) {
            LOGGER.info("参数数据:"+param.getParamId()+";"+param.getParamSign());
            ParamInfo paramInfo = new ParamInfo() ;
            paramInfo.setId(param.getParamId());
            paramInfo.setParamSign(param.getParamSign());
            paramInfo.setCreateTime(new Date());
            paramInfo.setUpdateTime(new Date());
            ParamInfoService paramInfoService = (ParamInfoService)SpringContextUtil.getBean("paramInfoService") ;
            paramInfoService.insertParam(paramInfo);
        }
        @Override
        public void executeRemoveRule(QueryParam param) {
            LOGGER.info("参数数据:"+param.getParamId()+";"+param.getParamSign());
            ParamInfoService paramInfoService = (ParamInfoService)SpringContextUtil.getBean("paramInfoService") ;
            ParamInfo paramInfo = paramInfoService.selectById(param.getParamId());
            if (paramInfo != null){
                paramInfoService.removeById(param.getParamId()) ;
            }
        }
    }
    
    规则调用接口
    @RestController
    @RequestMapping("/rule")
    public class RuleController {
        @Resource
        private KieSession kieSession;
        @Resource
        private RuleEngineService ruleEngineService ;
        @RequestMapping("/param")
        public void param (){
            QueryParam queryParam1 = new QueryParam() ;
            queryParam1.setParamId("1");
            queryParam1.setParamSign("+");
            QueryParam queryParam2 = new QueryParam() ;
            queryParam2.setParamId("2");
            queryParam2.setParamSign("-");
            // 入参
            kieSession.insert(queryParam1) ;
            kieSession.insert(queryParam2) ;
            kieSession.insert(this.ruleEngineService) ;
            // 返参
            RuleResult resultParam = new RuleResult() ;
            kieSession.insert(resultParam) ;
            kieSession.fireAllRules() ;
        }
    }
    

    由于水平有限,本博客难免有不足,恳请各位大佬不吝赐教!

  • 相关阅读:
    基于分布式 KV 存储引擎的高性能 K8s 元数据存储项目 —— KubeBrain
    C 语言数据类型概述
    java毕业设计网站基于javaweb活动报名管理系统
    java 企业工程管理系统软件源码 自主研发 工程行业适用
    java版工程管理系统Spring Cloud+Spring Boot+Mybatis实现工程管理系统源码
    简单的抓包
    mysql45讲记录
    关于GitHub Desktop中的“Open in Git Bash”无法使用的问题
    Power BI 傻瓜入门 9. 设计和部署数据模型
    UOS QTextEdit设置换行和滚动条(bug自动换行时右侧个别字符被遮盖)
  • 原文地址:https://blog.csdn.net/qq_42709715/article/details/126960688