当前位置: 首页 > news >正文

【Netty】消息分发处理方式

背景

检索平台,使用长链接的方式与外部系统进行交互; 因平台使用的的自定义二进制交互协议,因此需要针对每个接口请求与响应都要进行编解码, 因此需要一种针对不同消息的分发处理

方案一 注解 + 反射
示例:
/**
* 消息类型注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MessageHandler {
    //类型,平台使用符号CMD, 为了兼容不同类型,相同处理方式逻辑,这里可设置为数组
    String type();
    // 优先级
    int priority() default 0;
}

/**
* 基础处理器
*/
public abstract class AbstractMessageHandler {
    // 处理消息的抽象方法
    public abstract void handle(Object message);
}


/**
* 具体处理器示例
*/
@MessageHandler(type = "USER")
public class UserMessageHandler extends AbstractMessageHandler {
    @Override
    public void handle(Object message) {
        // 处理用户消息
    }
}

@MessageHandler(type = "ORDER")
public class OrderMessageHandler extends AbstractMessageHandler {
    @Override
    public void handle(Object message) {
        // 处理订单消息
    }
}

/**
  * 消息分发处理器
  */
public class MessageDispatchHandler extends ChannelInboundHandlerAdapter {
    private final Map<String, AbstractMessageHandler> handlerMap = new HashMap<>();

    
    public MessageDispatchHandler() {
        // 初始化时扫描并注册所有处理器
        initHandlers();
    }

    private void initHandlers() {
        // 扫描指定包下的所有类
        Reflections reflections = new Reflections("com.your.package");
        Set<Class<?>> handlers = reflections.getTypesAnnotatedWith(MessageHandler.class);
        
        for (Class<?> handlerClass : handlers) {
            MessageHandler annotation = handlerClass.getAnnotation(MessageHandler.class);
            try {
                AbstractMessageHandler handler = (AbstractMessageHandler) handlerClass.newInstance();
                handlerMap.put(annotation.type(), handler);
            } catch (Exception e) {
                // 异常处理
            }
        }
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        // 获取消息类型
        String type = getMessageType(msg);
        AbstractMessageHandler handler = handlerMap.get(type);
        
        if (handler != null) {
            handler.handle(msg);
        } else {
            // 处理未知类型消息
            ctx.fireChannelRead(msg);
        }
    }
}


/**
* 异常处理
*/
public class MessageDispatchHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // 统一的异常处理
        if (cause instanceof MessageHandleException) {
            // 处理特定异常
        } else {
            // 处理其他异常
        }
    }
}


/**
* 处理器生命周期管理
*/
public abstract class AbstractMessageHandler {
    public void init() {
        // 初始化逻辑
    }

    public void destroy() {
        // 销毁逻辑
    }

    public abstract void handle(Object message);
}

优势:

  1. 更容易实现动态的消息类型处理
  2. 可以更方便地进行统一的消息处理前后的拦截
  3. 便于实现消息处理的统计、监控等横切功能

问题:

  1. 反射可能带来性能开销
  2. 类型判断的逻辑集中在一处,可能会变得复杂
  3. 不是标准的 Netty Pipeline 模式,不能像 Netty Pipeline 那样灵活地调整处理顺序
方案二、Netty责任链
// 配置 Pipeline
public void initChannel(SocketChannel ch) {
    ChannelPipeline pipeline = ch.pipeline();
    pipeline.addLast(new StringDecoder());
    pipeline.addLast(new UserMessageHandler());
    pipeline.addLast(new OrderMessageHandler());
    pipeline.addLast(new SystemMessageHandler());
}

// 各个 Handler 只处理自己关心的消息类型
public class UserMessageHandler extends SimpleChannelInboundHandler<UserMessage> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, UserMessage msg) {
        // 处理用户消息
    }
}

public class OrderMessageHandler extends SimpleChannelInboundHandler<OrderMessage> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, OrderMessage msg) {
        // 处理订单消息
    }
}

优势:

  1. 代码结构更清晰 ,每个 Handler 职责单一,只处理特定类型的消息,处理流程清晰可见,易于理解和维护
  2. 更灵活的消息流转,可以动态决定是否继续传递消息,支持双向传递(Inbound 和 Outbound)
  3. 线程安全,Netty 的 Pipeline 实现保证了处理器的线程安全
  4. 避免了手动同步带来的复杂性
  5. 性能更优,Netty 的 Pipeline 实现经过优化

总结

从性能角度来说
  1. netty责任链模式性能更好
  2. 不需要运行时反射
  3. 类型检查更高效
  4. 内存占用更小

但是,这并不意味着反射注解就一定不好,在以下场景中,反射注解方案可能更适合:

  1. 需要非常灵活的消息处理配置
  2. 需要动态加载/卸载处理器
  3. 处理器的执行顺序需要频繁调整
  4. 业务逻辑比网络IO更重,反射带来的性能影响可以忽略

最终的选择应该基于性能要求、业务复杂度、扩展性需求、维护成本;如果没有特殊要求,建议使用原生的Netty原生的责任链模式,因为他不仅性能更好,而且与Netty的整体的设计理念更加契合

相关文章:

  • Unity shader管道液体流入并流出效果
  • Spring Boot 静态访问配置属性的解决方案
  • EditRocket for Mac v5.0.2 文本编辑器 支持M、Intel芯片
  • 从信息熵上看图像
  • RISCV虚拟化环境搭建
  • windows主机持久化技术
  • 实用插件推荐 -------- 一个可以将任意语言(python、C/C++、go、java等)的程序转换为汇编语言的小插件
  • 神经网络量化3-全连接层实现量化
  • 12 File文件对象:创建、获取基本信息、遍历文件夹、查找文件;字符集的编解码 (黑马Java视频笔记)
  • Qt动态设置样式,实现样式实时切换
  • IntelliJ 配置文件plugin.xml
  • Vector 的模拟实现:从基础到高级
  • 10、基于osg引擎生成热力图高度图实现3D热力图可视化、3D热力图实时更新(带过渡效果)
  • ABSD基于架构的软件设计
  • 在WINDOWS中如何运行VBS脚本,多种运行方式
  • 游戏引擎学习第167天
  • LLM(5):了解 GPT 架构
  • SY6280AAC usb电流限流电子开关
  • 美国站群服务器租用应该怎么选?
  • C++输入输出流第一弹:标准输入输出流 详解(带测试代码)
  • 央行:当前我国债券市场定价效率、机构债券投资交易和风险管理能力仍有待提升
  • 从上海首个到成片复制,闵行零工市场如何优化劳动就业服务?
  • 中华人民共和国和俄罗斯联邦在纪念中国人民抗日战争、苏联伟大卫国战争胜利和联合国成立80周年之际关于进一步深化中俄新时代全面战略协作伙伴关系的联合声明
  • 两部门发布山洪灾害气象预警:北京西部、河北西部等局地山洪可能性较大
  • 中国经济新动能|警惕数字时代下经济的“四大极化”效应
  • 蓝佛安:中方将采取更加积极有为的宏观政策,有信心实现今年5%左右增长目标