You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中StringBuilder生成相同字符串不相等及Drools包差异审计需求

Q2: Drools包函数差异审计的技术实现方案

我之前做规则引擎运维平台时刚好做过类似功能,核心思路是先解析提取新旧包的函数元数据,再通过唯一标识比对实现增删改判定,具体拆成这几个步骤:

1. 定义函数元数据模型

先把Drools函数的关键信息封装成实体,用来存储比对所需的核心数据:

public class DroolsFunctionMeta {
    // 函数唯一标识:函数名+参数类型签名(比如"calculateTotal(java.lang.String,int)")
    private String uniqueId;
    private String functionName;
    // 参数类型列表,比如["java.lang.String", "int"]
    private List<String> paramTypes;
    private String returnType;
    // 标准化后的函数体文本(避免换行空格导致误判)
    private String functionBody;
    // 可选:函数所在DRL文件路径、注释等
    private String drlFilePath;
}

这里的uniqueId是核心——Drools支持函数重载,必须用「函数名+参数类型签名」作为唯一标识,才能区分同名不同参数的函数。

2. 解析Drools包提取函数元数据

推荐优先用Drools官方API,比正则更准确:

方式一:利用Drools Kie API解析

通过KieServices加载DRL内容,从规则包描述符中提取函数信息:

KieServices kieServices = KieServices.Factory.get();
KieFileSystem kfs = kieServices.newKieFileSystem();
// 把DRL内容写入KieFileSystem(从数据库或文本框获取)
kfs.write("src/main/resources/rules/myPackage.drl", 
          kieServices.getResources().newByteArrayResource(drlContent.getBytes()));
KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll();
// 获取KieBase并提取函数描述符
KieBase kieBase = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId()).getKieBase();
Collection<FunctionDescr> functionDescrs = kieBase.getKiePackage("myPackage").getFunctions();
// 把FunctionDescr转成自定义的DroolsFunctionMeta
for (FunctionDescr descr : functionDescrs) {
    DroolsFunctionMeta meta = new DroolsFunctionMeta();
    meta.setFunctionName(descr.getName());
    meta.setReturnType(descr.getReturnType());
    // 提取参数类型
    List<String> paramTypes = descr.getParameters().stream()
            .map(ParamDescr::getType)
            .collect(Collectors.toList());
    meta.setParamTypes(paramTypes);
    // 生成唯一ID
    meta.setUniqueId(descr.getName() + "(" + String.join(",", paramTypes) + ")");
    // 从原始DRL中匹配函数体(FunctionDescr不直接存函数体文本)
    // 可结合正则从drlContent中提取对应函数的代码块
}

方式二:正则表达式解析(轻量场景)

如果不想依赖Kie API,先去除DRL中的单行/多行注释,再用正则匹配函数定义:

// 匹配函数定义的正则,支持多行
function\s+([a-zA-Z0-9_]+)\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*\{([\s\S]*?)\}

注意:正则要处理函数体嵌套大括号的边界情况,复杂场景建议用ANTLR生成Drools语法解析器来提取。

3. 新旧函数集的差异比对逻辑

用Map做索引实现快速比对:

// 1. 旧函数集转成Map,key为uniqueId
Map<String, DroolsFunctionMeta> oldFunctionMap = oldFunctionList.stream()
        .collect(Collectors.toMap(DroolsFunctionMeta::getUniqueId, meta -> meta));

// 2. 遍历新函数集,判断新增/修改
List<FunctionChangeRecord> changeRecords = new ArrayList<>();
for (DroolsFunctionMeta newMeta : newFunctionList) {
    String uniqueId = newMeta.getUniqueId();
    if (!oldFunctionMap.containsKey(uniqueId)) {
        // 新增函数
        changeRecords.add(new FunctionChangeRecord(newMeta, ChangeType.ADD));
    } else {
        DroolsFunctionMeta oldMeta = oldFunctionMap.get(uniqueId);
        // 比对核心字段,标准化文本避免格式差异误判
        boolean isModified = !normalizeText(newMeta.getFunctionBody()).equals(normalizeText(oldMeta.getFunctionBody()))
                || !newMeta.getReturnType().equals(oldMeta.getReturnType());
        if (isModified) {
            // 修改函数,记录新旧差异
            changeRecords.add(new FunctionChangeRecord(oldMeta, newMeta, ChangeType.MODIFY));
        }
        // 移除已匹配的旧函数,剩余的就是被删除的
        oldFunctionMap.remove(uniqueId);
    }
}

// 3. 旧函数Map中剩余的就是删除的函数
for (DroolsFunctionMeta deletedMeta : oldFunctionMap.values()) {
    changeRecords.add(new FunctionChangeRecord(deletedMeta, ChangeType.DELETE));
}

其中normalizeText()用来标准化文本,去除多余换行、空格:

private static String normalizeText(String text) {
    return text.replaceAll("\\s+", " ").trim();
}

4. 差异结果的存储与展示

把changeRecords存储到数据库审计表,或生成可视化报告:

  • 对修改的函数,用diff-match-patch等工具生成函数体的差异高亮;
  • 前端用表格展示所有变更,点击修改项可展开对比详情。

内容的提问来源于stack exchange,提问作者SagittariusA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 04:19:51