成为资深程序猿不得不看的netty线程模型详解

301 阅读15分钟

Netty线程模型

Netty简介

Netty是一个高性能,高可扩展性的异步事件驱动的网络应用程序框架,它极大的简化了TCP和UDP客户端和服务器开发等网络编程.

Netty的4个重要内容:

  1. Reactor线程模型:一种高性能的多线程程序设计思路
  2. Netty中自己定义的Channel概念:增强版的通道概念
  3. ChannelPipeline职责链设计模式:事件处理机制
  4. 内存管理:增强的ByteBuffer缓冲区

Netty整体结构图

Netty官网

Netty线程模型1.png

从图中可以看出,Netty整体结构包含三个模块:

  1. 支持Socket等多种传输方式
  2. 提供了多种协议的编解码实现
  3. 核心设计包含事件处理模型,API的使用,ByteBuffer的增强

用户指南

源码地址

官方示例

Netty线程模型

为了让NIO处理更好的利用多线程特性,Netty实现了Reactor线程模型,Reactor模型中有4个核心概念:

  1. Resource资源(请求/任务)
  2. Synchronous Event Demultiplexer同步事件复用器
  3. Dispatcher分配器
  4. Request Handler请求处理器

Netty线程模型2.png

EventLoopGroup初始化过程

  1. 构造函数
  2. 确定线程数量
  3. new Executor:构建线程执行器
  4. for->new Child():构建EventLoop
  5. new EventExecutorChooser

EventLoopGroup可以分为两种,分别是Main和Sub,分别对应reactor和work,如下:

Netty线程模型3.png

可以打看到两组EventLoopGroup(Main/Sub)处理不同通道的不同事件.

