Netty服务端启动过程相关源码分析

1、Netty 是怎么创建服务端Channel的呢?

我们在使用ServerBootstrap.bind(端口)方法时,最终调用其父类AbstractBootstrap中的doBind方法,相关源码如下:

private ChannelFuture doBind(final SocketAddress localAddress) { //初始化和注册 final ChannelFuture regFuture = initAndRegister(); .....

我们继续跟进initAndRegister()这个方法,发现是使用channelFactory.newChannel() 完成channel的创建:

final ChannelFuture initAndRegister() { Channel channel = null; try { channel = channelFactory.newChannel(); init(channel); } catch (Throwable t) {......}

ChannelFactory在实现类ReflectiveChannelFactory中的实现细节,内部使用了反射的方式创建Channel:

public T newChannel() { try { return clazz.newInstance(); } catch (Throwable t) {......} }

这里的ChannelFactory是通过 bootstrap.channel(NioServerSocketChannel.class) 加入的:

public B channel(Class<? extends C> channelClass) { if (channelClass == null) { throw new NullPointerException("channelClass"); } return channelFactory(new ReflectiveChannelFactory<C>(channelClass)); }

综上所述,Netty就是调用jdk底层方法创建NIO的channel,也就是通过反射完成NIO的channel创建。最后其包装成Netty自己的Channel.

2、初始化服务端Channel是怎么样的执行流程?

在创建了Channel之后就调用AbstractBootstrap的init(channel)抽象方法完成初始化:

abstract void init(Channel channel) throws Exception;

服务器端ServerBootstrap的init方法从源码来看主要完成工作为:

配置相关的Options和Attribute。

通过ChannelPipeline 添加相关逻辑处理器 ChannelHandler。

最后这些属性会传入ServerBootstrapAcceptor连接器,通过ServerBootstrapAcceptor连接器完成相应的初始化。

// We add this handler via the EventLoop as the user may have used a ChannelInitializer as handler. // In this case the initChannel(...) method will only be called after this method returns. Because // of this we need to ensure we add our handler in a delayed fashion so all the users handler are // placed in front of the ServerBootstrapAcceptor. ch.eventLoop().execute(new Runnable() { @Override public void run() { pipeline.addLast(new ServerBootstrapAcceptor( currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs)); } }); 3、怎么注册selector?

在Java NIO 中注册通道Channel到多路复用器Selector,并说明关注点SelectionKey.OP_ACCEPT,监听ACCEPT事件通常我们会这样写:

serverSocket.register(selector, SelectionKey.OP_ACCEPT);

Netty在底层将Channel注册到事件轮询器selector上就是基于此方法:

首先在初始化Channel后执行:

ChannelFuture regFuture = config().group().register(channel);

上面的代码实际是调用AbstractChannel的register方法,完成eventLoop的绑定。内部方法register0()中会调用AbstractNioChannel的doRegister() 方法:

protected void doRegister() throws Exception { boolean selected = false; for (;;) { try { selectionKey = javaChannel().register(eventLoop().selector, 0, this); return; } catch (CancelledKeyException e) {......} } }

这里其实就是调用NIO SelectableChannel的register方法。

从源码可以知道,注册成功后这里会以此执行服务器handler中的回调方法:handlerAdded ,channelActive

4、端口怎么绑定呢?

一切OK之后就会调用AbstractChannel中的 bind 方法,这个方法又会调用NioServerSocketChannel 的 doBind 方法,从doBind方法可知是调用的原生NIO 的bind做绑定:

protected void doBind(SocketAddress localAddress) throws Exception { if (PlatformDependent.javaVersion() >= 7) { javaChannel().bind(localAddress, config.getBacklog()); } else { javaChannel().socket().bind(localAddress, config.getBacklog()); } }

绑定完成后会执行代码:

if (!wasActive && isActive()) { invokeLater(new Runnable() { @Override public void run() { pipeline.fireChannelActive(); } }); }

这里会调用DefaultChannelPipeline中的内部类HeadContext的channelActive方法进行事件传播:

@Override public void channelActive(ChannelHandlerContext ctx) throws Exception { ctx.fireChannelActive(); readIfIsAutoRead(); }

那么服务端到底是在哪里 accept 连接的呢?
通过上面的代码我们跟进 AbstractChannel 的beginRead() 方法,继而找到 AbstractNioChannel 的 doBeginRead() 方法:

protected void doBeginRead() throws Exception { // Channel.read() or ChannelHandlerContext.read() was called final SelectionKey selectionKey = this.selectionKey; if (!selectionKey.isValid()) { return; } readPending = true; final int interestOps = selectionKey.interestOps(); if ((interestOps & readInterestOp) == 0) { selectionKey.interestOps(interestOps | readInterestOp); } }

上面的代码就是NIO编程中常用的写法,这里监听ACCEPT事件就是NioServerSocketChannel构造函数调用父类传入的SelectionKey.OP_ACCEPT:

public NioServerSocketChannel(ServerSocketChannel channel) { super(null, channel, SelectionKey.OP_ACCEPT); config = new NioServerSocketChannelConfig(this, javaChannel().socket()); }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpygwj.html