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>  
    <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-decisiontables</artifactId>
        <version>${runtime.version}</version>
    </dependency>

 

 

  沒有英漢互譯結果
   請嘗試網頁搜索


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM