Netty服务端启动源码解析

前言

前面写了一系列关于NIO和Netty基础相关的文章,对于学好Netty最主要的是什么呢?那应该是需要先学好NIO和理解Netty中的Reactor线程模型,还有关于网络编程方面的一些只是,譬如封帧、编解码等。

那么本篇文章就开始进行Netty源码的解析了,对于Netty源码的解析,我们还是先从代码运行链路的角度来进行源码解析,在进行源码解析之前,我们还需要先看下Netty Reactor线程模型图,如下:

上图中的含义大体如下:

  • 创建两组线程池BossGroup和WorkerGroup,BossGroup负责接受客户端的连接,WorkerGroup负责网路读写和处理业务逻辑。BossGroup和WorkerGroup的类型都是NioEventLoop。
  • NioEventLoopGroup相当于一个事件循环线程组,这个组中含有多个事件循环线程,每个事件循环线程为一个NioEventLoop。
  • 每一个NioEventLoop中都包含一个Selector,适用于监听注册在其上的SocketChannel的网络通讯。
  • 每个Boss NioEventLoop 线程内部的执行步骤如下:
    • 处理accept事件,与client建立连接,,生成NioSocketChannel。
    • 将NioSocketChannel注册到每个 Worker NioEventLoop中的Selector上。
    • 处理任务队列的任务:runAllTask。
  • 每个Worker NioEventLoop 线程内部的执行步骤如下:
    • 轮询注册到自己Selector上的所有NioSocketChannel的read、write事件。
    • 处理IO事件:read和write事件,在对应的NioScoketChannel中处理业务。
    • runAllTask处理任务队列TaskQueue的任务,一些耗时较长的任务可以放到TaskQueue中慢慢处理,但这不影响数据在pipeline中的流动处理。
  • 每个Worker NioEventLoop 处理NioSocketChannel业务时,会使用到pipeline(管道),管道中维护了很多Handler来处理Channel中的数据。

Netty示例代码

在了解完Netty Reactor的相关概念之后,那么我们再来看一下关于Netty 使用的示例代码(本示例代码依赖的netty版本为:4.1.35.Final),如下:

Netty Server端示例代码

public class NettyServer {
    public static void main(String[] args) throws Exception {

        //创建两个线程组:bossGroup和workGroup
        //bossGroup 只处理连接请求,真正的和客户端的业务处理,是交由workGroup处理的
        EventLoopGroup bossGroup = new NioEventLoopGroup(3);
        EventLoopGroup workerGroup = new NioEventLoopGroup(8);

        try {
            // 创建服务器端的启动对象
            ServerBootstrap bootstrap = new ServerBootstrap();
            // 使用链式编程来配置参数
            bootstrap.group(bossGroup, workerGroup) //设置两个线程组
                    // 使用NioServerSocketChannel作为服务器的通道实现
                    .channel(NioServerSocketChannel.class)
                    // 初始化服务器连接队列大小,服务端处理客户端连接请求是顺序处理的,所以同一时间只能处理一个客户端连接。
                    // 多个客户端同时来的时候,服务端将不能处理的客户端连接请求,将放在队列中等待处理
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    //创建通道初始化对象,设置初始化参数,在 SocketChannel 建立起来之前执行
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            //对workerGroup的SocketChannel设置处理器
                            socketChannel.pipeline().addLast(new NettyServerHandler());
                        }
                    });

            System.out.println("netty server start。。");


            ChannelFuture channelFuture = bootstrap.bind(9000).sync();
            channelFuture.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

 NettyServerHandler

public class NettyServerHandler extends ChannelInboundHandlerAdapter {