以EchoServer中的EventLoopGroup bossGroup = new NioEventLoopGroup(1);为例,如下:

  1. 在NioEventLoopGroup通过构造函数构建NioEventLoopGroup
    public NioEventLoopGroup(int nThreads) {
        //nThreads ---> 线程数1
        this(nThreads, (Executor) null);
    }
    
    public NioEventLoopGroup(int nThreads, Executor executor) {
        //nThreads ---> 线程数1
        //executor ---> 线程任务执行器 null
        this(nThreads, executor, SelectorProvider.provider());
    }
    
    public NioEventLoopGroup(
            int nThreads, Executor executor, final SelectorProvider selectorProvider) {
        //nThreads ---> 线程数1
        //executor ---> 线程任务执行器 null
        //selectorProvider ---> nio中selector选择器提供程序
        this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);
    }
    
    public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,
                             final SelectStrategyFactory selectStrategyFactory) {
        //nThreads ---> 线程数1
        //executor ---> 线程任务执行器 null
        //selectorProvider ---> nio中selector选择器提供程序
        //selectStrategyFactory ---> 默认选择策略工厂
        super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
    }
    
  2. 之后在其父类MultithreadEventLoopGroup中调用构造函数继续构造
    /**
     * @see MultithreadEventExecutorGroup#MultithreadEventExecutorGroup(int, Executor, Object...)
     */
    protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
        //nThreads ---> 线程数1
        //executor ---> 线程任务执行器 null
        //selectorProvider ---> nio中selector选择器提供程序 ---> args
        //selectStrategyFactory ---> 默认选择策略工厂 ---> args
        //RejectedExecutionHandlers ---> 默认拒绝处理程序 ---> args
        super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);  //如果没有指定线程数量,默认使用CPU核数x2的线程数量
    }
    
    顾名思义,既然NioEventLoopGroup继承自MultithreadEventLoopGroup,那么它一定是一个多线程的线程池.
  3. 之后再调用MultithreadEventLoopGroup的父类MultithreadEventExecutorGroup中的构造函数继续构造
    protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) {
        //nThreads ---> 线程数1
        //executor ---> 线程任务执行器 null
        //DefaultEventExecutorChooserFactory ---> 默认事件执行器选择工厂从group中选择合适的eventLoop
        //selectorProvider ---> nio中selector选择器提供程序 ---> args
        //selectStrategyFactory ---> 默认选择策略工厂 ---> args
        //RejectedExecutionHandlers ---> 默认拒绝处理程序 ---> args
        this(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args);
    }
    
    protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                            EventExecutorChooserFactory chooserFactory, Object... args) {
        //nThreads ---> 线程数1
        //executor ---> 线程任务执行器 null
        //DefaultEventExecutorChooserFactory ---> 默认事件执行器选择工厂从group中选择合适的eventLoop
        //selectorProvider ---> nio中selector选择器提供程序 ---> args
        //selectStrategyFactory ---> 默认选择策略工厂 ---> args
        //RejectedExecutionHandlers ---> 默认拒绝处理程序 ---> args
    
        //检查设定的线程是否合法
        checkPositive(nThreads, "nThreads");
    
        if (executor == null) {
            //线程创建器不存在,新建一个线程任务执行器,创建NioEventLoop的时候使用
            //executor ---> 线程任务执行器 ThreadPerTaskExecutor
            executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
        }
    
        //根据线程数量创建事件执行器数组,事件执行器就是NioEventLoop的父类
        children = new EventExecutor[nThreads];
    
        for (int i = 0; i < nThreads; i ++) {
            boolean success = false;
            try {
                //在这儿目的是创建EventLoop事件执行器
                //针对NioEventLoopGroup目的是创建NioEventLoop
                //那么children最终是一个NioEventLoop数组,那么可见NioEventLoop就是事件执行器
                //携带线程任务执行器创建事件执行器,也就是EventLoopGroup中具体的一个
                children[i] = newChild(executor, args);
                success = true;
            } catch (Exception e) {
                // ---
            } finally {
                // ---
            }
        }
        // ---
    }
    
    /**
     * Create a new EventExecutor which will later then accessible via the {@link #next()}  method. This method will be
     * called for each thread that will serve this {@link MultithreadEventExecutorGroup}.
     *
     */
    protected abstract EventExecutor newChild(Executor executor, Object... args) throws Exception;
    
  4. newChild方法实际调用的是NioEventLoopGroup类中的具体实现,其目的是创建一个EventLoop(事件执行器),在这儿实际上是创建的NioEventLoop,不妨继续往下走
    /**
     * 创建EventLoopGroup中具体的事件执行器
     * @param executor 线程任务执行器
     * @param args 参数[selectorProvider, selectStrategyFactory, rejectedExecutionHandler]
     * @return 返回事件执行器,在这儿是具体的NioEventLoop
     * @throws Exception 貌似没有
     */
    @Override
    protected EventLoop newChild(Executor executor, Object... args) throws Exception {
        //executor ---> 线程任务执行器 ThreadPerTaskExecutor
        //selectorProvider ---> nio中selector选择器提供程序 ---> args 0
        //selectStrategyFactory ---> 默认选择策略工厂 ---> args 1
        //rejectedExecutionHandler ---> 默认拒绝处理程序 ---> args 2
        SelectorProvider selectorProvider = (SelectorProvider) args[0];
        SelectStrategyFactory selectStrategyFactory = (SelectStrategyFactory) args[1];
        RejectedExecutionHandler rejectedExecutionHandler = (RejectedExecutionHandler) args[2];
        EventLoopTaskQueueFactory taskQueueFactory = null;  //没有
        EventLoopTaskQueueFactory tailTaskQueueFactory = null; //没有
    
        int argsLength = args.length;
        if (argsLength > 3) {
            taskQueueFactory = (EventLoopTaskQueueFactory) args[3];
        }
        if (argsLength > 4) {
            tailTaskQueueFactory = (EventLoopTaskQueueFactory) args[4];
        }
        //创建NioEvent的实际代码,构造器创建
        return new NioEventLoop(this, executor, selectorProvider,
                selectStrategyFactory.newSelectStrategy(),
                rejectedExecutionHandler, taskQueueFactory, tailTaskQueueFactory);
    }
    
  5. 调用NioEventLoop的构造方法创建组中的一个NioEventLoop
    NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
                 SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler,
                 EventLoopTaskQueueFactory taskQueueFactory, EventLoopTaskQueueFactory tailTaskQueueFactory) {
        //parent ---> 所属组 NioEventLoopGroup
        //executor ---> 线程任务执行器 ThreadPerTaskExecutor
        //selectorProvider ---> nio中selector选择器提供程序
        //selectStrategy ---> 选择策略
        //rejectedExecutionHandler ---> 默认拒绝处理程序 RejectedExecutionHandler
        //taskQueueFactory ---> 任务队列工厂 null
        //tailTaskQueueFactory ---> tail任务队列工厂 null
        super(parent, executor, false, newTaskQueue(taskQueueFactory), newTaskQueue(tailTaskQueueFactory),
                rejectedExecutionHandler);
        this.provider = ObjectUtil.checkNotNull(selectorProvider, "selectorProvider");  //设置nio中的任务选择器提供者
        this.selectStrategy = ObjectUtil.checkNotNull(strategy, "selectStrategy");  //设置选择策略
        final SelectorTuple selectorTuple = openSelector();
        this.selector = selectorTuple.selector;  //设置nio中的selector选择器,也就是说在创建NioEventLoop的时候就已经创建了selector
        this.unwrappedSelector = selectorTuple.unwrappedSelector;  //这个不知道干啥的,也是一个选择器
    }
    
    protected SingleThreadEventLoop(EventLoopGroup parent, Executor executor,
                                    boolean addTaskWakesUp, Queue<Runnable> taskQueue, Queue<Runnable> tailTaskQueue,
                                    RejectedExecutionHandler rejectedExecutionHandler) {
        //parent ---> 所属组 NioEventLoopGroup
        //executor ---> 线程任务执行器 ThreadPerTaskExecutor
        //addTaskWakesUp ---> 增加任务时是否唤醒 false
        //taskQueue ---> 任务队列 Queue<Runnable>
        //tailTaskQueue ---> tail任务队列 Queue<Runnable>
        //rejectedExecutionHandler ---> 默认拒绝处理程序 RejectedExecutionHandler
        super(parent, executor, addTaskWakesUp, taskQueue, rejectedExecutionHandler);
        tailTasks = ObjectUtil.checkNotNull(tailTaskQueue, "tailTaskQueue");  //设置tail任务队列
    }
    
    protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,
                                        boolean addTaskWakesUp, Queue<Runnable> taskQueue,
                                        RejectedExecutionHandler rejectedHandler) {
        //parent ---> 所属组 NioEventLoopGroup
        //executor ---> 线程任务执行器 ThreadPerTaskExecutor
        //addTaskWakesUp ---> 增加任务时是否唤醒 false
        //taskQueue ---> 任务队列 Queue<Runnable>
        //rejectedExecutionHandler ---> 默认拒绝处理程序 RejectedExecutionHandler
        super(parent);
        this.addTaskWakesUp = addTaskWakesUp;  //设置在这个事件执行器中添加任务不唤醒
        this.maxPendingTasks = DEFAULT_MAX_PENDING_EXECUTOR_TASKS;  //设置最大任务数
        this.executor = ThreadExecutorMap.apply(executor, this); //设置线程执行器
        this.taskQueue = ObjectUtil.checkNotNull(taskQueue, "taskQueue"); //设置任务队列
        this.rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler"); //设置任务队列超出之后的拒绝策略
    }
    
    protected AbstractScheduledEventExecutor(EventExecutorGroup parent) {
        //parent ---> 所属组 NioEventLoopGroup
        super(parent);
    }
    
    protected AbstractEventExecutor(EventExecutorGroup parent) {
        //parent ---> 所属组 NioEventLoopGroup
        this.parent = parent; //设置所属组
    }
    

