netty源码分析之-Channel、ChannelPipeline、ChannelHandler以及 ChannelHandlerContext 详解(2)

Channel

在netty中Channel表示能够用来进行I/O操作例如读、写、连接、绑定等的一个网络socket或者一种组件。Netty的Channel接口所提供的API大大地降低来直接使用Socket类的复杂性。该提供了以下功能:

  1. 当前Channel的状态(是否打开,是否已经连接)
  2. 提供与Channel相关的配置参数(接受的buffer大小)
  3. 进行Channel所支持的I/O操作
  4. 获取与该channel相关能够处理所有的I/O事件和请求的ChannelPipeline

在netty中所有相关的I/O操作一定能够是异步的,意味着所有的I/O调用将立即返回,但是无法保证请求的I/O操作一定是完成。可以通过返回的ChannelFuture实例来获取当I/O操作成功、失败或者取消后的通知。

在AbstractBootstrap.java中:

final ChannelFuture initAndRegister() {
        Channel channel = null;
        try {
            channel = channelFactory.newChannel();
            init(channel);
            ...
}

Channel的生命周期:

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

状态模型:
netty源码分析之-Channel、ChannelPipeline、ChannelHandler以及 ChannelHandlerContext 详解(2)_第1张图片

ChannelHandler

ChannelHandler用来处理I/O事件或者拦截I/O操作。并且传递到它所属ChannelPipeline中的下一个handler。ChannelHandler本身没有提供很多方法,一般都是通过实现它的一些子类

ChannelHandler生命周期:

状态 描述
handlerAdded 当把 ChannelHandler 添加到 ChannelPipeline 中时被调用
handlerRemoved 当从 ChannelPipeline 中移除 ChannelHandler 时被调用
exceptionCaught 当处理过程中在 ChannelPipeline 中有错误产生时被调用

Netty 定义了下面两个重要的 ChannelHandler 子接口:

  1. ChannelInboundHandler——处理入站数据以及各种状态变化;
  2. ChannelOutboundHandler——处理出站数据并且允许拦截所有的操作

ChannelPipeline

在netty中:

public interface ChannelPipeline
extends io.netty.channel.ChannelInboundInvoker, io.netty.channel.ChannelOutboundInvoker, Iterable<java.util.Map.Entry<String, io.netty.channel.ChannelHandler>>

ChannelPipeline表示用来处理或者拦截一个Channel相关的inbound或者outbound操作的 一系列ChannelHandler(双向链表来维护)。ChannelPipeline实现了高级的拦截过滤器功能(传统的拦截器,只能是输入输出都控制或者两者都不控制,ChannelPipeline将输入与输出的控制分离开,可以按需控制),让用户能够完全控制一个事件是如何被处理,以及在pipeline中的各个ChannelHandler之间是如何联系(通过ChannelHandlerContext中的传播策略)。每个channel在新建的时候都会自动创建与之相关的一个pipeline。实现了ChannelInboundHandle的ChannelHandle只会控制输入,实现了ChannelOutboundHandler的ChannelHandle只会控制输出,如果两者都实现将会同时控制输入输出。

 static final EventExecutorGroup group = new DefaultEventExecutorGroup(16);
   ...

   ChannelPipeline pipeline = ch.pipeline();

   pipeline.addLast("decoder", new MyProtocolDecoder());
   pipeline.addLast("encoder", new MyProtocolEncoder());

   // Tell the pipeline to run MyBusinessLogicHandler's event handler methods
   // in a different thread than an I/O thread so that the I/O thread is not blocked by
   // a time-consuming task.
   // If your business logic is fully asynchronous or finished very quickly, you don't
   // need to specify a group.
   pipeline.addLast(group, "handler", new MyBusinessLogicHandler());

如果自己实现的ChannelHandle是很耗时的任务,那么不应该将该操作放入I/O线程中去执行。可以通过上述新建一个执行事件组(多线程)来单独执行该任务,或者可以通过在conrete handle event中定义自己的线程池来完成。

  1. ChannelPipeline 保存了与 Channel 相关联的 ChannelHandler;
  2. ChannelPipeline 可以根据需要,通过添加或者删除 ChannelHandler 来动态地修改;
  3. ChannelPipeline 有着丰富的 API 用以被调用,以响应入站和出站事件。

ChannelHandlerContext

当 ChannelHandler 被添加到 ChannelPipeline 时,它将会被分配一个 ChannelHandlerContext,其代表了 ChannelHandler 和 ChannelPipeline 之间的绑定。虽然这个对象可 以被用于获取底层的 Channel,但是它主要还是被用于写出站数据。通过使用作为参数传递到每个方法的 ChannelHandlerContext,事件可以被传递给当前ChannelHandler 链中的下一个 ChannelHandler。通过调 用 ChannelHandlerContext 上的对应方法,每个都提供了简单地将事件传递给下一个 ChannelHandler 的方法的实现。

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

在Netty中,有两种发送消息的方式。你可以直接写到Channel中,也可以 写到和Channel- Handler 相关联的 ChannelHandlerContext 对象中。前一种方式将会导致消息从 Channel- Pipeline 的尾端开始流动,而后者将导致消息从 ChannelPipeline 中的下一个 Channel- Handler 开始流动。

  1. ChannelHandlerContext 和 ChannelHandler之间的关联(绑定)是永远不会改变的,所以缓存对它的引用是安全的;
  2. 相对于其他类的同名方法,ChannelHandler Context的方法将产生更短的事件流,应该尽可能地利用这个特性来获得最大的性能。

Channel、ChannelPipeline、ChannelHandler以及 ChannelHandlerContext 之间的关系

netty源码分析之-Channel、ChannelPipeline、ChannelHandler以及 ChannelHandlerContext 详解(2)_第2张图片

你可能感兴趣的:(netty)