设计模式——责任链模式实战,优雅处理Kafka消息

一、业务背景

Kafka接收消息,需要A,B,C...多种策略做处理,再通过http请求发送给下游。多种策略混在一起很难维护,通过责任链模式把每种策略的代码收敛到自己的Handler中

二、具体设计

classDiagram Handler <|-- StrategyAHandler Handler <|-- StrategyBHandler Handler <|-- UploadHandler Handler: +void handleUserData(UserContext, HandlerChain) Handler: +void handleOrderData(OrderContext, HandlerChain) class StrategyAHandler { +void handleUserData(UserContext, HandlerChain) +void handleOrderData(OrderContext, HandlerChain) } class StrategyBHandler { +void handleUserData(UserContext, HandlerChain) +void handleOrderData(OrderContext, HandlerChain) } class UploadHandler { +void handleUserData(UserContext, HandlerChain) +void handleOrderData(OrderContext, HandlerChain) } HandlerChain o--o Handler class HandlerChain { +List~Handler~ chain +void doHandle(AbstractContext context) } HandlerChain --> AbstractContext class AbstractContext { +JSONObject param +int position } AbstractContext <|-- UserContext AbstractContext <|-- OrderContext class UserContext { +UserInfo userInfo } class OrderContext { +OrderInfo orderInfo }

三、代码实现

1.HandlerChain类

java 复制代码
public class HandlerChain {

    List<Handler> chain;
    
    public HandlerChain() {
        chain = new ArrayList<>();
    }
    
    public void doHandle(AbstractContext context) {
        // 截止条件
        if (context.getPosition() >= chain.size()) {
            return;
        }
        // 获取当前要执行的handler
        Handler handler = chain.get(context.getPosition());
        // 移动到下一个要执行的handler位置
        context.setPosition(context.getPosition() + 1);
        // 利用Context类的多态,判断执行的具体方法
        if (context instanceof UserContext) {
            handler.handleUserData((UserContext) context, this);
        } else if (context instanceof OrderContext) {
            handler.handleOrderData((OrderContext) context, this);
        }
    }
    
    public void addHandler(Handler handler) {
        chain.add(hander);
    }

}

2.Handler类

  • Handler接口:定义需要处理的消息
java 复制代码
public interface Handler {
    // 处理用户数据消息
    void handleUserData(UserContext userContext, HandlerChain chain);
    // 处理订单数据消息
    void handleOrderData(OrderContext orderContext, HandlerChain chain);
}
  • Handler实现类:子类结构相同,执行各自的具体逻辑
java 复制代码
@Component
public class StrategyAHandler implements Handler {
    // 处理用户数据消息
    public void handleUserData(UserContext userContext, HandlerChain chain) {
        // ...
        // 核心方法,触发流转到下一个handler
        chain.doHandle(userContext);
    }
    // 处理订单数据消息
    public void handleOrderData(OrderContext orderContext, HandlerChain chain) {
        ...
        // 核心方法,触发流转到下一个handler
        chain.doHandle(orderContext);
    }
}

@Component
public class StrategyBHandler implements Handler {
 // ...
}

@Component
public class UploadHandler implements Handler {
 // ...
}

3.Context类

  • Context抽象类 :定义公共参数
    • param:处理到最后要发http请求,因此构建一个公共的JSONObject类型参数
    • position:标记即将执行的handler所在位置
java 复制代码
@Data
public abstract class AbstractContext {
    private JSONObject param = new JSONObject();
    private int position = 0;
}
  • Context实现类:定义每一种消息独有的参数
java 复制代码
@Data
public class UserContext extends AbstractContext {
    private UserInfo userInfo;
    
    public UserContext(UserInfo userInfo) {
        this.userInfo = userInfo;
    }
}
java 复制代码
@Data
public class OrderContext extends AbstractContext {
    private OrderInfo orderInfo;
    
    public OrderContext(OrderInfo orderInfo) {
        this.orderInfo = orderInfo;
    }
}

4.Handler组装类

  • 作用:接收Kafka消息,把各种策略按任意顺序组装
java 复制代码
@Component
public class DemoService {
    @Autowired
    private StrategyAHandler strategyAHandler;
    @Autowired
    private StrategyBHandler strategyBHandler;
    @Autowired
    private UploadHandler uploadHandler;
    
    // 处理Kafka发来的用户信息
    public void handleUserData(UserInfo userInfo) {
        HandlerChain chain = new HandlerChain();
        chain.addHandler(strategyAHandler);
        chain.addHandler(strategyBHandler);
        chain.addHandler(uploadHandler);
        UserContext userContext = new UserContext(userInfo);
        chain.doHandle(userContext);
    }
    
    // 处理Kafka发来的订单信息
    public void handleOrderData(OrderInfo orderInfo) {
        HandlerChain chain = new HandlerChain();
        chain.addHandler(strategyBHandler);
        chain.addHandler(strategyAHandler);
        chain.addHandler(uploadHandler);
        OrderContext orderContext = new OrderContext(orderInfo);
        chain.doHandle(orderContext);
    }
}

四、总结

  • Handler实现类交给Spring框架来管理,Context和HandlerChain则是每次调用创建一份
  • 实现效果是可以把某个策略的代码收敛在一个Handler实现类中
  • 如果需要去掉某个策略,直接把该策略从chain中去除即可
相关推荐
Meepo_haha1 分钟前
创建Spring Initializr项目
java·后端·spring
Memory_荒年2 分钟前
SpringBoot事务源码深度游:从注解到数据库的“奇幻漂流”
java·后端·spring
编码忘我5 分钟前
为什么要用SpringBoot
java·后端
Memory_荒年14 分钟前
SpringBoot事务:从“一键开关”到“踩坑大全”的生存指南
java·后端·spring
PFinal社区_南丞18 分钟前
一文讲透 .trae 文件夹 - Trae IDE 配置指南和最佳实践
后端
段小二38 分钟前
Spring AI Agent 完整实战:Function Calling + RAG + Memory + SafeGuard 构建机票助手
后端
编码忘我40 分钟前
Spring源码又看了一遍
后端
希望永不加班1 小时前
SpringBoot 主启动类解释:@SpringBootApplication 到底做了什么
java·spring boot·后端·spring
一只叫煤球的猫1 小时前
为什么不用 RAG 做记忆系统 ——压缩上下文与 memory.md 的架构选择
人工智能·后端·ai编程
智能工业品检测-奇妙智能1 小时前
国产化系统的性价比对比
人工智能·spring boot·后端·openclaw·奇妙智能