因此,最终总结下来就是通过EventLoopGroup bossGroup = new NioEventLoopGroup(1);本质上是创建了一个含有1个事件执行器的的事件执行组,那么NioEventLoop又是如何使用的?

EventLoop的启动

EventLoop自身实现了Executor类,当调用execute方法提交任务时,则判断是否启动,未启动则调用内置的executor创建新线程来触发run方法执行.

  1. execute:请求执行任务
  2. addTask:增加到任务队列
  3. 判断是否是EventLoop自身调用
  4. startThread -> doStartThread
  5. 使用executor创建新线程执行run

既然NioEventLoop可以认为是一个线程,那么必有其执行方法,只不过NioEventLoop没有具体的实现,而是在其父类SingleThreadEventExecutor中,如下:

@Override
    public void execute(Runnable task) {
        //task ---> 任务 Runnable

        //检查task是否为空
        ObjectUtil.checkNotNull(task, "task");
        //执行
        execute(task, !(task instanceof LazyRunnable) && wakesUpForTask(task));
    }
private void execute(Runnable task, boolean immediate) {
    //task ---> 任务 Runnable
    //immediate ---> 是否立刻执行(无需关注)

    boolean inEventLoop = inEventLoop(); //判断execute方法的调用者是不是和NioEventLoop事件执行器在同一个线程
    addTask(task); //将任务提交到任务队列taskQueue
    if (!inEventLoop) { //不是事件执行器所在线程的重复调用,则允许启动线程
        startThread(); //启动线程
        if (isShutdown()) {
            boolean reject = false;
            try {
                if (removeTask(task)) {
                    reject = true;
                }
            } catch (UnsupportedOperationException e) {
                // The task queue does not support removal so the best thing we can do is to just move on and
                // hope we will be able to pick-up the task before its completely terminated.
                // In worst case we will log on termination.
            }
            if (reject) {
                reject();
            }
        }
    }

    if (!addTaskWakesUp && immediate) {
        wakeup(inEventLoop);
    }
}

