netty实战笔记 第六章 ChannelHandler和ChannelPipeline

6.1 ChannelHandler家族

6.1.1 Channel的生命周期

Channel有四种状态.如下;

状态描述
channelUnregisteredchannel已经被创建,但还未注册到EventLoop
ChannelRegisteredChannel已经被注册到了EventLoop
ChannelActiveChannel处于活动状态(已经连接到它的远程节点),它现在可以接受和发送数据
ChannelInactiveChannel没有连接到远程节点
6.1.2 ChannelHandler的生命周期

ChannelHandler有三个状态。在ChannelHandler被添加到ChannelPipeline中或者被移除时调用这些操作。
| 类型 | 描述 |
| handlerAdded | 当把ChannelHandler添加到ChannelPipeline中时被调用|
| handlerRemoved | 当从ChannelPipeline中移除ChannelHandler的时候调用|
| exceptionCaught | 当处理过程中在ChannelPipeline中有错误产生的时候调用 |

两个子类:ChanneInboundHandler,ChannelOutboundHandler

6.1.3 ChannelInboundHandler 接口

处理入站数据以及各种状态变化
将在数据被接受的时候或者与其对应的Channel状态发生改变的时候调用。如下:

类型(对应着方法名)描述
channelRegistered当channel已经注册到它的EventLoop并且能处理IO时调用
channelUnregistered当channel从它的EventLoop注销并且无法处理任何IO时被调用
channelActive当channel处理活动状态时被调用,channel已经连接/绑定并且已经就绪
channeInactive当channel离开活动状态并且不再连接他的远程节点时调用
ChannelReadComplete当channel上的一个读操作完成时被调用
channelRead当从channel中读取数据时候被调用
channelWritabilityChanged当channel的可写状态发生改变时被调用。用户可以确保写操作不会完成的太快,或者可以在Channel变为再次可写时恢复写入.可以通过Channel的isWritable()方法来检测channel的可写性。与可写性相关的阈值可以通过channel.config().setWriteHighWaterMark()和channel.config().setWriteLowWaterMark()方法来设置。
userEventTriggered当channelInboundHandler.fireUseEventtriggered()方法被调用时被调用,应为一个POJO被传经了ChannelPipeline。

当某个ChannelInboundHandler的实现重写了channelRead()方法时,它将显示的释放与池化的Bytebuf相关的内存。

6.1.4 ChannelOutboundHandler接口

处理出站操作和数据。 其方法将被Channel,channelPipeline,已经ChannelHandlerContext调用。
其可以按需推迟操作或者事件,可以通过一些复杂的方法来处理请求。

类型描述
bind(ChannelHandlerContext,SocketAddress,ChannelPromis)当请求Channel绑定到本地地址时调用
connect(ChannelHandlerContext,SocketAddress,SocketAddress,ChannelPromise)当请求将Channel连接到远程节点的时候被调用
disconnect(ChannlelHandlerContext,ChannelPormise)当请求将Channel从远程节点断开的时候被调用
close(ChannelHandlerContext ,ChannelPromise)
当请求关闭Channel的时候被调用
deregister(ChannelHandlerContext,ChannelPromise)当请求将从他的EventLoop注销时被调用
read(ChannelHandlerContext)当请求从Channel读取更多数据的时候被调用
flush(ChannelHandlerContext)当请求通过Channel将入队数据冲刷到远程节点的时候被调用
write(ChannelHandlerContext,Object,ChannelPromise)当请求通过Channel将数据写到远程节点的时候背调用

6.1.5 ChannelHandler适配器

ChannelHandlerAdapter提供给了isSharable(),如果对应的实现被注为Sharable,返回true

6.1.6 资源管理

Netty定义了4中泄露级别

级别描述
DISABLED禁止泄漏检测,只有在详尽的测试后才设置这个值
SIMPLE使用 1%的默认采样率检测并报告任何发现的泄露。这是默认级别,适合绝大部分的情况
ADVANCED使用默认的采样率,报告所发现的任何的泄露以及对应的消息被访问的位置
PARANOID类似于ADVANCED,但是其将会对每次(对消息的)访问都进行采样。这对性能将会有很
大的影响,应该只在调试阶段使用

6.2 ChannelPipeline接口

ChannelPipeline是一个连接流程Channel的入站和出站时间的ChannelHandler事件链。
每一个新创建的Channel都将被分配一个新的ChannelPipeline。Channel既不能附件另一个ChannelPipeline,也不能分离当前的。

ChannelHandlerContext使得ChannelHandler能够和它的ChannelPipeline以及其他的ChannelHandler 交互。ChannelHandler 可以通知其所属的ChannelPipeline 中的下一个ChannelHandler,甚至可以动态修改它所属的ChannelPipeline

6.2.1 修改ChannelPipeline

