Netty源码分析

Netty 是一个很精致的框架,非常值得Java程序员来学习,为什么说很精致呢?

在网络通信里的大多数问题它都给你解决了,很多还是定制化的。更有:
1、异步非阻塞通信
2、高效的Reactor线程模型
3、无锁化的串行设计理念
4、高效的使用并发编程技术
5、高性能的序列化框架
6、操作系统的零拷贝技术
7、内存池的设计理念
8、灵活的TCP参数配置

这些编程技巧学会了,无论是提升工作能力还是面试装X 都是极好 Netty源码分析Netty源码分析

除了以上的优点,netty 很多性能优化都在尽力做到极致, 比如:

Netty源码分析

jdk 的 selectkey 是基于 hashset 实现的,
每个 节点对象 都多存了一个不用的 value 对象, netty 认为它浪费了内存
netty 优化成基于数组来实现,
节约了空间,减少了GC
基于哪怕只优化了 1~2% 的性能 。

如此花功夫的讲究,不可谓不精致

这些内容在以后的文章中都会介绍~
下面开始进入正题:

先罗列一下源码分析的主线:

基于 Reactor 模型的实现:
bossGroup处理客户端的连接请求,
对应处理的 channel 对象是
ServerSocketChannel

workerGroup处理业务请求,
对应处理的 channel 对象是 SocketChannel

Server 线程 :

  1. 创建 selector
  2. 创建 ServerSocketChannel
  3. 初始化 ServerSocketChannel
  4. 给 ServerSocketChannel 从
    BossGroup 中选择一个 NioEventLoop

BossGroup :

  1. 将 ServerSocketChannel 注册到选择的
    NioEventLoop 的 selector 上
    1. 绑定地址启动
  2. 注册接收连接的事件( OP_ACCEPT )
    到 selector 上

ServerSocketChannel :

  1. 初始化 option 对 TCP 的一些配置
  2. 初始化 attribute 给 channel 设置的属性
  3. 创建初始化一个 pipeline
  4. 设置一些对 childChannel 所需要的属性到
    一个handler里,放到
    ServerSocketChannel 的 pipeline 中
    1. 将 ServerSocketChannel
      注册到 eventLoop 的 selector 上
    2. 绑定端口并监听
      OP_ACCEPT 事件

Netty 是如何启动服务的呢?
来看一个demo 例子:

public final class EchoServer {

    public static void main(String[] args) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        final EchoServerHandler serverHandler = new EchoServerHandler();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup,workerGroup)
                .channel(NioServerSocketChannel.class)
                .handler(new LoggingHandler(LogLevel.INFO))
                .option(ChannelOption.SO_BACKLOG, 100)
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline p = ch.pipeline();
                        p.addLast(new LoggingHandler(LogLevel.INFO));
                        p.addLast(serverHandler);
                    }
                });

            ChannelFuture f = b.bind(8080).sync();
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
        }
    }
}

下面我们就根据这个简单的demo开始源码分析:

干了什么呢?

EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();

创建了一个 bossGroup :
bossGroup 会 调用 newChild() 去创建 eventLoop,
eventLoop 的构造器会调用 openSelector()
去创建 一个selector 轮询 注册的
ServerSocketChannel 去处理用户的连接请求

创建了一个workerGroup ,
workerGroup 里的eventLoop
会绑定channel 去处理用户的读写请求

ServerBootstrap b = new ServerBootstrap();

ServerBootstrap 是一个辅助类,
用来启动服务和完成一些组件的初始化,
1、ServerBootstrap
把 bossGroup 和 workerGroup
作为参数保存在了自己的属性当中。

2、通过 channle方法 传入了
NioServerSocketChannel.Class 对象;
这是为了创建 ServerSocketChannel
对象注册给 BossGroup创建的selector

3、创建了一个LoggingHandler
这个是用来记录日志的handler

4、设置了TCP 连接的 keepalive 属性

5、再通过ChannelInitializer 对象
初始化了用来 创建SocketChannel对象

6、bing方法 绑定了 8080 端口 服务启动完成

7、finally 代码块里 在服务器关闭的时候优雅的关闭workerGroup里的所有资源

首先看 new NioEventLoopGroup() 的初始化过程:
点进源码会走到 MultithreadEventExecutorGroup

protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
        super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
    }
 static {
        DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
                "io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));

        if (logger.isDebugEnabled()) {
            logger.debug("-Dio.netty.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS);
        }
    }

看到 NettyRuntime.availableProcessors() * 2
当我们对 NioEventLoopGroup这个线程池没有给参数的时候,它的核心线程数是 CPU核心的两倍

protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                            EventExecutorChooserFactory chooserFactory, Object... args) {
        if (nThreads <= 0) {
            throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
        }

        if (executor == null) {
            executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
        }
        // 根据核心线程数创建eventLoop的线程数组 用来存放 eventLoop
        children = new EventExecutor[nThreads];

        for (int i = 0; i < nThreads; i ++) {
            boolean success = false;
            try {
            // 这里是创建 eventLoop
                children[i] = newChild(executor, args);
                success = true;
            } catch (Exception e) {
                // TODO: Think about if this is a good exception type
                throw new IllegalStateException("failed to create a child event loop", e);
            } finally {
                if (!success) {
                    for (int j = 0; j < i; j ++) {
                        children[j].shutdownGracefully();
                    }

                    for (int j = 0; j < i; j ++) {
                        EventExecutor e = children[j];
                        try {
                            while (!e.isTerminated()) {
                                e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
                            }
                        } catch (InterruptedException interrupted) {
                            // Let the caller handle the interruption.
                            Thread.currentThread().interrupt();
                            break;
                        }
                    }
                }
            }
        }

 // 省略不重要的代码
    }

进入 newChild 方法的实现类 NioEventLoopGroup

 @Override
    protected EventLoop newChild(Executor executor, Object... args) throws Exception {
        EventLoopTaskQueueFactory queueFactory = args.length == 4 ? (EventLoopTaskQueueFactory) args[3] : null;
        return new NioEventLoop(this, executor, (SelectorProvider) args[0],
            ((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2], queueFactory);
    }
NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
                 SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler,
                 EventLoopTaskQueueFactory queueFactory) {
        super(parent, executor, false, newTaskQueue(queueFactory), newTaskQueue(queueFactory),
                rejectedExecutionHandler);
        if (selectorProvider == null) {
            throw new NullPointerException("selectorProvider");
        }
        if (strategy == null) {
            throw new NullPointerException("selectStrategy");
        }
        provider = selectorProvider;
        // openSelector 这里去拿到 一个Java Nio 包下的 selector 对象
        final SelectorTuple selectorTuple = openSelector();
        selector = selectorTuple.selector;
        unwrappedSelector = selectorTuple.unwrappedSelector;
        selectStrategy = strategy;
    }

这几段代码干的事情有:
1、eventLoopGroup无参的情况下创建一个核心线程数是CPU*2的线程池

2、循环的往 EventExecutor[] children 这个 线程数组里面放 eventLoop对象,后面 无论是ServerSocketChannel 跟 bossEventLoop 还是 SocketChannel 和 workerEventLoop 绑定 时,得到eventLoop对象 都是从 children 这个线程数组里面拿。

3、 EventLoop的构造方法会创建一个 Selector 作为属性自己保存起来后续会channel 和 eventLoop绑定时会用到。

再往下看到核心流程代码的 第8 行:
也就是 ServerBootstrap 的构造方法,
点进去是个空实现,
不过没关系,我们可以先看看它的几个属性

   // 绑定给 worker eventloop的 socketChannel 的配置信息
   private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap<ChannelOption<?>, Object>();
    private final Map<AttributeKey<?>, Object> childAttrs = new LinkedHashMap<AttributeKey<?>, Object>();
   // 用来获取 eventloopGroup的
    private final ServerBootstrapConfig config = new ServerBootstrapConfig(this);
    // workerGroup对象
    private volatile EventLoopGroup childGroup;
    // socketChannel 的 handler 
    private volatile ChannelHandler childHandler;

ServerBootstrap 继承 AbstractBootstrap
我们往下看到第九行:链式调用group();
将bossGroup和WorkerGroup传入,
bossGroup赋值给了 父类 AbstractBootstrap
workerGroup 赋值给了自己
ServerBootstrap 的 childGroup 属性。

第10行 channel 方法传入
NioServerSocketChannel.Class
后续初始化相关组件时会根据这个Class对象创建
NioServerSocketChannel对象。

第11行 设置一个 日志handler