addTask:添加任务到任务队列

/**
 * Add a task to the task queue, or throws a {@link RejectedExecutionException} if this instance was shutdown
 * before.
 */
protected void addTask(Runnable task) {
    //task ---> 任务 Runnable
    ObjectUtil.checkNotNull(task, "task"); //判空
    if (!offerTask(task)) { //提交任务
        reject(task); //未成功执行拒绝策略
    }
}

final boolean offerTask(Runnable task) {
    //task ---> 任务 Runnable
    if (isShutdown()) {  //判断线程是否已经关闭
        reject(); //已经关闭执行决绝策略
    }
    return taskQueue.offer(task);  //将任务添加到taskQueue,此taskQueue就是在创建NioEventLoop的时候初始化的
}

startThread:启动线程

private void startThread() {
    if (state == ST_NOT_STARTED) {
        //执行CAS操作将事件执行器状态由ST_NOT_STARTED(1)修改为ST_STARTED(2)
        if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
            boolean success = false; //设置标记
            try {
                doStartThread(); //启动线程
                success = true; //启动成功
            } finally {
                //未启动则使用CAS操作将事件执行器的状态还原
                if (!success) {
                    STATE_UPDATER.compareAndSet(this, ST_STARTED, ST_NOT_STARTED);
                }
            }
        }
    }
}

doStartThread:启动线程

