netty Handler介绍

01-09 1487人

ChannelHandler是netty中核心

  1. public interface ChannelHandler {  
  2.   
  3.     /** 
  4.      * Gets called before the {@link ChannelHandler} is added to the actual context. 
  5.      */  
  6.     void beforeAdd(ChannelHandlerContext ctx) throws Exception;  
  7.   
  8.     /** 
  9.      * Gets called after the {@link ChannelHandler} was added to the actual context. 
  10.      */  
  11.     void afterAdd(ChannelHandlerContext ctx) throws Exception;  
  12.   
  13.     /** 
  14.      * Gets called before the {@link ChannelHandler} is removed from the actual context. 
  15.      */  
  16.     void beforeRemove(ChannelHandlerContext ctx) throws Exception;  
  17.   
  18.     /** 
  19.      * Gets called after the {@link ChannelHandler} was removed from the actual context. 
  20.      */  
  21.     void afterRemove(ChannelHandlerContext ctx) throws Exception;  
  22.   
  23.     /** 
  24.      * Gets called if a {@link Throwable} was thrown. 
  25.      */  
  26.     void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;  
  27.   
  28.     /** 
  29.      * Gets called if an user event was triggered. 
  30.      */  
  31.     void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception;  
  32. }  

这里略去一个注解的声明--Sharable 
同时我没有列出对这个接口的注释。其实这个注释是3.5的还没更新。因为3.5到4.0还是有很大不同,我们来看看。 
一个handler的接口,应该是定义我们应该处理一些什么情况见函数: 
  1. /** 
  2.    * Gets called if an user event was triggered. 
  3. */  
  4. oid userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception;  

ChannelHandler 定义了事件接口。在仔细看这些事件接口,我们可以发现,都有一个ChannelHanderContext,注释中也说明,handler是注册到了ChannelHanderContext上的。所以,我们就看看ChannelHanderContext类吧。 
Java代码  收藏代码
  1. public interface ChannelHandlerContext  
  2.          extends AttributeMap, ChannelPropertyAccess,  
  3.                  ChannelInboundInvoker, ChannelOutboundInvoker {  
  4. ...  
  5. }  


这里的ChannelInboundInvoker接口基本上就是拥有通知Channel上的各种事件的能力,二ChannelOutboundInvoker则是具备了向管道外写数据,连接等功能。注意返回值都是ChannelFuture这就说明这些操作都是异步的。 
总之ChannelOutboundInvoker是Channel,ChannelhandlerContext, ChannelPipeline的父接口。 
好了,不要跑题了。对于ChannelHandlerContext来说,基本上就是对传输过程中的各个方面的管理器。包括ChannelHandler的注册销毁等等。 

而对于ChannelHandler来说,有很多很多子接口,实现类。具体来说可通过ChannelHandlerType可以分为2类,4个type 
Java代码  收藏代码
  1. public enum ChannelHandlerType {  
  2.     STATE(0),  
  3.     INBOUND(0),  
  4.     OPERATION(1),  
  5.     OUTBOUND(1);  
  6.   
  7.     final int direction; // 0 - up (inbound), 1 - down (outbound)  
  8.   
  9.     ChannelHandlerType(int direction) {  
  10.         if (direction != 0 && direction != 1) {  
  11.             throw new IllegalArgumentException("direction must be either 0 or 1");  
  12.         }  
  13.         this.direction = direction;  
  14.     }  
  15. }  


从这里可以看到,每个ChannelHander都是有方向性的。这里的方向性,也就是管道中inbound和outbound的意思。所以ChannelHander的两个子接口 ChannelOperationHandler 也就是outbound 和ChannelStateHandler 也就是inbound。围绕着in与out,又催生出子接口 ChannelOutboundHandler 和 ChannelInboundHandler。再下来,就是各种处理,基本不外乎 byte和message之间的转换。 

这里有很多两个常用的Adapter, 
  • ChannelInboundMessageHandlerAdapter<T>
  • ChannelInboundByteHandlerAdapter


对于ChannelInboundMessageHandlerAdapter<T>最主要的就是当消息到来时的处理,函数: 
public void messageReceived(ChannelHandlerContext ctx, I msg) throws Exception; 
将由用户去实现。 

