ChannelPipeline

ChannelPipeline 是一系列的ChannelHandler 实例,用于拦截 流经一个 Channel 的入站和出站事件,ChannelPipeline允许用户自己定义对入站/出站事件的处理逻辑,以及pipeline里的各个Handler之间的交互。

每一次创建了新的Channel ,都会新建一个新的 ChannelPipeline并绑定到Channel上。这个关联是 永久性的;Channel 既不能附上另一个 ChannelPipeline 也不能分离 当前这个。这些都由Netty负责完成,而无需开发人员的特别处理。

根据它的起源,一个事件将由 ChannelInboundHandler 或 ChannelOutboundHandler 处理。随后它将调用 ChannelHandlerContext 实现转发到下一个相同的超类型的处理程序。

ChannelHandlerContext

一个 ChannelHandlerContext 使 ChannelHandler 与 ChannelPipeline 和 其他处理程序交互。一个处理程序可以通知下一个 ChannelPipeline 中的 ChannelHandler 甚至动态修改 ChannelPipeline 的归属。

下图展示了用于入站和出站 ChannelHandler 的 典型 ChannelPipeline 布局。

channelpipeline\_1.png

Figure 6.2 ChannelPipeline and ChannelHandlers

上图说明了 ChannelPipeline 主要是一系列 ChannelHandler。通过ChannelPipeline ChannelPipeline 还提供了方法传播事件本身。如果一个入站事件被触发,它将被传递的从 ChannelPipeline 开始到结束。举个例子,在这个图中出站 I/O 事件将从 ChannelPipeline 右端开始一直处理到左边。

ChannelPipeline 相对论

你可能会说,从 ChannelPipeline 事件传递的角度来看,ChannelPipeline 的“开始” 取决于是否入站或出站事件。然而,Netty 总是指 ChannelPipeline 入站口(图中的左边)为“开始”,出站口(右边)作为“结束”。当我们完成使用 ChannelPipeline.add() 添加混合入站和出站处理程序,每个 ChannelHandler 的“顺序”是它的地位从“开始”到“结束”正如我们刚才定义的。因此,如果我们在图6.1处理程序按顺序从左到右第一个ChannelHandler被一个入站事件将是#1,第一个处理程序被出站事件将是#5*

随着管道传播事件,它决定下个 ChannelHandler 是否是相匹配的方向运动的类型。如果没有,ChannelPipeline 跳过 ChannelHandler 并继续下一个合适的方向。记住,一个处理程序可能同时实现ChannelInboundHandler 和 ChannelOutboundHandler 接口。

修改 ChannelPipeline

ChannelHandler 可以实时修改 ChannelPipeline 的布局,通过添加、移除、替换其他 ChannelHandler(也可以从 ChannelPipeline 移除 ChannelHandler 自身)。这个 是 ChannelHandler 重要的功能之一。

Table 6.6 ChannelHandler methods for modifying a ChannelPipeline

名称 描述
addFirstaddBeforeaddAfteraddLast 添加ChannelHandler到ChannelPipeline.
Remove 从ChannelPipeline移除ChannelHandler.
Replace 在ChannelPipeline替换另外一个ChannelHandler

下面展示了操作

Listing 6.5 Modify the ChannelPipeline

ChannelPipeline pipeline = null; // get reference to pipeline;
FirstHandler firstHandler = new FirstHandler(); //1
pipeline.addLast("handler1", firstHandler); //2
pipeline.addFirst("handler2", new SecondHandler()); //3
pipeline.addLast("handler3", new ThirdHandler()); //4
pipeline.remove("handler3"); //5
pipeline.remove(firstHandler); //6
pipeline.replace("handler2", "handler4", new ForthHandler()); //6
  1. 创建一个 FirstHandler 实例
  2. 添加该实例作为 “handler1” 到 ChannelPipeline
  3. 添加 SecondHandler 实例作为 “handler2” 到 ChannelPipeline 的第一个槽,这意味着它将替换之前已经存在的 “handler1”
  4. 添加 ThirdHandler 实例作为”handler3” 到 ChannelPipeline 的最后一个槽
  5. 通过名称移除 “handler3”
  6. 通过引用移除 FirstHandler (因为只有一个,所以可以不用关联名字 “handler1”).
  7. 将作为”handler2”的 SecondHandler 实例替换为作为 “handler4”的 FourthHandler

以后我们将看到,这种轻松添加、移除和替换 ChannelHandler 能力, 适合非常灵活的实现逻辑。

ChannelHandler 执行 ChannelPipeline 和阻塞

通常每个 ChannelHandler 添加到 ChannelPipeline 将处理事件 传递到 EventLoop( I/O 的线程)。至关重要的是不要阻塞这个线程, 它将会负面影响的整体处理I/O。 有时可能需要使用阻塞 api 接口来处理遗留代码。对于这个情况下,ChannelPipeline 已有 add() 方法,它接受一个EventExecutorGroup。如果一个定制的 EventExecutorGroup 传入事件将由含在这个 EventExecutorGroup 中的 EventExecutor之一来处理,并且从 Channel 的 EventLoop 本身离开。一个默认实现,称为来自 Netty 的 DefaultEventExecutorGroup