private void doStartThread() {
    assert thread == null; //判空
    //executor这个线程任务执行器是初始化NioEventLoop的时候传进来的,现在在NioEventLoop中执行任务就交给executor来执行
    executor.execute(new Runnable() {
        @Override
        public void run() {
            //获取执行execute的线程
            thread = Thread.currentThread();
            if (interrupted) {
                thread.interrupt();
            }

            boolean success = false;
            updateLastExecutionTime();
            try {
                //在此线程执行run方法
                //所以每个EventLoop中的任务都是执行run方法,实际上执行的是NioEventLoop中的run方法,做两件事:
                //1.轮询selector.select事件
                //2.执行taskQueue中的内容
                SingleThreadEventExecutor.this.run();
                success = true;
            } catch (Throwable t) {} finally {}
        }
    }
}

其中执行taskQueue中的内容不用多说,我们重点关注如何轮询selector.select事件

NioEventLoop.processSelectedKeys()

private void processSelectedKeys() {
    if (selectedKeys != null) {
        processSelectedKeysOptimized();
    } else {
        //携带选择器中的事件去轮询,这个选择器是初始化NioEventLoop的时候生成的,害为了这个看了两遍前面的
        //但是这个选择器和通道绑定后才能生效使用(执行这些事件的时候肯定已经绑定了)
        //从绑定了通道的selector中读取事件
        processSelectedKeysPlain(selector.selectedKeys());
    }
}

NioEventLoop.processSelectedKeysPlain()

/**
 * 处理事件
 * @param selectedKeys 事件集合
 */
private void processSelectedKeysPlain(Set<SelectionKey> selectedKeys) {
    // check if the set is empty and if so just return to not create garbage by
    // creating a new Iterator every time even if there is nothing to process.
    // See https://github.com/netty/netty/issues/597
    if (selectedKeys.isEmpty()) { //没有事件
        return;
    }

    //遍历查询结果
    Iterator<SelectionKey> i = selectedKeys.iterator();
    //轮询
    for (;;) {
        //被封装的事件
        final SelectionKey k = i.next();
        //获取事件对应通道
        final Object a = k.attachment();
        i.remove(); //从校核中移除事件

        if (a instanceof AbstractNioChannel) { //判断是否是netty通道
            //处理单个事件
            processSelectedKey(k, (AbstractNioChannel) a);
        } else {
            @SuppressWarnings("unchecked")
            NioTask<SelectableChannel> task = (NioTask<SelectableChannel>) a;
            processSelectedKey(k, task);
        }

        if (!i.hasNext()) {
            break;
        }

        if (needsToSelectAgain) {
            selectAgain();
            selectedKeys = selector.selectedKeys();

            // Create the iterator again to avoid ConcurrentModificationException
            if (selectedKeys.isEmpty()) {
                break;
            } else {
                i = selectedKeys.iterator();
            }
        }
    }
}

NioEventLoop.processSelectedKey()

private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
    //k ---> 被封装的事件
    //ch ---> 获取事件对应netty通道
    final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe();

    if (!k.isValid()) { //判断此事件是否有效(无效进入此逻辑关闭unsafe)
        final EventLoop eventLoop;
        try {
            eventLoop = ch.eventLoop();  //获取nio事件执行器
        } catch (Throwable ignored) {
            // If the channel implementation throws an exception because there is no event loop, we ignore this
            // because we are only trying to determine if ch is registered to this event loop and thus has authority
            // to close ch.
            return;
        }
        // Only close ch if ch is still registered to this EventLoop. ch could have deregistered from the event loop
        // and thus the SelectionKey could be cancelled as part of the deregistration process, but the channel is
        // still healthy and should not be closed.
        // See https://github.com/netty/netty/issues/5125
        if (eventLoop == this) {
            // close the channel if the key is not valid anymore
            unsafe.close(unsafe.voidPromise());
        }
        return;
    }

    try {
        int readyOps = k.readyOps(); //获取事件类型
        // We first need to call finishConnect() before try to trigger a read(...) or write(...) as otherwise
        // the NIO JDK channel implementation may throw a NotYetConnectedException.
        if ((readyOps & SelectionKey.OP_CONNECT) != 0) { //connect事件主要用于客户端
            // remove OP_CONNECT as otherwise Selector.select(..) will always return without blocking
            // See https://github.com/netty/netty/issues/924
            int ops = k.interestOps();
            ops &= ~SelectionKey.OP_CONNECT;
            k.interestOps(ops);

            unsafe.finishConnect();
        }

        // Process OP_WRITE first as we may be able to write some queued buffers and so free memory.
        if ((readyOps & SelectionKey.OP_WRITE) != 0) {
            // Call forceFlush which will also take care of clear the OP_WRITE once there is nothing left to write
            //write事件在这儿处理
            ch.unsafe().forceFlush();
        }

        // Also check for readOps of 0 to workaround possible JDK bug which may otherwise lead
        // to a spin loop
        if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
            //accept和read都在这儿进行处理(服务端重点关注)
            unsafe.read();
        }
    } catch (CancelledKeyException ignored) {
        unsafe.close(unsafe.voidPromise());
    }
}