ChannelHandler可以通过添加,删除,或者替换其他的ChannleHandler来实时的修改ChannelPipeline的布局。

名称描述
addFirst,addBefore,addAfter,addLast将一个Channelhandler添加到ChannelPipeline
remove讲一个CHannelhandler从ChannelPipeline中删除
replace将ChannelPipeline中的一个ChannelHandler替换为另一个ChannelHandler

ChannelPipeline的访问CHannelHandler的方法。

名称描述
get通过类型或者名称返回ChannelHandler
context返回和ChannelHandler绑定的ChannelHandlerContext
names返回ChannellPipeline中所有ChannelHandler的名称
6.2.2 触发时间

用于通过ChannelInboundHandler在ChannelPipeline中发生的事件。

方法名称描述
fireChannelRegistered调用ChannelPipeline 中下一个ChannelInboundHandler 的channelRegistered(ChannelHandlerContext)方法
fireChannelUnregistered调用ChannelPipeline 中下一个ChannelInboundHandler 的channelUnregistered(ChannelHandlerContext)方法
fireChannelActive调用ChannelPipeline 中下一个ChannelInboundHandler 的channelActive(ChannelHandlerContext)方法
fireChannelInactive调用ChannelPipeline 中下一个ChannelInboundHandler 的channelInactiveChannelHandlerContext)方法
fireExceptionCaught调用ChannelPipeline 中下一个ChannelInboundHandler 的exceptionCaught(ChannelHandlerContext, Throwable)方法
fireUserEventTriggered调用ChannelPipeline 中下一个ChannelInboundHandler 的userEventTriggered(ChannelHandlerContext, Object)方法
fireChannelRead调用ChannelPipeline 中下一个ChannelInboundHandler 的channelRead(ChannelHandlerContext, Object msg)方法
fireChannelReadComplete调用ChannelPipeline 中下一个ChannelInboundHandler 的channelReadComplete(ChannelHandlerContext)方法
fireChannelWritability-Changed调用ChannelPipeline 中下一个ChannelInboundHandler 的channelWritabilityChanged(ChannelHandlerContext)方法

ChannelPipeline 的出站操作

方 法 名 称描 述
bind将Channel 绑定到一个本地地址,这将调用ChannelPipeline 中的下一个ChannelOutboundHandler 的bind(ChannelHandlerContext, Socket-Address, ChannelPromise)方法
connect将Channel 连接到一个远程地址,这将调用ChannelPipeline 中的下一个ChannelOutboundHandler 的connect(ChannelHandlerContext, SocketAddress, ChannelPromise)方法
disconnect将Channel 断开连接。这将调hannelPipeline 中的下一个ChannelOutbound-Handler 的disconnect(ChannelHandlerContext, Channel Promise)方法
close将Channel 关闭。这将调用ChannelPipeline 中的下一个ChannelOutbound-Handler 的closeChannelHandlerContext, ChannelPromise)方法
deregister将Channel 从它先前所分配的EventExecutor(即EventLoop)中注销。这将调用ChannelPipeline 中的下一个ChannelOutboundHandler 的deregister(ChannelHandlerContext, ChannelPromise)方法
flush冲刷Channel所有挂起的写入。这将调用ChannelPipeline 中的下一个Channel-OutboundHandler 的flush(ChannelHandlerContext)方法
write将消息写入Channel。这将调用ChannelPipeline 中的下一个Channel-OutboundHandler的write(ChannelHandlerContext, Object msg, Channel-Promise)方法。注意:这并不会将消息写入底层的Socket,而只会将它放入队列中。要将它写入Socket,需要调用flush()或者writeAndFlush()方法
writeAndFlush这是一个先调用write()方法再接着调用flush()方法的便利方法
read请求从Channel 中读取更多的数据。这将调用ChannelPipeline 中的下一个ChannelOutboundHandler 的read(ChannelHandlerContext)方法

6.3 ChannelHandlerContext接口

代表了ChannelHandler和ChannelPipeline之间的关联。
每当有ChannelHandler添加到ChannelPipeline中时,都会创建ChannelHandlerContext。
ChannelHandlerContext的主要功能是管理它所在的连接的ChannelHandler和在同一个ChannelPipeline中的其他的Channelhandler之间的交互。

下面的时候ChannelChandlerContext的API