    /**
     * 当客户端连接服务器完成就会触发该方法
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        System.out.println("客户端连接通道建立完成");
    }

    /**
     * 读取客户端发送的数据
     * @param ctx  上下文对象, 含有通道channel,管道pipeline
     * @param msg  就是客户端发送的数据
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        //将 msg 转成一个 ByteBuf,类似NIO 的 ByteBuffer
        ByteBuf buf = (ByteBuf) msg;
        System.out.println("收到客户端的消息:" + buf.toString(CharsetUtil.UTF_8));
    }

    /**
     * 数据读取完毕处理方法
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ByteBuf buf = Unpooled.copiedBuffer("HelloClient".getBytes(CharsetUtil.UTF_8));
        ctx.writeAndFlush(buf);
    }

    /**
     * 处理异常, 一般是需要关闭通道
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        ctx.close();
    }
}

Netty Client端示例代码

public class NettyClient {
    public static void main(String[] args) throws Exception {

        //客户端需要一个事件循环组
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            //创建客户端启动对象
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group) //设置线程组
                    .channel(NioSocketChannel.class) // 使用NioSocketChannel作为客户端的通道实现
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            //加入处理器
                            socketChannel.pipeline().addLast(new NettyClientHandler());
                        }
                    });
            System.out.println("netty client start。。");
            //启动客户端去连接服务器端
            ChannelFuture cf = bootstrap.connect("127.0.0.1", 9000).sync();
            //对通道关闭进行监听
            cf.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully();
        }
    }
}

NettyClientHandler

public class NettyClientHandler extends ChannelInboundHandlerAdapter {
    /**
     * 当客户端连接服务器完成就会触发该方法
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        ByteBuf buf = Unpooled.copiedBuffer("HelloServer".getBytes(CharsetUtil.UTF_8));
        ctx.writeAndFlush(buf);
    }

    //当通道有读取事件时会触发,即服务端发送数据给客户端
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ByteBuf buf = (ByteBuf) msg;
        System.out.println("收到服务端的消息:" + buf.toString(CharsetUtil.UTF_8));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

上面展示了一下,关于Netty 使用的示例代码,本系列所有的代码解析都是从这些示例代码中出发的,当然前面的那张Netty Reactor线程模型图也是很重要的,需要读者详细了解,其中的相关关联关系,才能更好的深入了解Nettyd 源码。

因为本篇文章主要讲的是关于Netty 服务端启动源码的解析,所以这需要从 NettyServer 端的 bootstrap.bind(9000).sync() 这段代码开始入手,至于前面的EventLoopGroup、NioEventLoopGroup、ServerBootstrap、Bootstrap等相关组件的架构关系源码解析,后面将会用单独的篇章进行解析。

Netty服务注册

这里我们先看一下启动核心服务的时序图,从下图中可以清晰的看出关于NettyServer端示例代码中的主要流程,包括以下步骤:

  • 创建Boss NioEventLoopGroup
  • 创建多个Boss NioEventLoop,然后再每个Boss NioEventLoop上绑定一个Selector
  • 创建ServerBootstrap,并绑定端口及启动服务器
  • 创建NioServerSocketChannel
  • 初始化NioServerSocketChannel
  • 分配BossNioEventLoop
  • 注册NioServerSocketChannel到BossNioEventLoop里的Selector上
  • NioServerSocketChannel绑定端口
  • 注册NioServerSocketChannel的“读”事件

创建NioEventLoopGroup

从前面的示例中也是知道在Netty编程中,需要先创建一个Boss NioEventLoopGroup,在这个对象创建的时候会创建多个(这个多个是指自己传入或者根据CPU核心数进行相关计算的)NioEventLoop,在创建NioEventLoop时候,同时会绑定Selector,我们来看下代码的具体实现,如下:

// nThreads 参数是指传入的“多个”,可根据传入的数值来创建对应数量的NioEventLoop
public NioEventLoopGroup(int nThreads) {
    this(nThreads, (Executor)null);
}

public NioEventLoopGroup(int nThreads, Executor executor) {
    // SelectorProvider.provider() 便是Nio编程中创建Selector的方式
    this(nThreads, executor, SelectorProvider.provider());
}

public NioEventLoopGroup(int nThreads, Executor executor, SelectorProvider selectorProvider) {
    this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);
}

public NioEventLoopGroup(int nThreads, Executor executor, SelectorProvider selectorProvider, SelectStrategyFactory selectStrategyFactory) {
    super(nThreads, executor, new Object[]{selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject()});
}

protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
    // 判断是否传入了 nThreads,如果没传,则使用默认的参数,否则根据传入的参数创建
    super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
}

protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) {
    this(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args);
}

MultithreadEventExecutorGroup#MultithreadEventExecutorGroup(int, java.util.concurrent.Executor, io.netty.util.concurrent.EventExecutorChooserFactory, java.lang.Object...)

protected MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args) {
    this.terminatedChildren = new AtomicInteger();
    this.terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);
    if (nThreads <= 0) {
        throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
    } else {
        // 如果没有传入 executor,则创建 ThreadPerTaskExecutor
        if (executor == null) {
            executor = new ThreadPerTaskExecutor(this.newDefaultThreadFactory());
        }
        // 根据传入nThreads的数量,创建线程池数组,并赋值给 children
        this.children = new EventExecutor[nThreads];

        int j;
        // 根据传入nThreads的数量,循环创建 NioEventLoop
        for(int i = 0; i < nThreads; ++i) {
            boolean success = false;
            boolean var18 = false;
            try {
                var18 = true;
                // 创建 NioEventLoop
                this.children[i] = this.newChild((Executor)executor, args);
                success = true;
                var18 = false;
            } catch (Exception var19) {
                throw new IllegalStateException("failed to create a child event loop", var19);
            } finally {
                // 省略非关键代码
            }
    	// 省略非关键代码
        }
        // 获取 chooser
        this.chooser = chooserFactory.newChooser(this.children);
        FutureListener<Object> terminationListener = new FutureListener<Object>() {
            public void operationComplete(Future<Object> future) throws Exception {
                if (MultithreadEventExecutorGroup.this.terminatedChildren.incrementAndGet() == MultithreadEventExecutorGroup.this.children.length) {
                    MultithreadEventExecutorGroup.this.terminationFuture.setSuccess((Object)null);
                }

            }
        };
        // 省略非关键代码
    }
}

创建NioEventLoop

protected EventLoop newChild(Executor executor, Object... args) throws Exception {
    return new NioEventLoop(this, executor, (SelectorProvider)args[0], ((SelectStrategyFactory)args[1]).newSelectStrategy(), (RejectedExecutionHandler)args[2]);
}

NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider, SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {
    // 调用父类构造器
    super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);
    if (selectorProvider == null) {
        throw new NullPointerException("selectorProvider");
    } else if (strategy == null) {
        throw new NullPointerException("selectStrategy");
    } else {
        this.provider = selectorProvider;
        // 获取selector
        NioEventLoop.SelectorTuple selectorTuple = this.openSelector();
        // 将获取到的selector 赋值给NioEventLoop中的Selector
        this.selector = selectorTuple.selector;
        this.unwrappedSelector = selectorTuple.unwrappedSelector;
        this.selectStrategy = strategy;
    }
}

创建 SingleThreadEventLoop

protected SingleThreadEventLoop(EventLoopGroup parent, Executor executor, boolean addTaskWakesUp, int maxPendingTasks, RejectedExecutionHandler rejectedExecutionHandler) {
    super(parent, executor, addTaskWakesUp, maxPendingTasks, rejectedExecutionHandler);
    // 创建TaskQueue
    this.tailTasks = this.newTaskQueue(maxPendingTasks);
}

protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor, boolean addTaskWakesUp, int maxPendingTasks, RejectedExecutionHandler rejectedHandler) {
    super(parent);
    this.threadLock = new Semaphore(0);
    this.shutdownHooks = new LinkedHashSet();
    this.state = 1;
    this.terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);
    this.addTaskWakesUp = addTaskWakesUp;
    this.maxPendingTasks = Math.max(16, maxPendingTasks);
    this.executor = ThreadExecutorMap.apply(executor, this);
    this.taskQueue = this.newTaskQueue(this.maxPendingTasks); // 创建TaskQueue
    this.rejectedExecutionHandler = (RejectedExecutionHandler)ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
}

结合前面的Nettey Reactor模型图和前面的时序图,我们可以得知在创建 NioEventLoopGroup 的时候,会根据有没有传入线程数来判断创建多少个NioEventLoop,在没一个创建的NioEventLoop中,会绑定一个 Selector 和 TaskQueue。而创建Selector的方式,就是封装了NIO中获取方式。

创建ServerBootstrap等相关链式操作

在前面实力中在创建好两组NioEventLoopGroup后,便是继续创建ServerBootstrap,然后根据创建完ServerBootstrap的对象进行一些列链式调用ServerBootstrap中传入一些参数,譬如:两组NioEventLoopGroup、NioServerSocketChannel.class、Handler等。

调用io.netty.bootstrap.ServerBootstrap#group(io.netty.channel.EventLoopGroup, io.netty.channel.EventLoopGroup)方法传入的两组EventLoopGroup,在方法中只是进行了简单的赋值操作,这里就不多说了,而调用io.netty.bootstrap.AbstractBootstrap#channel方法,则是根据传入的Class类型来创建对应的类对象,那么来看下这个方法的代码是如何实现的,如下:

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

public ReflectiveChannelFactory(Class<? extends T> clazz) {
    ObjectUtil.checkNotNull(clazz, "clazz");
    try {
        this.constructor = clazz.getConstructor();
    } catch (NoSuchMethodException var3) {
        throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) + " does not have a public non-arg constructor", var3);
    }
}

上面的代码很简单,我们可以看到根据传入channelClass,然后传入ReflectiveChannelFactory构造函数中,再在其中获取期传入channelClass的构造函数,这是为了后续使用做准备的。至于示例代码中所展示的调用io.netty.bootstrap.AbstractBootstrap#option方法,其中也只是作了简单的启动参数---··赋值操作,这里就不赘述了。至于最后调用的io.netty.bootstrap.ServerBootstrap#childHandler(io.netty.channel.ChannelHandler)方法,则是将自定义的一些Handler添加到Channel的Pipeline中,以便后续的业务调用中使用。

AbstractBootstrap#bind(int)方法

这里我们追踪下io.netty.bootstrap.AbstractBootstrap#bind(int)方法,当追踪到io.netty.bootstrap.AbstractBootstrap#doBind方法即可,核心代码如下:

private ChannelFuture doBind(final SocketAddress localAddress) {
    // 初始化并注册Channel
    final ChannelFuture regFuture = this.initAndRegister();
    final Channel channel = regFuture.channel();
    if (regFuture.cause() != null) {
        return regFuture;
    } else if (regFuture.isDone()) { //不能肯定register完成,因为register是丢到nio event loop里面执行去了。
        ChannelPromise promise = channel.newPromise();
        doBind0(regFuture, channel, localAddress, promise);
        return promise;
    } else {
        final AbstractBootstrap.PendingRegistrationPromise promise = new AbstractBootstrap.PendingRegistrationPromise(channel);
        // 等着register完成,再来通知执行bind
        regFuture.addListener(new ChannelFutureListener() {
            public void operationComplete(ChannelFuture future) throws Exception {
                Throwable cause = future.cause();
                if (cause != null) {
                    promise.setFailure(cause);
                } else {
                    promise.registered();
                    AbstractBootstrap.doBind0(regFuture, channel, localAddress, promise);
                }

            }
        });
        return promise;
    }
}

final ChannelFuture initAndRegister() {
    Channel channel = null;

    try {
        // 创建Channel,
        channel = this.channelFactory.newChannel();
        // 初始化Channel
        this.init(channel);
    } catch (Throwable var3) {
        if (channel != null) {
            channel.unsafe().closeForcibly();
            return (new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE)).setFailure(var3);
        }

        return (new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE)).setFailure(var3);
    }
    // 开始 register channel
    ChannelFuture regFuture = this.config().group().register(channel);
    if (regFuture.cause() != null) {
        if (channel.isRegistered()) {
            channel.close();
        } else {
            channel.unsafe().closeForcibly();
        }
    }

    return regFuture;
}

在上面的AbstractBootstrap#doBind方法中,主要的调用逻辑是initAndRegister方法的调用和doBind0方法的调用。在initAndRegister方法中最要是创建channel和注册channel。

创建Channel

创建channel这里就会有前面提到的调用io.netty.bootstrap.AbstractBootstrap#channel方法是为后面做准备的,就是为这里创建Channel做准备的,io.netty.channel.ReflectiveChannelFactory#newChannel方法实现如下:

public T newChannel() {
    try {
        // 通过构造函数创建实例
        return (Channel)this.constructor.newInstance();
    } catch (Throwable var2) {
        throw new ChannelException("Unable to create Channel from class " + this.constructor.getDeclaringClass(), var2);
    }
}

public NioServerSocketChannel() {
    this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}

public NioServerSocketChannel(ServerSocketChannel channel) {
    // 调用 NioServerSocketChannel 的父类构造器
    super(null, channel, SelectionKey.OP_ACCEPT);
    config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}

protected AbstractNioMessageChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
    super(parent, ch, readInterestOp);
}

protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
    // 调用 AbstractNioChannel 父类构造器
    super(parent);
    this.ch = ch;
    this.readInterestOp = readInterestOp;
    try {
        // 非阻塞模式(对NIO的封装)
        ch.configureBlocking(false);
    } catch (IOException e) {
        // 省略非关键代码
    }
}
protected AbstractChannel(Channel parent) {
    this.parent = parent;
    id = newId();
    unsafe = newUnsafe();
    // 创建 pipeline
    pipeline = newChannelPipeline();
}

上面是整个Channel创建的流程,其中包含了对NIO的封装,以及最后创建了一个Pipeline等。在调用 NioServerSocketChannel 的父类构造器的时候,传入了一个OP_ACCEPT事件,这个事件的注册,后面会对其进行解析。创建Pipeline是为了给前面提到的ServerBootstrap链式调用中说到的Handler创建并放入pipeline做准备的。

初始化Channel

这里就是前面时序图中所说的,初始化 NioServerSocketChannel了,初始化Channel的调用是在io.netty.bootstrap.AbstractBootstrap#initAndRegister里面。那么来看下这个方法的实现,代码如下:

void init(Channel channel) throws Exception {
    Map<ChannelOption<?>, Object> options = this.options0();
    synchronized(options) {
        setChannelOptions(channel, options, logger);
    }

    Map<AttributeKey<?>, Object> attrs = this.attrs0();
    synchronized(attrs) {
        Iterator var5 = attrs.entrySet().iterator();

        while(true) {
            if (!var5.hasNext()) {
                break;
            }
            Entry<AttributeKey<?>, Object> e = (Entry)var5.next();
            AttributeKey<Object> key = (AttributeKey)e.getKey();
            channel.attr(key).set(e.getValue());
        }
    }

    ChannelPipeline p = channel.pipeline();
    final EventLoopGroup currentChildGroup = this.childGroup;
    final ChannelHandler currentChildHandler = this.childHandler;
    final Entry[] currentChildOptions;
    synchronized(this.childOptions) {
        currentChildOptions = (Entry[])this.childOptions.entrySet().toArray(newOptionArray(0));
    }

    final Entry[] currentChildAttrs;
    synchronized(this.childAttrs) {
        currentChildAttrs = (Entry[])this.childAttrs.entrySet().toArray(newAttrArray(0));
    }
    // ChannelInitializer一次性、初始化handler:
    // 负责添加一个ServerBootstrapAcceptor handler,添加完后,自己就移除了:
    // ServerBootstrapAcceptor handler: 负责接收客户端连接创建连接后,对连接的初始化工作。
    p.addLast(new ChannelHandler[]{new ChannelInitializer<Channel>() {
        public void initChannel(final Channel ch) throws Exception {
            final ChannelPipeline pipeline = ch.pipeline();
            ChannelHandler handler = ServerBootstrap.this.config.handler();
            if (handler != null) {
                pipeline.addLast(new ChannelHandler[]{handler});
            }
            ch.eventLoop().execute(new Runnable() {
                public void run() {
                    pipeline.addLast(new ChannelHandler[]{new ServerBootstrap.ServerBootstrapAcceptor(ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs)});
                }
            });
        }
    }});
}

注册Channel

注册Channel是在io.netty.bootstrap.AbstractBootstrap#initAndRegister方法中config().group().register(channel)代码的调用,config().group()就是获取所创建的NioEventLoopGroup,它里面有多个NioEventLoop,那我们来看下这个register(channel)方法的具体实现,代码如下:

io.netty.channel.MultithreadEventLoopGroup#register(io.netty.channel.Channel)

@Override
public ChannelFuture register(Channel channel) {
    // 注册
    return next().register(channel);
}

@Override
public EventLoop next() {
    // 从EventLoopGroup中取一个EventLoop
    return (EventLoop) super.next();
}

上面的register方法中通过调用next()方法,来调用每一个NioEventLoop来注册Channel,这个register方法的实现具体如下:

io.netty.channel.AbstractChannel.AbstractUnsafe#register

@Override
public ChannelFuture register(Channel channel) {
    return register(new DefaultChannelPromise(channel, this));
}

@Override
public ChannelFuture register(final ChannelPromise promise) {
    ObjectUtil.checkNotNull(promise, "promise");
    promise.channel().unsafe().register(this, promise);
    return promise;
}
// 这个方法中的eventLoop.execute(...)也是NioEventLoop启动的时机
@Override
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
    // 省略非关键代码
    AbstractChannel.this.eventLoop = eventLoop;
    // 判断是否是当前线程的
    if (eventLoop.inEventLoop()) {
        register0(promise);
    } else {
        try {
            eventLoop.execute(new Runnable() {
                @Override
                public void run() {
                    register0(promise);
                }
            });
        } catch (Throwable t) {
            // 省略非关键代码
        }
    }
}

private void register0(ChannelPromise promise) {
    try {
        if (!promise.setUncancellable() || !this.ensureOpen(promise)) {
            return;
        }
        boolean firstRegistration = this.neverRegistered;
        // 具体的注册操作
        AbstractChannel.this.doRegister();
        this.neverRegistered = false;
        AbstractChannel.this.registered = true;
        AbstractChannel.this.pipeline.invokeHandlerAddedIfNeeded();
        this.safeSetSuccess(promise);
        AbstractChannel.this.pipeline.fireChannelRegistered();
        //server socket的注册不会走进下面if,server socket接受连接创建的socket可以走进去。因为accept后就active了。
        if (AbstractChannel.this.isActive()) {
            if (firstRegistration) {
                // 监听OP_ACCEPT事件
                AbstractChannel.this.pipeline.fireChannelActive();
            } else if (AbstractChannel.this.config().isAutoRead()) {
                this.beginRead();
            }
        }
    } catch (Throwable var3) {
        // 省略非关键代码
    }
}

上面代码中的io.netty.channel.AbstractChannel.AbstractUnsafe#register方法首次执行时,NioEventLoop中的线程并没有启动,因此eventLoop.inEventLoop()返回的是false,任务便直接通过eventLoop.execute(...)方法来执行,而eventLoop.execute(...)方法的执行会导致线程启动。这就是把任务提交到NioEventLoop,来启动线程的代码,代码具体实现如下:

@Override
public void execute(Runnable task) {
    // 省略非关键代码
    boolean inEventLoop = inEventLoop();
    addTask(task);
    if (!inEventLoop) {
        startThread();
        if (isShutdown()) {
            boolean reject = false;
            try {
                if (removeTask(task)) {
                    reject = true;
                }
            } catch (UnsupportedOperationException e) {
            }
            if (reject) {
                reject();
            }
        }
    }
    if (!addTaskWakesUp && wakesUpForTask(task)) {
        wakeup(inEventLoop);
    }
}

io.netty.channel.nio.AbstractNioChannel#doRegister

当任务任务提交到NioEventLoop,来启动线程的时候便调用io.netty.channel.AbstractChannel.AbstractUnsafe#register0方法,代码实现具体如下:

@Override
protected void doRegister() throws Exception {
    boolean selected = false;
    for (;;) {
        try {
            // 把 ServerSocketChannel注册到Selector上,但是这里注册的是“0”,而非事件(对NIO的封装)
            selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
            return;
        } catch (CancelledKeyException e) {
            if (!selected) {
                eventLoop().selectNow();
                selected = true;
            } else {
                throw e;
            }
        }
    }
}

监听OP_ACCEPT事件

关于监听事件的调用是在io.netty.channel.AbstractChannel.AbstractUnsafe#register0方法中的pipeline.fireChannelActive()这行代码进行调用的,那么io.netty.channel.DefaultChannelPipeline#fireChannelActive方法代码逻辑大体如下:

@Override
public final ChannelPipeline fireChannelActive() {
    AbstractChannelHandlerContext.invokeChannelActive(head);
    return this;
}

static void invokeChannelActive(final AbstractChannelHandlerContext next) {
    EventExecutor executor = next.executor();
    if (executor.inEventLoop()) {
        next.invokeChannelActive();
    } else {
        executor.execute(new Runnable() {
            @Override
            public void run() {
                next.invokeChannelActive();
            }
        });
    }
}

private void invokeChannelActive() {
    if (invokeHandler()) {
        try {
            ((ChannelInboundHandler) handler()).channelActive(this);
        } catch (Throwable t) {
            notifyHandlerException(t);
        }
    } else {
        fireChannelActive();
    }
}

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

private void readIfIsAutoRead() {
    if (channel.config().isAutoRead()) {
        channel.read();
    }
}

上面代码中最后readIfIsAutoRead()方法中的channel.read()方法最终将会执行OP_ACCEPT事件注册过程。

总结

本篇文章主要是根据Netty Reactor和时序图进行的相关讲解:

  • 创建Boss NioEventLoopGroup
  • 创建多个Boss NioEventLoop,然后再每个Boss NioEventLoop上绑定一个Selector
  • 创建ServerBootstrap,并绑定端口及启动服务器
  • 创建NioServerSocketChannel
  • 初始化NioServerSocketChannel
  • 分配BossNioEventLoop
  • 注册NioServerSocketChannel到BossNioEventLoop里的Selector上
  • NioServerSocketChannel绑定端口
  • 注册NioServerSocketChannel的“读”事件
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值