AbstractNioChannel的抽象内部内同时继承了它父类的AbstractUnsafe实现了当前的NioUnsafe, 再往后看, 问题来了, 服务端和客户端在的针对read的特化实现在哪里呢? 想想看肯定在它子类的unsafe内部类中,如下图,紫框框
一会再具体看这两个 内部类是如何特化read的 注意啊,不再是抽象的了
再进一步 AbstractNioMessageChannel它的构造函数如下, 只是调用父类的构造函数,传递参数
protected AbstractNioMessageChannel(Channel parent, SelectableChannel ch, int readInterestOp) { // todo 在进去 // todo null ServerSocketChannel accept super(parent, ch, readInterestOp); } AbstractNioMessageChannel的MessageNioUnsafe对read()特化实现在read方法中,我们可以看到,他调用是本类的抽象方法doReadMessages(List<Object> buf), 方法的实现类是继承体系的最底层的NioServerSocketChannel, 因为他就是那个特化的服务端channel
当然如果我们一开始跟进read()时,来到的客户端的AbstractNioByteChannel,现在我们找到的doReadMessage()就是由 客户端的channelNioSocketChannel完成的doReadBytes()
// todo 用于处理新链接进来的内部类 private final class NioMessageUnsafe extends AbstractNioUnsafe { // todo 这个容器用于存放临时读到的连接 private final List<Object> readBuf = new ArrayList<Object>(); // todo 接受新链接的 read来到这里 @Override public void read() { ... doBeginRead(buf); ... } // todo 处理新的连接 是在 NioServerSocketChannel中实现的, 进入查看 protected abstract int doReadMessages(List<Object> buf) throws Exception; 最终,特化的channel实现现在我们就来到了最底层,整张继承图就全部展现在眼前了,下面就去看看,特化的服务端Channel NioServetSocketChannel和NioSocketChannel对 doReadMessages()和doReadBytes()的各自实现
服务端, 我们看到了,它的读取数据是在创建新的 Jdk远程channel, 因为它在创建新的连接chanel
@Override protected int doReadMessages(List<Object> buf) throws Exception { // todo java Nio底层在这里 创建jdk底层的 原生channel SocketChannel ch = SocketUtils.accept(javaChannel()); try { if (ch != null) { // todo 把java原生的channel, 封装成 Netty自定义的封装的channel , 这里的buf是list集合对象,由上一层传递过来的 // todo this -- NioServerSocketChannel // todo ch -- SocketChnnel buf.add(new NioSocketChannel(this, ch)); return 1; } ...客户端, 读取客户端发送过来的IO数据
@Override protected int doReadBytes(ByteBuf byteBuf) throws Exception { final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle(); allocHandle.attemptedBytesRead(byteBuf.writableBytes()); return byteBuf.writeBytes(javaChannel(), allocHandle.attemptedBytesRead()); } 小结:Netty的channel继承体系,到现在就完成了, 相信,当我们现在再正着从 NioServerEventLoop入手,看他的初始化过程应该很简单了, 其中我希望自己可以牢记几个点
AbstractChannel维护NioChannel的EventLoop
AbstractNioChannel维护jdk原生 channel
AbstractChannel中的AbstractUnsafe主要是定义了一套模板,给子类提供了填空题,下面的三个填空
注册 把chanel注册进Selector
绑定 把chanel绑定上端口
添加感兴趣的事件, 给创建出来的channel二次注册上netty可以处理的感兴趣的事件
channel的io操作是unsafe内部类完成的
服务端从channel,读取出新连接NioMessageUnsafe
客户端从channel,读取出数据NioByteUnsafeNioEventLoop的启动时机是在服务端的NioServerSocketChannel中的ServerSocketChannel初始化完成,且注册在NioEventLoop后执行的, 下一步就是去绑定端口,但是在绑定端口前,需要完成NioEventLoop的启动工作, 因为程序运行到这个阶段为止,依然只有MainThread一条线程,下面就开始阅读源码NioEventLoop开启新的线程自立家门的