Netty4.x 源码实战系列(三):NioServerSocketChannel全剖析
2017-12-31 22:30
495 查看
根据上一篇《Netty4.x 源码实战系列(二):服务端bind流程详解》所述,在进行服务端开发时,必须通过ServerBootstrap引导类的channel方法来指定channel类型, channel方法的调用其实就是实例化了一个用于生成此channel类型对象的工厂对象。 并且在bind调用后,会调用此工厂对象来生成一个新channel。
本篇将通过NioServerSocketChannel实例化过程,来深入剖析NioServerSocketChannel。
在开始代码分析之前,我们先看一下NioServerSocketChannel的类继承结构图:
调用工厂完成NioServerSocketChannel实例的创建
在绑定侦听端口过程中,我们调用了AbstractBootstrap的initAndRegister方法来完成channel的创建与初始化,channel实例化代码如下:
而channelFactory对象是我们通过ServerBootstrap.channel方法的调用生成的
通过代码可知,此工厂对象是ReflectiveChannelFactory实例
所以 channelFactory.newChannel() 实例化其实就是NioServerSocketChannel无参构造方法反射而成。
NioServerSocketChannel实例化过程分析
我们先看一下NioServerSocketChannel的无参构造代码
无参构造方法中有两个关键点:
1、使用默认的多路复用器辅助类 DEFAULT_SELECTOR_PROVIDER
2、通过newSocket创建ServerSocketChannel
我们将newSocket生成的ServerSocketChannel对象继续传递给本类中的NioServerSocketChannel(ServerSocketChannel channel)构造方法
在其内部,我们会调用父类AbstractNioMessageChannel的构造方法:
因为是服务端新生成的channel,第一个参数指定为null,表示没有父channel,第二个参数指定为ServerSocketChannel,第三个参数指定ServerSocketChannel关心的事件类型为SelectionKey.OP_ACCEPT。
在AbstractNioMessageChannel内部会继续调用父类AbstractNioChannel的构造方法:
在AbstractNioChannel中做了下面几件事:
1、继续调用父类AbstractChannel(Channel parent)构造方法;
2、通过this.ch = ch 保存ServerSocketChannel, 因为NioServerSocketChannel是Netty封装的对象,而ServerSocketChannel是有前面默认selector_provider生成的,是java nio的, 其实“this.ch = ch”可以被认为是绑定java nio服务端通道至netty对象中;
3、设置ServerSocketChannel关心的事件类型;
4、设置ServerSocketChannel为非阻塞的(熟悉Java NIO的都知道如果不设置为false,启动多路复用器会报异常)
我们再看一下AbstractChannel(Channel parent)的内部代码细节
此构造方法中,主要做了三件事:
1、给channel生成一个新的id
2、通过newUnsafe初始化channel的unsafe属性
3、newChannelPipeline初始化channel的pipeline属性
id的生成我们就不细究了,我们主要看看newUnsafe 及 newChannelPipeline是如何创建unsafe对象及pipeline对象的。
newUnsafe()方法调用
在AbstractChannel类中,newUnsafe()是一个抽象方法
通过上面的类继承结构图,我们找到AbstractNioMessageChannel类中有newUnsafe()的实现
此方法返回一个NioMessageUnsafe实例对象,而NioMessageUnsafe是AbstractNioMessageChannel的内部类
NioMessageUnsafe 只覆盖了 父类AbstractNioUnsafe中的read方法,通过NioMessageUnsafe 及其父类的代码便可以知道, 其实unsafe对象是真正的负责底层channel的连接/读/写等操作的,unsafe就好比一个底层channel操作的代理对象。
newChannelPipeline()方法调用
newChannelPipeline直接在AbstractChannel内实现
该方法返回了创建了一个DefaultChannelPipeline对象
此DefaultChannelPipeline对象会绑定NioServerSocketChannel对象,并初始化了HeadContext及TailContext对象。
head及tail初始化完成后,它们会相互连接。
通过上面的代码可以得出,pipeline就是一个双向链表。关于Pipeline的更多细节,此处不做赘述,欢迎大家关注下一篇文章。
我们在回到NioServerSocketChannel的构造方法 NioServerSocketChannel(ServerSocketChannel channel)
父类构造方法调用完成后,NioServerSocketChannel还要初始化一下自己的配置对象
NioServerSocketChannelConfig是NioServerSocketChannel的内部类
而NioServerSocketChannelConfig 又是继承自DefaultServerSocketChannelConfig,通过代码分析,此config对象就是就会对底层ServerSocket一些配置设置行为的封装。
至此NioServerSocketChannel对象应该创建完成了~
总结:
1、NioServerSocketChannel对象内部绑定了Java NIO创建的ServerSocketChannel对象;
2、Netty中,每个channel都有一个unsafe对象,此对象封装了Java NIO底层channel的操作细节;
3、Netty中,每个channel都有一个pipeline对象,此对象就是一个双向链表;
本篇将通过NioServerSocketChannel实例化过程,来深入剖析NioServerSocketChannel。
在开始代码分析之前,我们先看一下NioServerSocketChannel的类继承结构图:
调用工厂完成NioServerSocketChannel实例的创建
在绑定侦听端口过程中,我们调用了AbstractBootstrap的initAndRegister方法来完成channel的创建与初始化,channel实例化代码如下:
channelFactory.newChannel()
而channelFactory对象是我们通过ServerBootstrap.channel方法的调用生成的
public B channel(Class<? extends C> channelClass) { if (channelClass == null) { throw new NullPointerException("channelClass"); } return channelFactory(new ReflectiveChannelFactory<C>(channelClass)); }
通过代码可知,此工厂对象是ReflectiveChannelFactory实例
public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> { private final Class<? extends T> clazz; public ReflectiveChannelFactory(Class<? extends T> clazz) { if (clazz == null) { throw new NullPointerException("clazz"); } this.clazz = clazz; } @Override public T newChannel() { try { return clazz.getConstructor().newInstance(); } catch (Throwable t) { throw new ChannelException("Unable to create Channel from class " + clazz, t); } } }
所以 channelFactory.newChannel() 实例化其实就是NioServerSocketChannel无参构造方法反射而成。
NioServerSocketChannel实例化过程分析
我们先看一下NioServerSocketChannel的无参构造代码
public NioServerSocketChannel() { this(newSocket(DEFAULT_SELECTOR_PROVIDER)); }
无参构造方法中有两个关键点:
1、使用默认的多路复用器辅助类 DEFAULT_SELECTOR_PROVIDER
private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
2、通过newSocket创建ServerSocketChannel
private static ServerSocketChannel newSocket(SelectorProvider provider) { try { return provider.openServerSocketChannel(); } catch (IOException e) { throw new ChannelException( "Failed to open a server socket.", e); } }
我们将newSocket生成的ServerSocketChannel对象继续传递给本类中的NioServerSocketChannel(ServerSocketChannel channel)构造方法
public NioServerSocketChannel(ServerSocketChannel channel) { super(null, channel, SelectionKey.OP_ACCEPT); config = new NioServerSocketChannelConfig(this, javaChannel().socket()); }
在其内部,我们会调用父类AbstractNioMessageChannel的构造方法:
protected AbstractNioMessageChannel(Channel parent, SelectableChannel ch, int readInterestOp) { super(parent, ch, readInterestOp); }
因为是服务端新生成的channel,第一个参数指定为null,表示没有父channel,第二个参数指定为ServerSocketChannel,第三个参数指定ServerSocketChannel关心的事件类型为SelectionKey.OP_ACCEPT。
在AbstractNioMessageChannel内部会继续调用父类AbstractNioChannel的构造方法:
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) { // 继续调用父类构造方法 super(parent); // 将ServerSocketChannel对象保存 this.ch = ch; // 设置关心的事件 this.readInterestOp = readInterestOp; try { // 设置当前通道为非阻塞的 ch.configureBlocking(false); } 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); } }
在AbstractNioChannel中做了下面几件事:
1、继续调用父类AbstractChannel(Channel parent)构造方法;
2、通过this.ch = ch 保存ServerSocketChannel, 因为NioServerSocketChannel是Netty封装的对象,而ServerSocketChannel是有前面默认selector_provider生成的,是java nio的, 其实“this.ch = ch”可以被认为是绑定java nio服务端通道至netty对象中;
3、设置ServerSocketChannel关心的事件类型;
4、设置ServerSocketChannel为非阻塞的(熟悉Java NIO的都知道如果不设置为false,启动多路复用器会报异常)
我们再看一下AbstractChannel(Channel parent)的内部代码细节
protected AbstractChannel(Channel parent) { this.parent = parent; id = newId(); unsafe = newUnsafe(); pipeline = newChannelPipeline(); }
此构造方法中,主要做了三件事:
1、给channel生成一个新的id
2、通过newUnsafe初始化channel的unsafe属性
3、newChannelPipeline初始化channel的pipeline属性
id的生成我们就不细究了,我们主要看看newUnsafe 及 newChannelPipeline是如何创建unsafe对象及pipeline对象的。
newUnsafe()方法调用
在AbstractChannel类中,newUnsafe()是一个抽象方法
protected abstract AbstractUnsafe newUnsafe();
通过上面的类继承结构图,我们找到AbstractNioMessageChannel类中有newUnsafe()的实现
@Override protected AbstractNioUnsafe newUnsafe() { return new NioMessageUnsafe(); }
此方法返回一个NioMessageUnsafe实例对象,而NioMessageUnsafe是AbstractNioMessageChannel的内部类
private final class NioMessageUnsafe extends AbstractNioUnsafe { private final List<Object> readBuf = new ArrayList<Object>(); @Override public void read() { assert eventLoop().inEventLoop(); final ChannelConfig config = config(); final ChannelPipeline pipeline = pipeline(); final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle(); allocHandle.reset(config); boolean closed = false; Throwable exception = null; try { try { do { int localRead = doReadMessages(readBuf); if (localRead == 0) { break; } if (localRead < 0) { closed = true; break; } allocHandle.incMessagesRead(localRead); } while (allocHandle.continueReading()); } catch (Throwable t) { exception = t; } int size = readBuf.size(); for (int i = 0; i < size; i ++) { readPending = false; pipeline.fireChannelRead(readBuf.get(i)); } readBuf.clear(); allocHandle.readComplete(); pipeline.fireChannelReadComplete(); if (exception != null) { closed = closeOnReadError(exception); pipeline.fireExceptionCaught(exception); } if (closed) { inputShutdown = true; if (isOpen()) { close(voidPromise()); } } } finally { if (!readPending && !config.isAutoRead()) { removeReadOp(); } } } }
NioMessageUnsafe 只覆盖了 父类AbstractNioUnsafe中的read方法,通过NioMessageUnsafe 及其父类的代码便可以知道, 其实unsafe对象是真正的负责底层channel的连接/读/写等操作的,unsafe就好比一个底层channel操作的代理对象。
newChannelPipeline()方法调用
newChannelPipeline直接在AbstractChannel内实现
protected DefaultChannelPipeline newChannelPipeline() { return new DefaultChannelPipeline(this); }
该方法返回了创建了一个DefaultChannelPipeline对象
protected DefaultChannelPipeline(Channel channel) { this.channel = ObjectUtil.checkNotNull(channel, "channel"); succeededFuture = new SucceededChannelFuture(channel, null); voidPromise = new VoidChannelP a330 romise(channel, true); tail = new TailContext(this); head = new HeadContext(this); head.next = tail; tail.prev = head; }
此DefaultChannelPipeline对象会绑定NioServerSocketChannel对象,并初始化了HeadContext及TailContext对象。
tail = new TailContext(this); head = new HeadContext(this);
head及tail初始化完成后,它们会相互连接。
通过上面的代码可以得出,pipeline就是一个双向链表。关于Pipeline的更多细节,此处不做赘述,欢迎大家关注下一篇文章。
我们在回到NioServerSocketChannel的构造方法 NioServerSocketChannel(ServerSocketChannel channel)
public NioServerSocketChannel(ServerSocketChannel channel) { super(null, channel, SelectionKey.OP_ACCEPT); config = new NioServerSocketChannelConfig(this, javaChannel().socket()); }
父类构造方法调用完成后,NioServerSocketChannel还要初始化一下自己的配置对象
config = new NioServerSocketChannelConfig(this, javaChannel().socket());
NioServerSocketChannelConfig是NioServerSocketChannel的内部类
private final class NioServerSocketChannelConfig extends DefaultServerSocketChannelConfig { private NioServerSocketChannelConfig(NioServerSocketChannel channel, ServerSocket javaSocket) { super(channel, javaSocket); } @Override protected void autoReadCleared() { clearReadPending(); } }
而NioServerSocketChannelConfig 又是继承自DefaultServerSocketChannelConfig,通过代码分析,此config对象就是就会对底层ServerSocket一些配置设置行为的封装。
至此NioServerSocketChannel对象应该创建完成了~
总结:
1、NioServerSocketChannel对象内部绑定了Java NIO创建的ServerSocketChannel对象;
2、Netty中,每个channel都有一个unsafe对象,此对象封装了Java NIO底层channel的操作细节;
3、Netty中,每个channel都有一个pipeline对象,此对象就是一个双向链表;
相关文章推荐
- 《Java 源码分析》:Java NIO 之 ServerSocketChannel
- Netty4.x 源码实战系列(一): 深入理解ServerBootstrap 与 Bootstrap (1)
- 《Java 源码分析》:Java NIO 之 ServerSocketChannel
- Java NIO系列教程(六) ServerSocketChannel
- Java NIO系列教程(六) ServerSocketChannel
- 自动化运维Python系列之IO多路复用、SocketServer源码分析
- 使用select异步IO实现socketserver服务器 源码剖析
- NIO编程之ServerSocketChannel用法详解
- Java NIO系列教程(9):ServerSocketChannel
- Java NIO系列教程(九) ServerSocketChannel
- Java NIO系列教程(九) ServerSocketChannel
- Java NIO系列教程(九) ServerSocketChannel
- Java NIO系列教程(九) ServerSocketChannel
- Java NIO ServerSocketChannel
- Java NIO系列教程(九) ServerSocketChannel
- Java Nio 十、Java NIO ServerSocketChannel
- 【JAVA】【NIO】10、Java NIO ServerSocketChannel
- Nio(九)ServerSocketChannel
- Java NIO系列教程(九) ServerSocketChannel
- Java NIO系列教程(九) ServerSocketChannel