通过查看源代码当前可以知道,EventLoop本身不是一个线程,它的线程时通过线程创建器创建的,之后执行EventLoop中的run方法,去执行任务队列taskQueue中的内容,以及事件选择器Selector.

轮询的机制确实是这样,但是到目前位置还没有看到有通道绑定以及事件的通知,继续吧...

bind绑定端口过程

  1. bind(端口):AbstractBootStrap
  2. 创建和初始化channel
  3. 注册到EventLoop中的Selector上(提交任务到EventLoop执行),注册完成后再继续绑定
  4. doBind() -> channel.bind
  5. pipeline.bind(责任链)
  6. HeadContext.bind
  7. AbstractUnsafe.bind
  8. NioServerSocketChannel.doBind

EchoServer

ChannelFuture f = b.bind(PORT).sync();

AbstractBootstrap

/**
 * Create a new {@link Channel} and bind it. 创建通道并绑定端口
 */
public ChannelFuture bind(int inetPort) {
    //绑定端口的入口方法
    return bind(new InetSocketAddress(inetPort));
}
/**
 * Create a new {@link Channel} and bind it.
 */
public ChannelFuture bind(SocketAddress localAddress) {
    //校验group和channelFactory
    validate();
    //执行绑定代码
    return doBind(ObjectUtil.checkNotNull(localAddress, "localAddress"));
}
private ChannelFuture doBind(final SocketAddress localAddress) {
    //初始化ServerSocketChannel对象,并注册到selector选择器
    final ChannelFuture regFuture = initAndRegister();
    final Channel channel = regFuture.channel(); //获取初始化的通道
    if (regFuture.cause() != null) { //通道没有注册完成
        return regFuture;
    }

    // channel注册完成后再开始绑定端口,防止端口开放了却不能正常处理请求
    if (regFuture.isDone()) {
        // At this point we know that the registration was complete and successful.
        ChannelPromise promise = channel.newPromise();
        //实际处理端口绑定的方法
        doBind0(regFuture, channel, localAddress, promise);
        return promise;
    } else {
        // Registration future is almost always fulfilled already, but just in case it's not.
        final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
        regFuture.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                Throwable cause = future.cause();
                if (cause != null) {
                    // Registration on the EventLoop failed so fail the ChannelPromise directly to not cause an
                    // IllegalStateException once we try to access the EventLoop of the Channel.
                    promise.setFailure(cause);
                } else {
                    // Registration was successful, so set the correct executor to use.
                    // See https://github.com/netty/netty/issues/2586
                    promise.registered();

                    doBind0(regFuture, channel, localAddress, promise);
                }
            }
        });
        return promise;
    }
}
final ChannelFuture initAndRegister() {
    Channel channel = null;
    //初始化init
    try {
        //创建一个netty的通道
        channel = channelFactory.newChannel();
        //初始化
        init(channel);
    } catch (Throwable t) {
        if (channel != null) {
            // channel can be null if newChannel crashed (eg SocketException("too many open files"))
            channel.unsafe().closeForcibly();
            // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
            return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
        }
        // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
        return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
    }

    //选择一个事件执行器,将初始化的通道与EventLoop(Selector)进行绑定
    //config().group() ---> EventLoopGroup
    //故而register应该是EventLoopGroup的方法可以查找
    //EventLoopGroup没有查找其父类
    ChannelFuture regFuture = config().group().register(channel);
    if (regFuture.cause() != null) { //没有注册完成
        if (channel.isRegistered()) { //通道已经被注册
            channel.close(); //销毁通道
        } else {
            channel.unsafe().closeForcibly(); //立即关闭通道
        }
    }

    // If we are here and the promise is not failed, it's one of the following cases:
    // 1) If we attempted registration from the event loop, the registration has been completed at this point.
    //    i.e. It's safe to attempt bind() or connect() now because the channel has been registered.
    // 2) If we attempted registration from the other thread, the registration request has been successfully
    //    added to the event loop's task queue for later execution.
    //    i.e. It's safe to attempt bind() or connect() now:
    //         because bind() or connect() will be executed *after* the scheduled registration task is executed
    //         because register(), bind(), and connect() are all bound to the same thread.

    return regFuture;
}

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

