code-learning/netty/32-Netty 源码解析-Channel(六)之 writeAndFlush 操作.md

130 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 精尽 Netty 源码解析 —— Channel之 writeAndFlush 操作
# 1. 概述
本文接 [《精尽 Netty 源码解析 —— Channel之 flush 操作》](http://svip.iocoder.cn/Netty/Channel-5-flush/) ,分享 Netty Channel 的 `#writeAndFlush(Object msg, ...)` 方法write + flush 的组合,将数据写到内存队列后,立即刷新**内存队列**,又将其中的数据写入到对端。
😈 本来是不准备写这篇的,因为内容主要是 [《精尽 Netty 源码解析 —— Channel之 write 操作》](http://svip.iocoder.cn/Netty/Channel-4-write/) 和 [《精尽 Netty 源码解析 —— Channel之 flush 操作》](http://svip.iocoder.cn/Netty/Channel-5-flush/) 的组合。但是,考虑到内容的完整性,于是乎就稍微水更下下。
# 2. AbstractChannel
AbstractChannel 对 `#writeAndFlush(Object msg, ...)` 方法的实现,代码如下:
```
@Override
public ChannelFuture writeAndFlush(Object msg) {
return pipeline.writeAndFlush(msg);
}
@Override
public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) {
return pipeline.writeAndFlush(msg, promise);
}
```
- 在方法内部,会调用对应的
```
ChannelPipeline#write(Object msg, ...)
```
方法,将 write 和 flush
两个
事件在 pipeline 上传播。详细解析,见
「3. DefaultChannelPipeline」
- 最终会传播 write 事件到 `head` 节点,将数据写入到内存队列中。详细解析,见 [「5. HeadContext」](https://svip.iocoder.cn/Netty/Channel-6-writeAndFlush/#) 。
- 最终会传播 flush 事件到 `head` 节点,刷新**内存队列**,将其中的数据写入到对端。详细解析,见 [「5. HeadContext」](https://svip.iocoder.cn/Netty/Channel-6-writeAndFlush/#) 。
# 3. DefaultChannelPipeline
`DefaultChannelPipeline#writeAndFlush(Object msg, ...)` 方法,代码如下:
```
@Override
public final ChannelFuture write(Object msg) {
return tail.writeAndFlush(msg);
}
@Override
public final ChannelFuture write(Object msg, ChannelPromise promise) {
return tail.writeAndFlush(msg, promise);
}
```
- 在方法内部,会调用 `TailContext#writeAndFlush(Object msg, ...)` 方法,将 write 和 flush **两个**事件在 pipeline 中,从尾节点向头节点传播。详细解析,见 [「4. TailContext」](https://svip.iocoder.cn/Netty/Channel-6-writeAndFlush/#) 。
# 4. TailContext
TailContext 对 `TailContext#writeAndFlush(Object msg, ...)` 方法的实现,是从 AbstractChannelHandlerContext 抽象类继承,代码如下:
```
@Override
public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) {
if (msg == null) {
throw new NullPointerException("msg");
}
// 判断是否为合法的 Promise 对象
if (isNotValidPromise(promise, true)) {
// 释放消息( 数据 )相关的资源
ReferenceCountUtil.release(msg);
// cancelled
return promise;
}
// 写入消息( 数据 )到内存队列
write(msg, true, promise); // <1>
return promise;
}
```
- 这个方法,和我们在 [《精尽 Netty 源码解析 —— Channel之 write 操作》](http://svip.iocoder.cn/Netty/Channel-4-write/) 的 [「4. TailContext」](https://svip.iocoder.cn/Netty/Channel-6-writeAndFlush/#) 的小节,`TailContext#write(Object msg, ...)` 方法,基本类似,差异在于 `<1>` 处,调用 `#write(Object msg, boolean flush, ChannelPromise promise)` 方法,传入的 `flush = true` 方法参数,表示 write 操作的同时,**后续**需要执行 flush 操作。代码如下:
```
private void write(Object msg, boolean flush, ChannelPromise promise) {
// 获得下一个 Outbound 节点
AbstractChannelHandlerContext next = findContextOutbound();
// 简化代码 😈
// 执行 write + flush 操作
next.invokeWriteAndFlush(m, promise);
}
private void invokeWriteAndFlush(Object msg, ChannelPromise promise) {
if (invokeHandler()) {
// 执行 write 事件到下一个节点
invokeWrite0(msg, promise);
// 执行 flush 事件到下一个节点
invokeFlush0();
} else {
writeAndFlush(msg, promise);
}
}
```
- 在后面,就是 [《精尽 Netty 源码解析 —— Channel之 write 操作》](http://svip.iocoder.cn/Netty/Channel-4-write/) 的 [「5. HeadContext」](https://svip.iocoder.cn/Netty/Channel-6-writeAndFlush/#) 的小节及其后续的小节。
- 再在后面,就是 [《精尽 Netty 源码解析 —— Channel之 flush 操作》](http://svip.iocoder.cn/Netty/Channel-5-flush/) 。
# 666. 彩蛋
😈 真的是水更,哈哈哈哈。
推荐阅读文章:
- 闪电侠 [《netty 源码分析之 writeAndFlush 全解析》](https://www.jianshu.com/p/feaeaab2ce56) 的 [「writeAndFlush: 写队列并刷新」](https://svip.iocoder.cn/Netty/Channel-6-writeAndFlush/#) 小节。