第12行 设置TCP 的配置参数

第13行 设置 TCP keepalive 的配置

第14行 childHandler 方法传入一个 handler,这里的 ChannelInitializer handler 主要是把像个中介一样 把我们的 自定义的 handler 放到 pipeline 中去,然后把自己删除

好的,终于走到了 bind() 方法了。走进去瞧瞧
AbstractBootstrap 的 doBind(address) 方法

dobind() 干了两件事 :
1、initAndRegister
2、然后完成 doBind

initAndRegister 做了三件事情:

  1. 创建一个 ServerSocketChannel
  2. 初始化 ServerSocketChannel
  3. 将 ServerSocketChannelregister
    注册到 eventLoop 的 selector 上

可以看到 initAndRegister() 的返回值是一个 future
说明这是一个异步的操作
那么 regFuture.isDone 如果完成了就会进行 doBind
否则 将 doBind 的操作 封装成一个 task
丢给 future的listener 里面,
等待 register 的完成来异步通知 listener 的执行

private ChannelFuture doBind(final SocketAddress localAddress) {
        //  初始化 并 注册 channel
        final ChannelFuture regFuture = initAndRegister();
        final Channel channel = regFuture.channel();
        if (regFuture.cause() != null) {
            return regFuture;
        }
        // 不一定 立马就 register 完成 ,因为 register 是交给了
        // nioEventLoop 去执行的 这是一个异步 过程
        if (regFuture.isDone()) {
            // At this point we know that the registration was complete and successful.
            ChannelPromise promise = channel.newPromise();
            // 开始dobind 干活了
            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);
            // 等着 register 完成再来 bind
            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;
        }
    }

点进 initAndRegister () 瞧瞧

final ChannelFuture initAndRegister() {
        Channel channel = null;
        try {
            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);
        }

        ChannelFuture regFuture = config().group().register(channel);
        if (regFuture.cause() != null) {
            if (channel.isRegistered()) {
                channel.close();
            } else {
                channel.unsafe().closeForcibly();
            }
        }

通过 channelFactory 工厂创建一个 channnel,那这个是什么channel 呢?
还记得我们在第一个主流程里传入的 NioServerSocketChannel 对象么?

// 这里传入 NioServerSocketChannel.Class 通过反射 拿到实例化对象 
public ReflectiveChannelFactory(Class<? extends T> clazz) {
        ObjectUtil.checkNotNull(clazz, "clazz");
        try {
            this.constructor = clazz.getConstructor();
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +
                    " does not have a public non-arg constructor", e);
        }
    }
    @Override
    public T newChannel() {
        try {
            return constructor.newInstance();
        } catch (Throwable t) {
            throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
        }
    }

再注意一下 创建 NioServerSocketChannel 时
会给父类的 AbstractNioChannel 的
readInterestOp 属性 set 一个值
这个值是 SelectionKey.OP_ACCEPT 1<< 4(16)

/**
     * Create a new instance using the given {@link ServerSocketChannel}.
     */
    public NioServerSocketChannel(ServerSocketChannel channel) {
        super(null, channel, SelectionKey.OP_ACCEPT);
        config = new NioServerSocketChannelConfig(this, javaChannel().socket());
    }

然后回到 init(channel); 进去 ServerBootStrap 的实现类

@Override
    void init(Channel channel) throws Exception {
    // 拿到 对 SocketChannel 的相关诶之
        final Map<ChannelOption<?>, Object> options = options0();
        synchronized (options) {
            setChannelOptions(channel, options, logger);
        }

        final Map<AttributeKey<?>, Object> attrs = attrs0();
        synchronized (attrs) {
            for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
                @SuppressWarnings("unchecked")
                AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
                channel.attr(key).set(e.getValue());
            }
        }
        // 获取一个 pipeline 对象
        ChannelPipeline p = channel.pipeline();
        // workerGroup对象
        final EventLoopGroup currentChildGroup = childGroup;
         // socketChannel 的 handler 
        final ChannelHandler currentChildHandler = childHandler;
         // 绑定给 worker eventloop的 socketChannel 的配置信息
        final Entry<ChannelOption<?>, Object>[] currentChildOptions;
        final Entry<AttributeKey<?>, Object>[] currentChildAttrs;
        synchronized (childOptions) {
            currentChildOptions = childOptions.entrySet().toArray(newOptionArray(0));
        }
        synchronized (childAttrs) {
            currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0));
        }
   // ChannelInitializer  是一个 一个性 初始化的 handler
