惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
Stack Overflow Blog
Stack Overflow Blog
Hugging Face - Blog
Hugging Face - Blog
博客园_首页
T
The Blog of Author Tim Ferriss
博客园 - 叶小钗
N
Netflix TechBlog - Medium
腾讯CDC
C
Check Point Blog
P
Proofpoint News Feed
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI
S
SegmentFault 最新的问题
F
Fortinet All Blogs
美团技术团队
U
Unit 42
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 司徒正美
F
Full Disclosure
Recorded Future
Recorded Future
D
DataBreaches.Net
博客园 - 【当耐特】
Martin Fowler
Martin Fowler
J
Java Code Geeks
I
InfoQ
Y
Y Combinator Blog
A
About on SuperTechFans
AI
AI
爱范儿
爱范儿
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Forbes - Security
Forbes - Security
W
WeLiveSecurity
M
MIT News - Artificial intelligence
雷峰网
雷峰网
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Simon Willison's Weblog
Simon Willison's Weblog
Schneier on Security
Schneier on Security
The GitHub Blog
The GitHub Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
aimingoo的专栏
aimingoo的专栏
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
G
GRAHAM CLULEY
Know Your Adversary
Know Your Adversary
Latest news
Latest news
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
D
Docker
Recent Commits to openclaw:main
Recent Commits to openclaw:main
量子位
V2EX - 技术
V2EX - 技术
Project Zero
Project Zero

博客园 - 三驾马车

Claude Code 官宣:可以在 IDEA 用了! idea gitee 更新已取消 解决方案 ByteBuffer和ByteBuf区别 Marshalling.getProvidedMarshallerFactory("serial") 参数有那些 ProtobufVarint32FrameDecoder和ProtobufDecoder区别 protobuf 的 Varint 编码规范 ChannelInboundHandlerAdapter 的channelRead和channelReadComplete的区别 Unpooled.buffer()和Unpooled.copiedBuffer区别 ServerBootstrap 和Bootstrap 区别 childhandler 和 handler 区别 ChannelInitializer<SocketChannel> 的作用详解 ChannelHandlerAdapter 和 ChannelInboundHandlerAdapter 的区别 SimpleChannelInboundHandler 中的 messageReceived 和 channelRead0 ChannelHandlerAdapter 与 ChannelInboundHandler 的区别 Application run failed .ParserException: while parsing a block mapping in 'reader' openssl genrsa 自签名ssl证书 上传本地项目到新建git项目 save download pdf
netty initChannel ch.pipeline().addLast 先后顺序很重要
三驾马车 · 2025-05-20 · via 博客园 - 三驾马车

在 Netty 中,ChannelPipeline 的处理器(ChannelHandler)的 添加顺序(addLast 的顺序)会直接影响数据的处理流程,尤其是在 入站(Inbound) 和 出站(Outbound) 事件的传播方向上。以下是关键点解析:


1. Pipeline 的处理顺序

Netty 的 ChannelPipeline 是一个 双向链表,事件(如数据读取、写入)会按照处理器的添加顺序依次传递。

  • 入站事件(Inbound):从 head → 自定义处理器 → tail(即 addLast 的先后顺序)。

  • 出站事件(Outbound):从 tail → 自定义处理器 → head(即 addLast 的逆序)。

示例代码

ch.pipeline()
    .addLast("decoder", new StringDecoder())    

2. 入站事件(Inbound)的顺序影响

假设接收到数据 "Hello"

  1. StringDecoder:将 ByteBuf 解码为 String

  2. MyBusinessHandler:处理解码后的字符串。

如果顺序颠倒

ch.pipeline()
    .addLast("handler", new MyBusinessHandler()) 
  • 问题MyBusinessHandler 会直接收到原始的 ByteBuf,无法正确处理数据。


3. 出站事件(Outbound)的顺序影响

假设发送数据 "World"

  1. MyBusinessHandler:发出 String 类型数据。

  2. StringEncoder:将 String 编码为 ByteBuf

如果顺序颠倒

ch.pipeline()
    .addLast("encoder", new StringEncoder())     
  • 问题StringEncoder 会先于 MyBusinessHandler 处理数据,导致编码失败(因为业务处理器未先转换数据)。


4. 必须遵循的规则

  1. 解码器(Inbound)

    • 应放在业务处理器之前,确保数据先解码再处理。

    • 例如:ProtobufDecoderStringDecoder

  2. 编码器(Outbound)

    • 应放在业务处理器之后,确保业务数据先准备好再编码。

    • 例如:ProtobufEncoderStringEncoder

  3. 业务处理器

    • 通常放在编解码器之间,处理已解码的入站数据或准备出站数据。


5. 典型 Pipeline 配置示例

场景:处理 Protobuf 数据

执行顺序

  • 入站
    FrameDecoder → ProtobufDecoder → MyBusinessHandler

  • 出站
    MyBusinessHandler → ProtobufEncoder → LengthFieldPrepender


6. 调试技巧

如果处理器顺序不正确,可以通过以下方式排查:

  1. 打印 pipeline 的当前顺序:

    System.out.println(ch.pipeline().names());
  2. 检查日志中事件的传播路径,确保编解码器在正确位置。


7. 特殊处理器

  • SimpleChannelInboundHandler
    只处理特定类型的入站数据,需确保前置解码器已转换数据到目标类型。

  • ChannelDuplexHandler
    同时处理入站和出站事件,需谨慎安排顺序。


总结

  • 顺序很重要addLast 的先后顺序直接影响数据处理流程。

  • 入站:从前往后(解码 → 业务处理)。

  • 出站:从后往前(业务处理 → 编码)。

  • 黄金法则:编解码器靠近传输层,业务处理器靠近应用层。

如果遇到数据解析失败或编码错误,首先检查 Pipeline 的处理器顺序!