本文最后更新于 2025-04-04,文章超过7天没更新,应该是已完结了~

https://wx.zsxq.com/group/48411118851818/topic/588182845455484

今天在解析xfg对于白名单和敏感词规则过滤这个功能的实现,蛮有收获的,写一篇文章记录下~~

整体的设计思路:

具体实现代码

public interface ILogicFilter {
    RuleLogicEntity<ChatProcessAggregate> filter(ChatProcessAggregate chatProcess) throws Exception;
}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogicStrategy {

    DefaultLogicFactory.LogicModel logicMode();

}
@Slf4j
@Component
@LogicStrategy(logicMode = DefaultLogicFactory.LogicModel.SENSITIVE_WORD)
public class SensitiveWordFilter implements ILogicFilter {

    @Resource
    private SensitiveWordBs words;

    @Value("${app.config.white-list}")
    private String whiteListStr;

    @Override
    public RuleLogicEntity<ChatProcessAggregate> filter(ChatProcessAggregate chatProcess) throws Exception {
        // 白名单用户不做敏感词处理
        if (chatProcess.isWhiteList(whiteListStr)) {
            return RuleLogicEntity.<ChatProcessAggregate>builder()
                    .type(LogicCheckTypeVO.SUCCESS).data(chatProcess).build();
        }

        ChatProcessAggregate newChatProcessAggregate = new ChatProcessAggregate();
        newChatProcessAggregate.setOpenid(chatProcess.getOpenid());
        newChatProcessAggregate.setModel(chatProcess.getModel());

        List<MessageEntity> newMessages = chatProcess.getMessages().stream()
                .map(message -> {
                    String content = message.getContent();
                    String replace = words.replace(content);
                    return MessageEntity.builder()
                            .role(message.getRole())
                            .name(message.getName())
                            .content(replace)
                            .build();
                })
                .collect(Collectors.toList());

        newChatProcessAggregate.setMessages(newMessages);

        return RuleLogicEntity.<ChatProcessAggregate>builder()
                .type(LogicCheckTypeVO.SUCCESS)
                .data(newChatProcessAggregate)
                .build();
    }
}
@Slf4j
@Component
@LogicStrategy(logicMode = DefaultLogicFactory.LogicModel.ACCESS_LIMIT)
public class AccessLimitFilter implements ILogicFilter {

    @Value("${app.config.limit-count:10}")
    private Integer limitCount;
    @Value("${app.config.white-list}")
    private String whiteListStr;
    @Resource
    private Cache<String, Integer> visitCache;

    @Override
    public RuleLogicEntity<ChatProcessAggregate> filter(ChatProcessAggregate chatProcess) throws Exception {
        // 1. 白名单用户直接放行
        if (chatProcess.isWhiteList(whiteListStr)) {
            return RuleLogicEntity.<ChatProcessAggregate>builder()
                    .type(LogicCheckTypeVO.SUCCESS).data(chatProcess).build();
        }
        String openid = chatProcess.getOpenid();

        // 2. 访问次数判断
        int visitCount = visitCache.get(openid, () -> 0);
        if (visitCount < limitCount) {
            visitCache.put(openid, visitCount + 1);
            return RuleLogicEntity.<ChatProcessAggregate>builder()
                    .type(LogicCheckTypeVO.SUCCESS).data(chatProcess).build();
        }

        return RuleLogicEntity.<ChatProcessAggregate>builder()
                .info("您今日的免费" + limitCount + "次,已耗尽!")
                .type(LogicCheckTypeVO.REFUSE).data(chatProcess).build();
    }

}
@Service
public class DefaultLogicFactory {

    public Map<String, ILogicFilter> logicFilterMap = new ConcurrentHashMap<>();

    public DefaultLogicFactory(List<ILogicFilter> logicFilters) {
        logicFilters.forEach(logic -> {
            LogicStrategy strategy = AnnotationUtils.findAnnotation(logic.getClass(), LogicStrategy.class);
            if (null != strategy) {
                logicFilterMap.put(strategy.logicMode().getCode(), logic);
            }
        });
    }

    public Map<String, ILogicFilter> openLogicFilter() {
        return logicFilterMap;
    }


    /**
     * 规则逻辑枚举
     */
    public enum LogicModel {

        ACCESS_LIMIT("ACCESS_LIMIT", "访问次数过滤"),
        SENSITIVE_WORD("SENSITIVE_WORD", "敏感词过滤"),
        ;
    }

}

使用过程

@Override
    protected RuleLogicEntity<ChatProcessAggregate> doCheckLogic(ChatProcessAggregate chatProcess, String... logics) throws Exception {
        Map<String, ILogicFilter> logicFilterMap = logicFactory.openLogicFilter();
        RuleLogicEntity<ChatProcessAggregate> entity = null;
        for (String code : logics) {
            entity = logicFilterMap.get(code).filter(chatProcess);
            if (!LogicCheckTypeVO.SUCCESS.equals(entity.getType())) return entity;
        }
        return entity != null ? entity : RuleLogicEntity.<ChatProcessAggregate>builder()
                .type(LogicCheckTypeVO.SUCCESS).data(chatProcess).build();
    }

解析以及相关设计模式

1、依赖注入+反射 + 注解驱动(基于元编程)

@Service
public class DefaultLogicFactory {

    public Map<String, ILogicFilter> logicFilterMap = new ConcurrentHashMap<>();

