目录
<div class="table-of-contents"><ul><li><a href="#%E5%89%8D%E8%A8%80">前言</a></li><li><a href="#%E4%BA%8B%E4%BB%B6%E6%98%AF%E5%A6%82%E4%BD%95%E5%9C%A8pipeline%E4%B8%AD%E4%BC%A0%E6%92%AD%E7%9A%84">事件是如何在pipeline中传播的</a></li><li><a href="#%E4%BC%A0%E6%92%AD%E9%A1%BA%E5%BA%8F">传播顺序</a></li><li><a href="#%E7%9C%8B%E7%9C%8B%E7%B1%BB%E5%9B%BE">看看类图</a><ul><li><a href="#channelinboundhandler">ChannelInboundHandler</a></li><li><a href="#channeloutboundhandler">ChannelOutboundHandler</a></li><li><a href="#adapter">Adapter</a></li></ul></li></ul></div>
# 前言
因为后两篇博客我打算针对inbound和outbound的某个事件跟一下回调代码,所以现在这里写一篇博客记录一下inbound和outbound事件的区别。
本篇博客比较短,主要是摘自Netty的JavaDoc中,关于[ChannelPipeline](https://netty.io/4.1/api/io/netty/channel/ChannelPipeline.html)的描述。
> 文档版本:4.1.x
<br/>
在这里我还想吐槽一下Netty的官方文档:像inbound和oubound概念区分这么重要的东西,怎么就不写在 https://netty.io 中呢?偏偏写在ChannelPipeline的JavaDoc中,要不是我有点追文档的习惯恰好看到,可能这辈子都无法区分inbound和outbound事件了。
<br/>
# 事件是如何在pipeline中传播的
我们先来看看官方文档中给出的一张“图”:
```java
I/O Request
via Channel or
ChannelHandlerContext
|
+---------------------------------------------------+---------------+
| ChannelPipeline | |
| \|/ |
| +---------------------+ +-----------+----------+ |
| | Inbound Handler N | | Outbound Handler 1 | |
| +----------+----------+ +-----------+----------+ |
| /|\ | |
| | \|/ |
| +----------+----------+ +-----------+----------+ |
| | Inbound Handler N-1 | | Outbound Handler 2 | |
| +----------+----------+ +-----------+----------+ |
| /|\ . |
| . . |
| ChannelHandlerContext.fireIN_EVT() ChannelHandlerContext.OUT_EVT()|
| [ method call] [method call] |
| . . |
| . \|/ |
| +----------+----------+ +-----------+----------+ |
| | Inbound Handler 2 | | Outbound Handler M-1 | |
| +----------+----------+ +-----------+----------+ |
| /|\ | |
| | \|/ |
| +----------+----------+ +-----------+----------+ |
| | Inbound Handler 1 | | Outbound Handler M | |
| +----------+----------+ +-----------+----------+ |
| /|\ | |
+---------------+-----------------------------------+---------------+
| \|/
+---------------+-----------------------------------+---------------+
| | | |
| [ Socket.read() ] [ Socket.write() ] |
| |
| Netty Internal I/O Threads (Transport Implementation) |
+-------------------------------------------------------------------+
```
从官方给出的图中,我们不难领悟到,**inbound和outbound这两个词中的in和out就是相对于ChannelPipeline的。**
- **如果事件传播出ChannelPipeline,就是outbound事件**。
- **如果事件是从外部传进ChannelPipeline的,就是inbound事件**。
<br/>
# 传播顺序
从上面的图中,我们首先获得的第一印象是:
- outbound事件是自顶向下传播的。
- inbound事件则是自底向上传播的。
如果结合我前面的[pipeline初始化](https://wenjie.store/archives/about-pipeline-1)、[添加ChannelHandler](https://wenjie.store/archives/about-pipeline-2)两篇博客,就很容易**误以为**:outbound事件是从head节点传播到tail节点,inbound事件是从tail节点传播到head节点。但实际上**这个第一印象是错的**,把这个第一印象反过来就对了。
<br/>
官方文档也给出了解释顺序的例子,我们一起来看一下,假如有如下代码:
```java
ChannelPipeline p = ...;
p.addLast("1", new InboundHandlerA());
p.addLast("2", new InboundHandlerB());
p.addLast("3", new OutboundHandlerA());
p.addLast("4", new OutboundHandlerB());
p.addLast("5", new InboundOutboundHandlerX());
```
- 对于inbound事件传播,顺序是1,2,5,跟添加顺序相同。
- 对于outbound事件传播,顺序是5,4,3,跟添加顺序相反。
后来我自己调试代码(将过程记录与后两篇博客),也确实是上述的顺序。
<br/>
# 看看类图
看看ChannelInboundHandler、ChannelOutboundHandler两大方法的类图:

ChannelHandler在[这一篇](https://wenjie.store/archives/about-pipeline-1)已经提到过了,这里就不再赘述。
<br/>
## ChannelInboundHandler
直接来看看这些方法:

- 在我前面的博客中遇到过大部分,用官方的图来解释,即channel的变化事件传播,都是由Netty内部的I/O线程传播到pipeline的,属于inbound事件。
<br/>
## ChannelOutboundHandler
也是直接来看看它的方法:

- 说明诸如绑定、读取新连接、写数据等操作,都是由pipeline传播到Netty内部的I/O线程的。
<br/>
## Adapter
ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter则是官方提供的一个便利父类,绝大部分方法的默认实现都是将事件传播给下/上一个节点。

【Netty】Pipeline相关(四):inbound和outbound事件的区别