方法名称描述
alloc返回和这个实例相关联的Channel 所配置的ByteBufAllocator
bind绑定到给定的SocketAddress,并返回ChannelFuture
channel返回绑定到这个实例的Channel
close关闭Channel,并返回ChannelFuture
connect连接给定的SocketAddress,并返回ChannelFuture
deregister从之前分配的EventExecutor 注销,并返回ChannelFuture
disconnect从远程节点断开,并返回ChannelFuture
executor返回调度事件的EventExecutor
fireChannelActive触发对下一个ChannelInboundHandler上的channelActive()方法(已连接)的调用
fireChannelInactive触发对下一个ChannelInboundHandler 上的channelInactive()方法(已关闭)的调用
fireChannelRead触发对下一个ChannelInboundHandler 上的channelRead()方法(已接收的消息)的调用
fireChannelReadComplete触发对下一个ChannelInboundHandler 上的channelReadComplete()方法的调用
fireChannelRegistered触发对下一个ChannelInboundHandler 上的fireChannelRegistered()方法的调用
fireChannelUnregistered触发对下一个ChannelInboundHandler上的fireChannelUnregistered()方法的调用
fireChannelWritabilityChanged触发对下一个ChannelInboundHandler 上的fireChannelWritabilityChanged()方法的调用
fireExceptionCaught触发对下一个ChannelInboundHandler 上的fireExceptionCaught(Throwable)方法的调用
fireUserEventTriggered触发对下一个ChannelInboundHandler 上的fireUserEventTriggered(Object evt)方法的调用
handler返回绑定到这个实例的ChannelHandler
isRemoved如果所关联的ChannelHandler 已经被从ChannelPipeline中移除则返回true
name返回这个实例的唯一名称
pipeline返回这个实例所关联的ChannelPipeline
read将数据从Channel读取到第一个入站缓冲区;如果读取成功则触发①一个channelRead事件,并(在最后一个消息被读取完成后)通知ChannelInboundHandler 的channelReadComplete
write通过这个实例写入消息并经过ChannelPipeline
writeAndFlush通过这个实例写入并冲刷消息并经过ChannelPipeline

注意

  • channelHandlerContext和ChannelHandler之间的关联是永远不会改变的,所以缓存对它的引用是安全的。

  • ChannelHandlerContext的方法将产生更短的事件流,应该尽可能的利用这个特性来获取最大的性能。

6.3.1 使用ChannelHandlerContext

先看下 ChannelHandlerContext,Channel,ChannelPipeline之间的关系。在这里插入图片描述
下面的是事件从一个ChannelHandler到下一个ChannelHandler 的移ChannelHandlerContext 上的调用完成的。在这里插入图片描述
[外链图片转存失败(img-vSQn27Q0-1567313402162)(…/…/_images/netty/20181214132452.png)]

通过ChannlHandlerContext的write()方法
在这里插入图片描述

6.3.2 ChannelHandler和ChannelHanderContext的高级用法

通过 调用ChannelHandlerContext上的pipeline()方法来获得被封闭的ChannelPipeline的引用。这使得运行时得以操作ChannelPipeline的ChannelHandler,依次我们可以实现比价复杂的内容。

因为一个ChannelHandler 可以从属于多个ChannelPipeline,所以它也可以绑定到多
个ChannelHandlerContext 实例。对于这种用法指在多个ChannelPipeline 中共享同一
个ChannelHandler,对应的ChannelHandler 必须要使用@Sharable 注解标注;否则,
试图将它添加到多个ChannelPipeline 时将会触发异常

6.4 异常处理

6.4.1 处理出站数据异常

  • ChannelHandler.exceptionCaught()的默认实现是简单地将当前异常转发给ChannelPipeline 中的下一个ChannelHandler;
  • 如果异常到达了ChannelPipeline 的尾端,它将会被记录为未被处理;
  • 要想定义自定义的处理逻辑,你需要重写exceptionCaught()方法。然后你需要决定
    是否需要将该异常传播出去。

6.4.2 处理出站数据异常

用于处理出站操作中的正常完成以及异常的选项,都基于以下的通知机制。

  • 每个出站操作都将返回一个ChannelFuture。注册到ChannelFuture 的Channel-
    FutureListener 将在操作完成时被通知该操作是成功了还是出错了。
  • 几乎所有的ChannelOutboundHandler 上的方法都会传入一个ChannelPromise
    的实例。作为ChannelFuture 的子类,ChannelPromise 也可以被分配用于异步通
    知的监听器。但是,ChannelPromise 还具有提供立即通知的可写方法:
ChannelPromise setSuccess();
Chan nelPromise setFailure(Throwable cause); 

添加ChannelFutureListener 只需要调用ChannelFuture 实例上的addListener(ChannelFutureListener)方法,并且有两种不同的方式可以做到这一点。其中最常用的方式是,调用出站操作(如write()方法)所返回的ChannelFuture 上的addListener()方法。第二种方式是将ChannelFutureListener 添加到即将作为参数传递给ChannelOutboundHandler的方法的ChannelPromise。

最后

如果你觉得写的还不错,就关注下公众号呗,关注后,有点小礼物回赠给你。
你可以获得5000+电子书,java,springCloud,adroid,python等各种视频教程,IT类经典书籍,各种软件的安装及破解教程。
希望一块学习,一块进步!
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

方_小_白

谢谢金主子,记得关注方家小白哦

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值