    public DefaultLogicFactory(List<ILogicFilter> logicFilters) {
        logicFilters.forEach(logic -> {
            LogicStrategy strategy = AnnotationUtils.findAnnotation(logic.getClass(), LogicStrategy.class);
            if (null != strategy) {
                logicFilterMap.put(strategy.logicMode().getCode(), logic);
            }
        });
    }
....

1.自动注入和Bean初始化

  • DefaultLogicFactory 被Spring容器管理,构造函数会在Bean实例化时被调用。

  • 构造函数的参数 List<ILogicFilter> logicFilters 会被Spring自动收集。也就是说,Spring会将容器中所有实现了 ILogicFilter 接口的Bean注入到这个列表中。即我们实现的AccessLimitFilterSensitiveWordFilter

2.不需要手动维护 ILogicFilter 的映射关系

  • AnnotationUtils.findAnnotation() 通过反射获取类上的 @LogicStrategy 注解。动态获取 logicMode(),并将 ILogicFilter 实例注册到 logicFilterMap ,相当于 给每个加了@LogicStrategy 的过滤器加了个标识。

3.实现了“无侵入式”扩展:新的规则引擎过滤器 只需要实现ILogicFilter,就会自动被工厂发现和注册,并给加上 @LogicStrategy 自动添加标记识别。(优雅~)

2、 策略模式(Strategy Pattern)

不同的过滤策略(如 AccessLimitFilterSensitiveWordFilter)可以独立定义并在运行时动态选择

public interface ILogicFilter {
    RuleLogicEntity<ChatProcessAggregate> filter(ChatProcessAggregate chatProcess) throws Exception;
}

@Slf4j
@Component
@LogicStrategy(logicMode = DefaultLogicFactory.LogicModel.ACCESS_LIMIT)
public class AccessLimitFilter implements ILogicFilter {
    @Override
    public RuleLogicEntity<ChatProcessAggregate> filter(ChatProcessAggregate chatProcess) throws Exception {
        // 访问次数校验逻辑
    }
}

@Slf4j
@Component
@LogicStrategy(logicMode = DefaultLogicFactory.LogicModel.SENSITIVE_WORD)
public class SensitiveWordFilter implements ILogicFilter {
    @Override
    public RuleLogicEntity<ChatProcessAggregate> filter(ChatProcessAggregate chatProcess) throws Exception {
        // 敏感词过滤逻辑
    }
}

策略模式的好处:

开闭原则(OCP):可以添加新的 ILogicFilter 实现,而不需要修改现有代码。
降低耦合:具体的过滤逻辑被隔离到不同的 ILogicFilter 里,工厂负责选择正确的策略。
运行时动态选择:过滤器的选择基于 logicMode,可以在运行时灵活调整,而不需要写死在代码里,如下:

3、 责任链模式(Chain of Responsibility Pattern)

多个 ILogicFilter 形成责任链,逐个执行,直到某个过滤器失败

@Override
protected RuleLogicEntity<ChatProcessAggregate> doCheckLogic(ChatProcessAggregate chatProcess, String... logics) throws Exception {
    Map<String, ILogicFilter> logicFilterMap = logicFactory.openLogicFilter();
    RuleLogicEntity<ChatProcessAggregate> entity = null;
    for (String code : logics) {
        entity = logicFilterMap.get(code).filter(chatProcess);
        if (!LogicCheckTypeVO.SUCCESS.equals(entity.getType())) return entity;
    }
    return entity != null ? entity : RuleLogicEntity.<ChatProcessAggregate>builder()
            .type(LogicCheckTypeVO.SUCCESS).data(chatProcess).build();
}
  • logics 传入多个逻辑码(如 "ACCESS_LIMIT""SENSITIVE_WORD")。

  • 遍历 logics,依次获取 logicFilterMap 中的过滤器,并执行 filter(chatProcess)

  • 如果某个过滤器返回失败(entity.getType() 不是 SUCCESS),立即终止责任链并返回失败结果

责任链模式的好处:

增强扩展性:可以轻松添加新的 ILogicFilter,不会影响现有逻辑。
灵活组合:调用方可以根据业务需要动态指定执行哪些过滤器,而不是固定的流程。
优化性能:一旦有一个过滤器失败,后续的过滤器不会执行,节省计算资源。

4、 工厂模式(Factory Pattern)

public class DefaultLogicFactory {
    public Map<String, ILogicFilter> logicFilterMap = new ConcurrentHashMap<>();

    public DefaultLogicFactory(List<ILogicFilter> logicFilters) {
        logicFilters.forEach(logic -> {
            LogicStrategy strategy = AnnotationUtils.findAnnotation(logic.getClass(), LogicStrategy.class);
            if (null != strategy) {
                logicFilterMap.put(strategy.logicMode().getCode(), logic);
            }
        });
    }

    public Map<String, ILogicFilter> openLogicFilter() {
        return logicFilterMap;
    }
}
  • DefaultLogicFactory 负责管理所有 ILogicFilter 实现类。

  • 在构造函数中,它扫描所有实现了 ILogicFilter 接口的类,并通过 @LogicStrategy 注解找到它们的 logicMode,然后将其注册到 logicFilterMap

  • ChatService 需要使用过滤器时,只需从 logicFilterMap 获取,而不需要手动创建实例。

工厂模式的好处:

解耦对象创建过程ChatService 并不关心具体的 ILogicFilter 具体实现是如何创建的,它只需要从 DefaultLogicFactory 获取。
易于扩展:如果有新的 ILogicFilter 需要加入,只需实现接口并添加 @LogicStrategy 注解,而不需要修改 DefaultLogicFactory