除了上述操作,其他访问 ChannelHandler 的方法如下:

Table 6.7 ChannelPipeline operations for retrieving ChannelHandlers

名称 描述
get(…) ReturnaChannelHandlerbytypeorname
context(…) ReturntheChannelHandlerContextboundtoaChannelHandler.
names()iterator() ReturnthenamesorofalltheChannelHanderintheChannelPipeline.

发送事件

ChannelPipeline API 有额外调用入站和出站操作的方法。下表列出了入站操作,用于通知 ChannelPipeline 中 ChannelInboundHandlers 正在发生的事件

Table 6.8 Inbound operations on ChannelPipeline

名称 描述
fireChannelRegistered CallschannelRegistered(ChannelHandlerContext)onthenextChannelInboundHandlerintheChannelPipeline.
fireChannelUnregistered CallschannelUnregistered(ChannelHandlerContext)onthenextChannelInboundHandlerintheChannelPipeline.
fireChannelActive CallschannelActive(ChannelHandlerContext)onthenextChannelInboundHandlerintheChannelPipeline.
fireChannelInactive CallschannelInactive(ChannelHandlerContext)onthenextChannelInboundHandlerintheChannelPipeline.
fireExceptionCaught CallsexceptionCaught(ChannelHandlerContext,Throwable)onthenextChannelHandlerintheChannelPipeline.
fireUserEventTriggered CallsuserEventTriggered(ChannelHandlerContext,Object)onthenextChannelInboundHandlerintheChannelPipeline.
fireChannelRead CallschannelRead(ChannelHandlerContext,Objectmsg)onthenextChannelInboundHandlerintheChannelPipeline.
fireChannelReadComplete CallschannelReadComplete(ChannelHandlerContext)onthenextChannelStateHandlerintheChannelPipeline.

在出站方面,处理一个事件将导致底层套接字的一些行动。下表列出了ChannelPipeline API 出站的操作。

Table 6.9 Outbound operations on ChannelPipeline

名称 描述
bind BindtheChanneltoalocaladdress.Thiswillcallbind(ChannelHandlerContext,SocketAddress,ChannelPromise)onthenextChannelOutboundHandlerintheChannelPipeline.
connect ConnecttheChanneltoaremoteaddress.Thiswillcallconnect(ChannelHandlerContext,SocketAddress,ChannelPromise)onthenextChannelOutboundHandlerintheChannelPipeline.
disconnect DisconnecttheChannel.Thiswillcalldisconnect(ChannelHandlerContext,ChannelPromise)onthenextChannelOutboundHandlerintheChannelPipeline.
close ClosetheChannel.Thiswillcallclose(ChannelHandlerContext,ChannelPromise)onthenextChannelOutboundHandlerintheChannelPipeline.
deregister DeregistertheChannelfromthepreviouslyassignedEventExecutor(theEventLoop).Thiswillcallderegister(ChannelHandlerContext,ChannelPromise)onthenextChannelOutboundHandlerintheChannelPipeline.
flush FlushallpendingwritesoftheChannel.Thiswillcallflush(ChannelHandlerContext)onthenextChannelOutboundHandlerintheChannelPipeline.
write WriteamessagetotheChannel.Thiswillcallwrite(ChannelHandlerContext,Objectmsg,ChannelPromise)onthenextChannelOutboundHandlerintheChannelPipeline.Note:thisdoesnotwritethemessagetotheunderlyingSocket,butonlyqueuesit.TowriteittotheSocketcallflush()orwriteAndFlush().
writeAndFlush Conveniencemethodforcallingwrite()thenflush().
read RequeststoreadmoredatafromtheChannel.Thiswillcallread(ChannelHandlerContext)onthenextChannelOutboundHandlerintheChannelPipeline.

总结下:

  • 一个 ChannelPipeline 是用来保存关联到一个 Channel 的ChannelHandler
  • 可以修改 ChannelPipeline 通过动态添加和删除 ChannelHandler
  • ChannelPipeline 有着丰富的API调用动作来回应入站和出站事件。

看完两件小事

如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:

  1. 关注我们的 GitHub 博客,让我们成为长期关系
  2. 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
  3. 关注公众号 「方志朋」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程

JS中文网是中国领先的新一代开发者社区和专业的技术媒体,一个帮助开发者成长的社区,目前已经覆盖和服务了超过 300 万开发者,你每天都可以在这里找到技术世界的头条内容。欢迎热爱技术的你一起加入交流与学习,JS中文网的使命是帮助开发者用代码改变世界

results matching ""

    No results matching ""