// 负责 添加一个ServerBootStrapAcceptor handele 添加完以后 自己就在 pipeline 中移除了
// ServerBootStrapAcceptor  负责接收 客户端创建连接后 对连接的初始化工作
        p.addLast(new ChannelInitializer<Channel>() {
            @Override
            public void initChannel(final Channel ch) throws Exception {
                final ChannelPipeline pipeline = ch.pipeline();
                ChannelHandler handler = config.handler();
                if (handler != null) {
                    pipeline.addLast(handler);
                }

                ch.eventLoop().execute(new Runnable() {
                    @Override
                    public void run() {
                        pipeline.addLast(new ServerBootstrapAcceptor(
                                ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                    }
                });
            }
        });
    }

上面这四个核心属性都是为了帮我们初始化 socketChannel 使用的,也就是用来处理读写请求的 channel

ChannelInitializer:

主要是把像个中介一样 把我们的 自定义的 handler 放到 pipeline 中去,然后把自己删除

ServerBootStrapAcceptor :

是负责接收客户端创建的连接后 为我们的连接进行初始化 工作 所以它需要我们对 socketChannel 相关的配置
然后把ServerBootStrapAcceptor 这个handler
放到 pipeline 中 交给 bossEventLoop

初始化 channel 完成后就开始准备注册了,
看到 initAndRegister() 的
config().group().register(channel)

这里是把ServersocketChannel
绑定给了 bossEventLoop
进入register 可以看到
MultithreadEventLoopGroup 类的 next().register()
next() 提供一个eventLoop
给 channel 来注册

有两种方式:
一个是PowerOfTwoEventExecutorChooser
和 GenericEventExecutorChooser 的next 方法
GenericEventExecutorChooser采用 直接取模的方式
而 PowerOfTwoEventExecutorChooser
采用的是与运算的方式 毫无疑问
与运算的效率会更高

public EventExecutorChooser newChooser(EventExecutor[] executors) {
        if (isPowerOfTwo(executors.length)) {
            return new PowerOfTwoEventExecutorChooser(executors);
        } else {
            return new GenericEventExecutorChooser(executors);
        }
    }

    private static boolean isPowerOfTwo(int val) {
        return (val & -val) == val;
    }

    private static final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser {
        private final AtomicInteger idx = new AtomicInteger();
        private final EventExecutor[] executors;

        PowerOfTwoEventExecutorChooser(EventExecutor[] executors) {
            this.executors = executors;
        }

        @Override
        public EventExecutor next() {
            return executors[idx.getAndIncrement() & executors.length - 1];
        }
    }

    private static final class GenericEventExecutorChooser implements EventExecutorChooser {
        private final AtomicInteger idx = new AtomicInteger();
        private final EventExecutor[] executors;

        GenericEventExecutorChooser(EventExecutor[] executors) {
            this.executors = executors;
        }

        @Override
        public EventExecutor next() {
            return executors[Math.abs(idx.getAndIncrement() % executors.length)];
        }
    }

得到eventLoop对象后 进入 AbstractChannel 的 register() 

 @Override
        public final void register(EventLoop eventLoop, final ChannelPromise promise) {
           // 只保留了部分核心流程代码
            AbstractChannel.this.eventLoop = eventLoop;
          // 判断当前线程是不是 eventLoop 线程,服务刚刚起来
          // 还是 main 线程 所以不是 eventLoop 线程 进 else 的逻辑
            if (eventLoop.inEventLoop()) {
                register0(promise);
            } else {
                try {
                    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);
                }
            }
        }

看到了register0() 被包装成 一个 task 丢到了 eventLoop 里去了,点进 excute 方法看看, 进入 SingleThreadEventExecutor 的 excute()

@Override
    public void execute(Runnable task) {
        if (task == null) {
            throw new NullPointerException("task");
        }

        boolean inEventLoop = inEventLoop();
        // 把 register0() 加到 eventLoop 的阻塞队列中
        addTask(task);
        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 && wakesUpForTask(task)) {
            wakeup(inEventLoop);
        }
    }

启动线程后 我们进入 register0() ,
立马就看到了激动人心的 doRegister()
看到do开头的方法很容易想到它是干活的了
进入 AbstractNioChannel 类的 doRegister() 方法:

@Override
    protected void doRegister() throws Exception {
        boolean selected = false;
        for (;;) {
            try {
      //  可以看到 将 serverSocketChannel 注册给了  Selector 
                selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
                return;
            } catch (CancelledKeyException e) {
                if (!selected) {
                    // Force the Selector to select now as the "canceled" SelectionKey may still be
                    // cached and not removed because no Select.select(..) operation was called yet.
                    eventLoop().selectNow();
                    selected = true;
                } else {
                    // We forced a select operation on the selector before but the SelectionKey is still cached
                    // for whatever reason. JDK bug ?
                    throw e;
                }
            }
        }
    }

eventLoop 的 selector 是哪儿来的呢?
在初始化 主线程 eventLoopGroup 的时候会调
MultithreadEventExecutorGroup
的 MultithreadEventExecutorGrou()
会调用到 newChild(executor, args)
newChild 的构造方法会调用 openSelector 方法初始化 selector

回到 dobind0() 完成最后的 绑定端口 就算完成整个初始化过程了
点进去跳到 AbstractChannel 的bind 方法,

@Override
    public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
        return pipeline.bind(localAddress, promise);
    }

看到了一个 pipeline,pipeline 是一个双向链表,里面有很多handler,我们直接进入关键的 bind 方法 DefaultChannelPipeline 类的 bind 方法

@Override
        public void bind(
                ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) {
            unsafe.bind(localAddress, promise);
        }

回到 AbstractChannel 的bind 方法

@Override
        public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
          // 省略不关键代码

            boolean wasActive = isActive();
            try {
            // 真正绑定端口方法
                doBind(localAddress);
            } catch (Throwable t) {
                safeSetFailure(promise, t);
                closeIfClosed();
                return;
            }
            // 绑定后才开始激活
            if (!wasActive && isActive()) {
                invokeLater(new Runnable() {
                    @Override
                    public void run() {
                    // 最后 激活
                        pipeline.fireChannelActive();
                    }
                });
            }

            safeSetSuccess(promise);
        }

NioDatagramChannel 的 doBind0()

private void doBind0(SocketAddress localAddress) throws Exception {
        if (PlatformDependent.javaVersion() >= 7) {
            SocketUtils.bind(javaChannel(), localAddress);
        } else {
            javaChannel().socket().bind(localAddress);
        }
    }

绑定完端口还没有激活,怎么办?当然是去激活呀!
看到 pipeline.fireChannelActive()

直接进入DefaultChannelPipeline.channeActive()

 @Override
        public void channelActive(ChannelHandlerContext ctx) {
            ctx.fireChannelActive();
            // 注册读事件,读包括 创建连接/ 读数据
            readIfIsAutoRead();
        }

点进ReadIfIsAutoRead() 看到 AbstractNioChannel的doBeginRead()

@Override
    protected void doBeginRead() throws Exception {
        // Channel.read() or ChannelHandlerContext.read() was called
        // 获取当前监听的 OPS 明显就是ServerSocketChannel
        // 注册 到 selector 上时的 OPS 啦 值是 0
        // selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
        final SelectionKey selectionKey = this.selectionKey;
        if (!selectionKey.isValid()) {
            return;
        }

        readPending = true;

        final int interestOps = selectionKey.interestOps();
        if ((interestOps & readInterestOp) == 0) {
        // readInterestOp 为 16 表示 selectionKey 的 OP_ACCEPT属性
        // 表示 selector 开始监听 客户端发来的  ACCEPT 请求了
            selectionKey.interestOps(interestOps | readInterestOp);
        }
    }

readInterestOp 是在 channel 工厂创建
NioServerSocketChannel 时 调用的
父类 AbstractNioChannel 的构造方法
readInterestOp 是赋值创建的
它的值是 SelectionKey.OP_READ

到此 服务启动,服务器可以开始处理来自客户端的请求了

总结启动服务时一些比较让人模糊的知识点:

Netty源码分析

Netty源码分析

如果你看完我的文章有不懂的地方,欢迎加我的微信一起沟通学习~
如果有什么好的建议给我,更是欢迎~图片

Netty源码分析

上一篇:【翻译】- ASP.NET Core 中的内存管理和模式


下一篇:Kubernetes核心技术之Controller