而对于ChannelInboundByteHandlerAdapter来说,函数和ChannelStateHandler的接口类似,被封装成: 
/** 
     * Callback which will get notifed once the given {@link ByteBuf} received more data to read. What will be done 
     * with the data at this point is up to the implementation. 
     * Implementations may choose to read it or just let it in the buffer to read it later. 
     */ 
    public abstract void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception; 


那么,handler是如何在事件发生时被调用的呢? 
其实这应该是ChannelHandlerContext 告诉handler的,我们看下DefaultChannelHandlerContext就知道了。ChannelHandlerContext接口不具备了事件通知功能,也具备了管道的能力。 

从DefaultChannelHandlerContext构造函数看 
  DefaultChannelHandlerContext( 
            DefaultChannelPipeline pipeline, EventExecutorGroup group, 
            DefaultChannelHandlerContext prev, DefaultChannelHandlerContext next, 
            String name, ChannelHandler handler) 
最主要的几个成员变量就是这几个参数。从prev和next我们可以初步判断出这个ChannelHandlerContext 并不是单一出现的,而是linked的。 

在来看pipeline,也有一个实现类DefaultChannelPipeline,构造函数为: 
  public DefaultChannelPipeline(Channel channel) 
这也看得出这是对一个Channel的封装。再看成员变量,有 
Java代码  收藏代码
  1. final DefaultChannelHandlerContext head;  
  2.    private volatile DefaultChannelHandlerContext tail;  
  3.    private final Map<String, DefaultChannelHandlerContext> name2ctx =  
  4.        new HashMap<String, DefaultChannelHandlerContext>(4);  

于是猜到最终的ChannelHandlerContext是在这里生成的,而且是链式的。 
来看看我们最常用的函数 addFirst 
Java代码  收藏代码
  1. @Override  
  2. public ChannelPipeline addFirst(String name, ChannelHandler handler) {  
  3.     return addFirst(null, name, handler);  
  4. }  
  5.   
  6. @Override  
  7. public ChannelPipeline addFirst(EventExecutorGroup group, final String name, ChannelHandler handler) {  
  8.     final DefaultChannelHandlerContext nextCtx;  
  9.     final DefaultChannelHandlerContext newCtx;  
  10.   
  11.     synchronized (this) {  
  12.         checkDuplicateName(name);  
  13.         nextCtx = head.next;  
  14.         newCtx = new DefaultChannelHandlerContext(this, group, head, nextCtx, name, handler);  
  15.   
  16.         if (!newCtx.channel().isRegistered() || newCtx.executor().inEventLoop()) {  
  17.             addFirst0(name, nextCtx, newCtx);  
  18.             return this;  
  19.         }  
  20.     }  
  21.   
  22.     // Run the following 'waiting' code outside of the above synchronized block  
  23.     // in order to avoid deadlock  
  24.   
  25.     newCtx.executeOnEventLoop(new Runnable() {  
  26.             @Override  
  27.             public void run() {  
  28.                 synchronized (DefaultChannelPipeline.this) {  
  29.                     checkDuplicateName(name);  
  30.                     addFirst0(name, nextCtx, newCtx);  
  31.                 }  
  32.             }  
  33.         });  
  34.   
  35.     return this;  
  36. }  
  37.   
  38. private void addFirst0(  
  39.         final String name, DefaultChannelHandlerContext nextCtx, DefaultChannelHandlerContext newCtx) {  
  40.     callBeforeAdd(newCtx);  
  41.   
  42.     if (nextCtx != null) {  
  43.         nextCtx.prev = newCtx;  
  44.     }  
  45.     head.next = newCtx;  
  46.     if (tail == head) {  
  47.         tail = newCtx;  
  48.     }  
  49.   
  50.     name2ctx.put(name, newCtx);  
  51.   
  52.     callAfterAdd(newCtx);  
  53. }  

这里基本就是对链表的处理了。DefaultChannelHandlerContext中还定义了一些事件任务。这些任务都是在EventLoop中提交的。使用EventExecutor。这些事件是用来通知链上的下一个ChannelHandlerContext,具体是什么需要看handler的方向了。 

至此,ChannelHandler就差不多了,接下来该看看EventLoop是如何工作的了。


	
色迷迷 哭 呕吐 大笑 口水 微笑 啵一个 发怒

Hi,您需要填写昵称和邮箱!

  • 必填项
  • 必填项