drools简单应用

  当某个服务的需求经常变的时候,如果使用了硬编码的方式进行开发会是一件非常麻烦的事。

  最近在对项目的积分模块进行改造的时候想到了规则引擎,使用规则引擎处理复杂而且多变的业务逻辑有其非常大的优势,包括实时更新、性能等方面。

不多说,直接上代码:

1、第一步先写好工具类,有了工具类,只需在应用的业务场景中调用相应方法就可以了

@Component
public class KieSessionUtils {

    private static KieBase kieBase;

    //定义规则文件的包名,与drl文件里的package对应
    private static final String drlPackage = "rules";

    //定义drl文件的存放路径,静态变量需要通过在其set方法上打@Value注解,才可实现配置注入
    private static String drlPath;

    //通过配置拉取路径,这里推荐一下apollo配置中心,使用apollo可以实时更改通过@Value拉取的配置
    @Value("${drools.points.drlPath}")
    public void setDrlPath(String drlPath){
        KieSessionUtils.drlPath = drlPath;
    }

    /**
     *  生成kieSeesion会话
     * @param ruleName
     * @return
     * @throws Exception
     */
    public static KieSession newKieSession(String ruleName) throws Exception {
        //无状态的kieSession,和有状态相比,区别在于不维持会话,即使用完后自动释放资源,不需要手动调dispose
        //StatelessKieSession kieSession = getKieBase(ruleName).newStatelessKieSession();
        //有状态的kieSession
        KieSession kieSession = getKieBase(ruleName).newKieSession();
        //添加监听器,这里加的是对规则文件运行debug监听器,测试时最好加上,用于排查问题,生产上可视情况去掉
        kieSession.addEventListener(new DebugRuleRuntimeEventListener());
        return kieSession;
    }

    /**
     *  生成kieBase
     * @param ruleName 规则文件名
     * @return
     * @throws Exception
     */
    protected static KieBase getKieBase(String ruleName) throws Exception {
        //判断kieBase和需要获取的规则文件是否存在,不存在则重新初始化kieBase
        if (kieBase ==null || kieBase.getRule(drlPackage,ruleName)==null) {
            KieServices kieServices = KieServices.Factory.get();
            KieFileSystem kfs = kieServices.newKieFileSystem();
            //获取规则数据源,这里由于本人项目使用的是springboot,打包会打成jar包,如果想做实时更新,drl文件需要放在jar包外面
            //获取resource的方式很多,不一定要用读取文件的方式,可根据自己的设计和业务场景采取不同方案
            Resource resource = kieServices.getResources().newFileSystemResource(new File(drlPath+"/"+ruleName));
            resource.setResourceType(ResourceType.DRL);
            kfs.write(resource);
            KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll();
            if (kieBuilder.getResults().getMessages(Message.Level.ERROR).size() > 0) {
                throw new Exception();
            }
            KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());
            kieBase = kieContainer.getKieBase();
        }
        return kieBase;
    }
    
    /**
     * 更新规则
     * @param ruleName 规则名和规则文件名
     * @throws Exception
     */
    public static void refreshRules(String ruleName) throws Exception {
        //判断规则不为null,则移除规则
        if (kieBase !=null && kieBase.getRule(drlPackage,ruleName)!=null){
            //为了方便,本人把规则名和drl文件名称统一定义了
            kieBase.removeRule(drlPackage,ruleName);
            //重新初始化kieBase
            getKieBase(ruleName);
        }
    }
}

2、编写规则文件,这里只给出和规则引擎格式有关的代码

package rules;    //包名

import com.jiuair.dto.AddObject
import java.util.List
import java.util.HashMap
import java.util.Map
import java.util.ArrayList
import java.util.Date
import java.util.Iterator
import java.util.Set

global com.demo.dto.AddObject addObject    //传入的对象,同时也是返回值对象

    rule "add.drl"    //规则名,为了方便,设为何drl文件名一样,可以不一样
        
        when
            $s : AddObject();
        then
            。。。。。//这一段加自己业务代码逻辑,支持jdk
           $s.setResult(X);    //执行完逻辑后将结果设置到对象中
end

3、在业务场景中调用工具类里的方法

private AddObject executeAddRule(Object data) {
        AddObject addObject = new AddObject();
        addObject.setJsonObject(data);
        try {
            //获取会话
            KieSession kieSession = KieSessionUtils.newKieSession("add.drl");
            //设置传入参数
            kieSession.insert(addObject);
            //设置全局参数
            kieSession.setGlobal("addObject",addObject);
            //执行规则
            kieSession.fireAllRules();
            //释放会话资源
            kieSession.dispose();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return addObject;
    }

4、实现实时更新drl文件

   /**
     * 更新规则文件,这里只给出service层的代码了,相信controller大家都会写。。。
     * @param name  名称为drl的文件名
     * @param is    由于dubbo不支持流的方式传输,文件需在controller转为byte数组,再传到service
     */
    @Override
    public void refreshRule(String name, byte[] is) {
        try {
            FileOutputStream fos = new FileOutputStream(drlPath+"/"+name);
            fos.write(is);
            fos.close();
            KieSessionUtils.refreshRules(name);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

附maven引包:

      <properties>
        <runtime.version>7.20.0.Final</runtime.version>
    </properties>


    <dependency>
            <groupId>org.kie</groupId>
            <artifactId>kie-api</artifactId>
            <version>${runtime.version}</version>
        </dependency>
        <dependency>
            <groupId>org.kie</groupId>
            <artifactId>kie-internal</artifactId>
            <version>${runtime.version}</version>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-core</artifactId>
            <version>${runtime.version}</version>
        </dependency>    

  没有英汉互译结果
   请尝试网页搜索

猜你喜欢

转载自www.cnblogs.com/jagerLan/p/10857004.html