java netty之AbstractNioChannel

来源:互联网 发布:米思米 矩阵 编辑:程序博客网 时间:2024/06/05 23:19

前面的文章分析了eventloopgroup以及eventloop的继承体系,在这篇文章主要分析以下netty对channel的封装,我只对nio感兴趣,那么就只分析对nio这一部分的封装。。。。

主要来分析以下的继承体系:


channel是netty定义的顶层接口,其无非就是定义了一些基本的方法,例如返回当前channel所属的eventloop,判断channel是否已经打开,是否已经注册,本地地址,连接的远程地址等。

另外它还定义了一个十分重要的内部接口Unsfe,在这个里面的定义了一些具体的数据传输的方法,官方给出的注释给出的说明是:这里面定义的方法不应该被用户空间的代码所直接调用。。。

另外,channel还继承了AttributeMap,ChannelOutboundInvoker,ChannelPropertyAccess,Comparable接口。。。


接下来就是AbstractChannel,一个夹在中间的抽象类,它实现了一些基本的方法,另外还定义了一些属性,首先我们来看它定义的一些属性:

static final ConcurrentMap<Integer, Channel> allChannels = PlatformDependent.newConcurrentHashMap();   //静态属性,用于保存所有的channel,每个channel都对应一个负数的ID
allChannels是一个静态属性,是一个ConcurrentHashMap,主要是用于保存和管理当前存在的所有channel,它的索引是一个负数的ID


private final Channel parent;   //父channel    private final Integer id;   //当前channel的id    private final Unsafe unsafe;    //usafe对象    private final DefaultChannelPipeline pipeline;   //当前channel的pipeline    private final ChannelFuture succeededFuture = new SucceededChannelFuture(this, null);    private final VoidChannelPromise voidPromise = new VoidChannelPromise(this);    private final CloseFuture closeFuture = new CloseFuture(this);    //close时候用到的future    protected final ChannelFlushPromiseNotifier flushFutureNotifier = new ChannelFlushPromiseNotifier();    private volatile SocketAddress localAddress;   //本地地址    private volatile SocketAddress remoteAddress;   //连接的远程地址    private volatile EventLoop eventLoop;    //所属的eventloop    private volatile boolean registered;     //是否已经register

上述都是一些基本的属性定义,比较重要的有定义了一个Unsafe,以及pipeline,,我们可以来看一些AbstractChannel定义的构造方法:
    //abstractchannel的构造函数    protected AbstractChannel(Channel parent, Integer id) {        if (id == null) {            id = allocateId(this);   //为当前的channel分配一个负数的id        } else {            if (id.intValue() < 0) {                throw new IllegalArgumentException("id: " + id + " (expected: >= 0)");            }            if (allChannels.putIfAbsent(id, this) != null) {                throw new IllegalArgumentException("duplicate ID: " + id);            }        }        this.parent = parent;        this.id = id;        unsafe = newUnsafe();        pipeline = new DefaultChannelPipeline(this);    //构造pipeline        //为closefuture添加一个listeer,也就是close的时候将当前channel从allChannels中移除        closeFuture().addListener(new ChannelFutureListener() {            @Override            public void operationComplete(ChannelFuture future) {                allChannels.remove(id());            }        });    }
还是比较简单的,首先为当前的channel分配一个id,然后构造unsfae对象,以及pipeline对象,这里newUnsafe方法是一个抽象方法,也就意味着真正unsafe的定义还要延后到子类当中去,最后还未closeFuture添加了一个listener,当channel被关闭的时候将会被调用,操作也非常简单,无非就是从allChannels静态属性中将当前channel移除。。这样垃圾回收也就能回收了。。。


另外还要分析以下在AbstractChannel中定义的AbstractUnsafe,在它里面实现了一些基本的顶层方法,我个人觉得最为重要的是register方法,该方法的作用就是将当前channel注册到eventLoop当中,不过其实最终又会调用doRegister方法,这个方法将会在AbstractNioChannel中被重写。。。


最后来分析一下AbstractNioChannel,其实它也是一个抽象类,不过它定义的一些属性和方法就很有Nio的意思了。。首先还是来分析一下它的一些属性。。。

    private final SelectableChannel ch;    //真正用到的channel    protected final int readInterestOp;  //真正关心的读事件    private volatile SelectionKey selectionKey;   //注册后获取的的key
稍微熟悉一点Nio的人应该就能知道这几个东西是干嘛的吧。。。首先定义了一个SelectableChannel,它是一个java Nio定义的channel,另外readInterestOp用于区分当前channel所关注的的事件类型,至于selectionKey这东西就更为直白了,它是将 SelectableChannel注册到selector后得到的。。。。

从上面一些属性的定义就可以看出,在AbstractNioChannel中就已经将Netty的channel和java nio的channel联系起来了。。


还是来看一下它的构造函数吧:

    //构造函数    protected AbstractNioChannel(            Channel parent, Integer id, SelectableChannel ch, int readInterestOp) {        super(parent, id);        this.ch = ch;        this.readInterestOp = readInterestOp;        try {            ch.configureBlocking(false);    //将channel设置为非阻塞        } catch (IOException e) {            try {                ch.close();            } catch (IOException e2) {                if (logger.isWarnEnabled()) {                    logger.warn(                            "Failed to close a partially initialized socket.", e2);                }            }            throw new ChannelException("Failed to enter non-blocking mode.", e);        }    }
这里面比较有意思也是比价直白的就是将当前的selectableChannel设置为非阻塞的,看到这里就有点觉得,其实所有的编程语言和平台他们最终的实现都差不多,不管是c语言还是java,他们最终编程套路都差不多,起码在netty中我觉得和c语言的io框架的实现其实也都是差不太多的,唯一可能比较不一样的地方就是java的类封装比较漂亮,不过也稍微显的比较繁琐,没有c语言来的直白。。。


另外最后还要分析一下在AbstractNioChannel中定义的AbstractNioUnsafe,不过这里我只是想分析一下其中定义的一个方法,也就是在上面提到过的doRegister方法:

    @Override    //channel的regist    protected Runnable doRegister() throws Exception {        boolean selected = false;        for (;;) {            try {            //获取实际的channel然后注册到eventloop的selector上面                selectionKey = javaChannel().register(eventLoop().selector, 0, this);                return null;            } catch (CancelledKeyException e) {                if (!selected) {                    // Force the Selector to select now  as the "canceled" SelectionKey may still be                    // cached and not removed because no Select.select(..) operation was called yet.                    eventLoop().selectNow();                    selected = true;                } else {                    // We forced a select operation on the selector before but the SelectionKey is still cached                    // for whatever reason. JDK bug ?                    throw e;                }            }        }    }
上面的代码就将netty的channel和java nio完全的联系起来了。。。这里eventLoop方法返回的是一个NioEventLoop对象,在它里面定义了selector属性,doRegister的主要作用就是将当前对象的selectableChannel注册到eventLoop的selector去,并保存返回的key。



好了,这篇文章好像写的比较多了,不过它确实比较重要,清清楚楚的将netty与java nio联系了起来。。。。