欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

在Spring Boot/Cloud和Nacos中无缝集成Drools:规则更改无需重启服务

最编程 2024-02-01 13:22:19
...

最近做了个需求,就是http调第三方地图图层接口获取点位信息,要把reponseData转换为我们自己的entity数据结构然后入库,因为每种图层返回的json数据结构都不一样,并且图层种类又很多,于是就考虑使用drools来根据规则动态转换,为了使得规则修改后不需要重启服务,我把.drl配置到了nacos config里,并且加了监听器。

小提示

虽然可以把.drl挂到nacos里,但是一开始最好放到工程的resource目录下,因为这样我们编写.drl规则时idea会给快捷提示。

maven pom引入drools

<drools.version>7.60.0.Final</drools.version>

<!-- drools -->
<dependency>
    <groupId>org.kie</groupId>
    <artifactId>kie-api</artifactId>
    <version>${drools.version}</version>
</dependency>
<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-core</artifactId>
    <version>${drools.version}</version>
</dependency>
<dependency>
    <groupId>org.kie</groupId>
    <artifactId>kie-ci</artifactId>
    <version>${drools.version}</version>
</dependency>
<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-compiler</artifactId>
    <version>${drools.version}</version>
</dependency>

drools处理类

import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;import lombok.extern.slf4j.Slf4j;
import org.kie.api.KieBase;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.QueryResults;
import org.kie.api.runtime.rule.QueryResultsRow;
import org.kie.internal.utils.KieHelper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executor;

@Service
@Slf4j
public class DroolsLayerHandler {

    private final static String DEFAULT_GROUP = "DEFAULT_GROUP";
    String dataId = "my-parse-http-result-dev.drl";

    public ConfigService configService;

    private KieSession kieSession;

    @Value("${spring.profiles.address}")
    private String SERVER_ADDRESS;

    @PostConstruct
    public void init() {
        initConfigService();
        registerNacosListener();
        loadDroolSession();
    }


    public synchronized void loadDroolSession() {
        log.info("------------准备载入图层规则");
        try {
            String droolRule = configService.getConfig(dataId, DEFAULT_GROUP, 3000);
            log.info("获取nacos规则配置信息.\n{}", droolRule);


            KieHelper kieHelper = new KieHelper();
            kieHelper.addContent(droolRule, ResourceType.DRL);
            KieBase kieBase = kieHelper.build();
            if (kieSession != null) {
                kieSession.dispose();
            }
            kieSession = kieBase.newKieSession();
        } catch (Exception e) {
            log.error("load drools session error", e);
        }
    }

    /**
     * 触发规则逻辑
     *
     * @param
     */
    public void fireRules(String jsonStr, String layerName, String typeName, String typeCode, LayerDataHandler layerDataHandler) {
 // 给drool设置全局变量 kieSession.setGlobal(
"layerDataHandler", layerDataHandler);
 // 给drool设置入参 kieSession.insert(jsonStr);
// kieSession.insert(layerName); // kieSession.insert(typeName); // kieSession.insert(typeCode); kieSession.fireAllRules(); } /** * 查询规则引擎里设置的结果数据 */ public List<MyPoint> getQueryResults() { QueryResults results = kieSession.getQueryResults("getMyPointResult"); for (QueryResultsRow row : results) { MyPointResult result = (MyPointResult) row.get("rs"); return result.getPoints(); } return null; }
// 获取nacos config service
public void initConfigService() { Properties properties = new Properties(); properties.setProperty(PropertyKeyConst.NAMESPACE, ""); properties.put(PropertyKeyConst.SERVER_ADDR, SERVER_ADDRESS); try { configService = NacosFactory.createConfigService(properties); } catch (NacosException e) { log.error("Nacos ConfigService create error", e); } }
// 实时监听配置文件是否改动
private void registerNacosListener() { try { Listener configListener = new Listener() { @Override public void receiveConfigInfo(String configInfo) { log.info("监听到nacos配置的规则{}有改动", dataId);
// 重载规则 loadDroolSession(); } @Override
public Executor getExecutor() { return null; // Use the default executor } }; configService.addListener(dataId, DEFAULT_GROUP, configListener); } catch (Exception e) { log.error("Error registering Nacos listener", e); } } }

nacos里配置.drl

规则文件内容

import com.ttttt.entity.MyPoint;
import java.util.List
import com.tttttt.handler.LayerDataHandler
import com.ttttt.dal.dto.drools.MyPointResult;

// 声明全局变量
global LayerDataHandler layerDataHandler;

// 规则定义
rule "Parse JSON String"
    when
// 定义的规则,入参是否同时包含三个字符串 $jsonStr : String(
this contains "features", this contains "roseName", this contains "geometry" ) then
// 调用Java代码里的具体转换方法 List
<MyPoint> parsedPoints = layerDataHandler.parseText($jsonStr); System.out.println("规则被触发了,解析的点数是: " + parsedPoints.size()); MyPointResult rs = new MyPointResult(parsedPoints);
// 设置结果进工作内存 insert(rs); end
// 查询结果 query "getMyPointResult" rs : MyPointResult() end

json转换处理类

import cn.hutool.http.HttpUtil;
import com.tttttt.dal.entity.MyPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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

/**
 * @Author: 夏威夷8080
 * @Date: 2023/8/23 15:50
 */
@Component
public class LayerMyDataHandler implements LayerDataHandler {

    @Autowired
    private DroolsLayerHandler droolsLayerHandler;

    @Override
    public String getLayerName() {
        return "我的图层";
    }

    @Override
    public String getLayerCode() {
        return SECTION;
    }

    @Override
    public String getReqDataUrl() {
        return "http://test.com/pp/tt" + "?type=" + getTypeCode() + "&typeName=" + getTypeName();
    }

    @Override
    public String getTypeCode() {
        return "MY_TCLD";
    }

    @Override
    public String getTypeName() {
        return "my_tcld";
    }

    @Override
    public String syncData() {
        return HttpUtil.createGet(getReqDataUrl())
                .execute().body();
    }

    @Override
    public List<MyPoint> parseText(String httpResult) {
        List<MyPoint> points = new ArrayList<>();
        MyPoint supportLayerPoint = new MyPoint();
        supportLayerPoint.setLayerName(getLayerName());
        supportLayerPoint.setPointName("my point name");
        points.add(supportLayerPoint);
        return points;
    }

    @Override
    public List<MyPoint> convertByRule(String httpResult) {
        droolsLayerHandler.fireRules(httpResult, getLayerName(), getTypeName(), getTypeCode(), this);
        List<MyPoint> queryResults = droolsLayerHandler.getQueryResults();
        return queryResults;
    }

}

测试方法

public void test() {
        LayerDataHandler handler = layerSyncHandlerFactory.getHandler(SECTION);
        String httpResult = handler.syncData();
        List<MyPoint> points = handler.convertByRule(httpResult);
        System.out.println(points);
    }

原文地址:https://www.cnblogs.com/shamo89/p/17654233.html