netty实战笔记 第六章 ChannelHandler和ChannelPipeline

秒速五厘米 2022-04-04 10:28 390阅读 0赞

6.1 ChannelHandler家族

6.1.1 Channel的生命周期

Channel有四种状态.如下;


























状态 描述
channelUnregistered channel已经被创建,但还未注册到EventLoop
ChannelRegistered Channel已经被注册到了EventLoop
ChannelActive Channel处于活动状态(已经连接到它的远程节点),它现在可以接受和发送数据
ChannelInactive Channel没有连接到远程节点

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 条评论,390人围观)

还没有评论,来说两句吧...

相关阅读