config().group()一定返回的是EventLoopGroup,故而register应该是EventLoopGroup的方法可以查找,而EventLoopGroup中的方法是抽象方法,故而应该去找其实现类,我们知道在这儿调用的实际上是一个NioEventLoopGroup,故而应该在NioEventLoopGroup中去查找该方法,未查询到,查找其父类MultithreadEventLoopGroup,从中查询到register方法,如下:

@Override
public ChannelFuture register(Channel channel) {
    //next()选择一个合适的NioEventLoop进行绑定 ---> EventLoop(Selector) ---> NioEventLoop
    //故而调用NioEventLoop的register方法
    //从NioEventLoop中查找到register方法,但是通过参数可以发现一定调用的不是这个方法
    //故而应该查询其父类的方法
    return next().register(channel);
}

next().register(channel);

next()选择一个合适的EventLoop(NioEventLoop)进行绑定,故而调用NioEventLoop的register方法,从NioEventLoop中查找到register方法,但是通过参数可以发现一定调用的不是这个方法,故而应该查询其父类的方法.最终从NioEventLoop的父类SingleThreadEventLoop中查询到register方法,如下:

@Override
public ChannelFuture register(Channel channel) {
    //执行通道绑定到NioEventLoop的相关代码
    return register(new DefaultChannelPromise(channel, this));
}
@Override
public ChannelFuture register(final ChannelPromise promise) {
    //NioServerSocketChannel -> NioMessageUnsafe
    ObjectUtil.checkNotNull(promise, "promise");
    //promise.channel() --=> NioServerSocketChannel
    //故而unsafe方法一定是NioServerSocketChannel的方法
    //从NioServerSocketChannel中未查询到其方法,从其父类AbstractNioMessageChannel中查询
    //从AbstractNioMessageChannel为查询到其方法,从其父类AbstractNioChannel中查询
    //最终从AbstractChannel中查询到unsafe方法,是在构造AbstractChannel对象时使用newUnsafe()创建的此值
    //因此我们如果要知道unsafe的方法具体的返回值就要从构造方法入手

    //首先从NioServerSocketChannel查询newUnsafe方法
    //最终从其父类中查询到此方法返回一个NioMessageUnsafe实例

    //故而register一定是NioMessageUnsafe的方法
    //最终从NioMessageUnsafe的父类AbstractUnsafe中查询到register方法

    //故而通道绑定实际调用的还是Channel的register方法
    promise.channel().unsafe().register(this, promise);
    return promise;
}

promise.channel().unsafe().register(this, promise)

promise.channel()的返回值是一个通道,可以明确知道是NioServerSocketChannel,故而unsafe方法一定是NioServerSocketChannel的方法,从NioServerSocketChannel中未查询到其方法,从其父类AbstractNioMessageChannel中查询,从AbstractNioMessageChannel为查询到其方法,从其父类AbstractNioChannel中查询,最终从AbstractChannel中查询到unsafe方法,是在构造AbstractChannel对象时使用newUnsafe()创建的此值

@Override
public Unsafe unsafe() {
    return unsafe;
}
protected AbstractChannel(Channel parent) {
    this.parent = parent;
    id = newId();
    unsafe = newUnsafe();
    pipeline = newChannelPipeline();
}

因此要知道unsafe具体是什么实例,就要探究newUnsafe()方法,既然是在构造方法中进行初始化的,就要从头开始查找,首先从NioServerSocketChannel查询newUnsafe方法,最终从其父类中查询到此方法返回一个NioMessageUnsafe实例

