zoukankan      html  css  js  c++  java
  • netty入门01

    Netty4

    Netty是一个和MINA类似的Java NIO框架,目前的最新版本是4.0.13,这两个框架的主要作者好像都是同一个韩国人


    Channel

    Channel是Netty最核心的接口,一个Channel就是一个联络Socket的通道,通过Channel,你可以对Socket进行各种操作。


    ChannelHandler

    用Netty编写网络程序的时候,你很少直接操纵Channel,而是通过ChannelHandler来间接操纵Channel。


    ChannelPipeline

    ChannelPipeline实 际上应该叫做ChannelHandlerPipeline,可以把ChannelPipeline看成是一个ChandlerHandler的链表,当 需要对Channel进行某种处理的时候,Pipeline负责依次调用每一个Handler进行处理。每个Channel都有一个属于自己的 Pipeline,调用Channel#pipeline()方法可以获得Channel的Pipeline,调用Pipeline#channel()方法可以获得Pipeline的Channel。

    ChannelPipeline的方法有很多,其中一部分是用来管理ChannelHandler的,如下面这些:

    1. ChannelPipeline addFirst(String name, ChannelHandler handler);  
    2. ChannelPipeline addLast(String name, ChannelHandler handler);  
    3. ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler);  
    4. ChannelPipeline addAfter(String baseName, String name, ChannelHandler handler);  
    5. ChannelPipeline remove(ChannelHandler handler);  
    6. ChannelHandler remove(String name);  
    7. ChannelHandler removeFirst();  
    8. ChannelHandler removeLast();  
    9. ChannelPipeline replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler);  
    10. ChannelHandler replace(String oldName, String newName, ChannelHandler newHandler);  
    11. ChannelHandler first();  
    12. ChannelHandler last();  
    13. ChannelHandler get(String name);  

    根据上面的方法,能够大概想象的到Pipeline按照什么样的方式组织Handler。

    ChannelHandlerContext

    ChannelPipeline并不是直接管理ChannelHandler,而是通过ChannelHandlerContext来间接管理,这一点通过ChannelPipeline的默认实现DefaultChannelPipeline可以看出来。

    调用ChannelHandlerContext#channel()方法可以得到和Context绑定的Channel,调用ChannelHandlerContext#handler()方法可以得到和Context绑定的Handler。


    ChannelPipeline和ChannelHandlerContext默认实现

    DefaultChannelHandlerContext和DefaultChannelPipeline是ChannelHandlerContext和ChannelPipeline的默认实现,下面是它们的部分代码:

    1. final class DefaultChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext {  
    2.   
    3.     volatile DefaultChannelHandlerContext next;  
    4.     volatile DefaultChannelHandlerContext prev;  
    5.   
    6.     private final boolean inbound;  
    7.     private final boolean outbound;  
    8.     private final AbstractChannel channel;  
    9.     private final DefaultChannelPipeline pipeline;  
    10.     private final String name;  
    11.     private final ChannelHandler handler;  
    12.     private boolean removed;  
    13.   
    14.     // ...  
    15. }  
    1. final class DefaultChannelPipeline implements ChannelPipeline {  
    2.     // ...  
    3.   
    4.     final DefaultChannelHandlerContext head;  
    5.     final DefaultChannelHandlerContext tail;  
    6.   
    7.     // ...  
    8. }  


    从上面的代码可以看出,在DefaultPipeline内部,DefaultChannelHandlerContext组成了一个双向链表:

    再来看看DefaultChannelPipeline的构造函数:

    1. public DefaultChannelPipeline(AbstractChannel channel) {  
    2.     if (channel == null) {  
    3.         throw new NullPointerException("channel");  
    4.     }  
    5.     this.channel = channel;  
    6.   
    7.     TailHandler tailHandler = new TailHandler();  
    8.     tail = new DefaultChannelHandlerContext(this, null, generateName(tailHandler), tailHandler);  
    9.   
    10.     HeadHandler headHandler = new HeadHandler(channel.unsafe());  
    11.     head = new DefaultChannelHandlerContext(this, null, generateName(headHandler), headHandler);  
    12.   
    13.     head.next = tail;  
    14.     tail.prev = head;  
    15. }  


    可以看到,DefaultChinnelPipeline内部使用了两个特殊的Handler来表示Handler链的头和尾:


    ChannelHandler的种类

    从上面DefaultChannelHandlerContext代码可以知道,Handler实际上分为两种,Inbound和Outbound,这一点也可以从ChannelHandler接口的子接口得到证明:

    1. public interface ChannelInboundHandler extends ChannelHandler {  
    2.   // ...  
    3. }  
    4.   
    5. public interface ChannelOutboundHandler extends ChannelHandler {  
    6.   // ...  
    7. }  

    事件的传播

    为了搞清楚事件如何在Pipeline里传播,让我们从Channel的抽象子类AbstractChannel开始,下面是AbstractChannel#write()方法的实现:

    1. public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {  
    2.     // ...  
    3.     @Override  
    4.     public Channel write(Object msg) {  
    5.         return pipeline.write(msg);  
    6.     }  
    7.     // ...  
    8. }  


    AbstractChannel直接调用了Pipeline的write()方法:


    再看DefaultChannelPipeline的write()方法实现:

    1. final class DefaultChannelPipeline implements ChannelPipeline {  
    2.     // ...  
    3.     @Override  
    4.     public ChannelFuture write(Object msg) {  
    5.         return tail.write(msg);  
    6.     }  
    7.     // ...  
    8. }  


    因为write是个outbound事件,所以DefaultChannelPipeline直接找到tail部分的context,调用其write()方法:


    接着看DefaultChannelHandlerContext的write()方法:

    1. final class DefaultChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext {  
    2.     // ...  
    3.     @Override  
    4.     public ChannelFuture write(Object msg) {  
    5.         return write(msg, newPromise());  
    6.     }  
    7.   
    8.     @Override  
    9.     public ChannelFuture write(final Object msg, final ChannelPromise promise) {  
    10.         if (msg == null) {  
    11.             throw new NullPointerException("msg");  
    12.         }  
    13.   
    14.         validatePromise(promise, true);  
    15.   
    16.         write(msg, false, promise);  
    17.   
    18.         return promise;  
    19.     }  
    20.   
    21.     private void write(Object msg, boolean flush, ChannelPromise promise) {  
    22.         DefaultChannelHandlerContext next = findContextOutbound();  
    23.         next.invokeWrite(msg, promise);  
    24.         if (flush) {  
    25.             next.invokeFlush();  
    26.         }  
    27.     }  
    28.   
    29.     private DefaultChannelHandlerContext findContextOutbound() {  
    30.         DefaultChannelHandlerContext ctx = this;  
    31.         do {  
    32.             ctx = ctx.prev;  
    33.         } while (!ctx.outbound);  
    34.         return ctx;  
    35.     }  
    36.   
    37.     private void invokeWrite(Object msg, ChannelPromise promise) {  
    38.         try {  
    39.             ((ChannelOutboundHandler) handler).write(this, msg, promise);  
    40.         } catch (Throwable t) {  
    41.             notifyOutboundHandlerException(t, promise);  
    42.         }  
    43.     }  
    44.   
    45.     // ...  
    46. }  


    context的write()方法沿着context链往前找,直至找到一个outbound类型的context为止,然后调用其invokeWrite()方法:


    invokeWrite()接着调用handler的write()方法:

    最后看看ChannelOutboundHandlerAdapter的write()方法实现:

    1. public class ChannelOutboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelOutboundHandler {  
    2.     // ...  
    3.     @Override  
    4.     public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {  
    5.         ctx.write(msg, promise);  
    6.     }  
    7.     // ...  
    8. }  


    默认的实现调用了context的write()方法而不做任何处理,这样write事件就沿着outbound链继续传播:


    可见,Pipeline的事件传播,是靠Pipeline,Context和Handler共同协作完成的。


  • 相关阅读:
    pause
    vim 修改复制过来的代码缩进
    解决TeamViewer提示商业用途
    服务器上安装解决ole错误
    vs密匙
    oracle11g忘记管理员密码
    sql同时删除多个表的数据
    删除表中多余的重复记录(多个字段),只留有rowid最小的记录
    查找表中多余的重复记录(多个字段)
    删除表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断,只留有rowid最小的记录
  • 原文地址:https://www.cnblogs.com/xdrlczj/p/5845720.html
Copyright © 2011-2022 走看看