@Override
protected AbstractNioUnsafe newUnsafe() {
    return new NioMessageUnsafe();
}

到此可以明确知晓,实际调用register方法的对象时NioMessageUnsafe对象,因此可以从NioMessageUnsafe中查询register方法,最终从NioMessageUnsafe的父类AbstractUnsafe中查询到register方法,如下:

@Override
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
    //eventLoop ---> 选择器
    //promise --->通道
    ObjectUtil.checkNotNull(eventLoop, "eventLoop");
    if (isRegistered()) {
        promise.setFailure(new IllegalStateException("registered to an event loop already"));
        return;
    }
    if (!isCompatible(eventLoop)) {
        promise.setFailure(
                new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
        return;
    }

    AbstractChannel.this.eventLoop = eventLoop;

    //判断调用绑定的方法的线程是不是选择器线程,如果不是以线程的方式提交
    if (eventLoop.inEventLoop()) {
        //实际绑定过程
        register0(promise);
    } else {
        try {
            //一旦触发了任务提交,eventLoop就会开始正式执行工作,轮询
            eventLoop.execute(new Runnable() {
                @Override
                public void run() {
                    register0(promise);
                }
            });
        } catch (Throwable t) {
            logger.warn(
                    "Force-closing a channel whose registration task was not accepted by an event loop: {}",
                    AbstractChannel.this, t);
            closeForcibly();
            closeFuture.setClosed();
            safeSetFailure(promise, t);
        }
    }
}
private void register0(ChannelPromise promise) {
    try {
        // check if the channel is still open as it could be closed in the mean time when the register
        // call was outside of the eventLoop
        if (!promise.setUncancellable() || !ensureOpen(promise)) {
            return;
        }
        boolean firstRegistration = neverRegistered;
        doRegister();  //NioChannel中,将Channel与NioEventLoop进行绑定

        //到此为止注册完成


        neverRegistered = false;
        registered = true;

        // Ensure we call handlerAdded(...) before we actually notify the promise. This is needed as the
        // user may already fire events through the pipeline in the ChannelFutureListener.
        pipeline.invokeHandlerAddedIfNeeded();

        safeSetSuccess(promise);
        pipeline.fireChannelRegistered();
        // Only fire a channelActive if the channel has never been registered. This prevents firing
        // multiple channel actives if the channel is deregistered and re-registered.
        if (isActive()) {
            if (firstRegistration) {
                pipeline.fireChannelActive();
            } else if (config().isAutoRead()) {
                // This channel was registered before and autoRead() is set. This means we need to begin read
                // again so that we process inbound data.
                //
                // See https://github.com/netty/netty/issues/4805
                beginRead();
            }
        }
    } catch (Throwable t) {
        // Close the channel directly to avoid FD leak.
        closeForcibly();
        closeFuture.setClosed();
        safeSetFailure(promise, t);
    }
}

到此为止理清了initAndRegister方法,通道已经绑定,事件开始轮询,之后的事情就是开放端口接收请求了

doBind0(regFuture, channel, localAddress, promise);

这是实际处理端口绑定的方法

private static void doBind0(
        final ChannelFuture regFuture, final Channel channel,
        final SocketAddress localAddress, final ChannelPromise promise) {

    // This method is invoked before channelRegistered() is triggered.  Give user handlers a chance to set up
    // the pipeline in its channelRegistered() implementation.
    channel.eventLoop().execute(new Runnable() {
        @Override
        public void run() {  //想NioEventLoop提交任务进行端口绑定
            //注册完成并且成功
            if (regFuture.isSuccess()) {
                //绑定
                channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
            } else {
                promise.setFailure(regFuture.cause());
            }
        }
    });
}
@Override
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
    //触发一个netty职责链中的绑定事件,由应用层代码发起到底层,属于outBound
    return pipeline.bind(localAddress, promise);
}

之后的绑定是netty的职责链需要做的事,到这儿知道端口已经放通就可以了.

小站地址:http://175.24.172.160:3000/#/netty/