Netty4 NioEventLoopGroup 解析

我们从框架的应用层面来分析,NioEventLoopGroup在netty中的使用。

这是我们需要配置的地方。

紧接着我们进入netty的运行中。ServerBootstrap.bind(PORT);

这是一个bind操作。我们来看一下NioEventLoopGroup在这个操作中的使用。

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

config()返回在ServerBootstrap中内部属性:private final ServerBootstrapConfig config = new ServerBootstrapConfig(this);

注意这里传入的是this即ServerBootstrap对象。

这个类主要是用来暴露我们的配置的,直接把我们配置的ServerBootstrap传递进来。

我们继续ChannelFuture regFuture = config().group().register(channel);

这里的config()返回一个ServerBootstrapConfig,然后调用他的group()。

这个类是ServerBootstrapConfig的父类。调用了ServerBootstrap.group().方法。注意因为group方法是在弗雷AbstractBootstrap中定义的,所以这里进入父类的group()方法中来。

这个方法直接返回EventLoopGroup对象。

我们在回过头来看我们最初的配置,来发现这个group属性究竟是什么。

我们配置了两个NioEventLoopGroup,一个一个线程的传递给了父类AbstractBootstrap.一个初始化给当前的ServerBootstrap的内部属性childGroup.

我们在回到这里ChannelFuture regFuture = config().group().register(channel);

现在通过AbstractBootstrap.group()方法返回了一个NioEventLoopGroup对象,即我们配置的第一个单线程的NioEventLoopGroup对象。

现在进入他的register(channel)方法。由于这个方法是在他的父类中定义的,所以我们进入他的父类MultithreadEventLoopGroup()中。

next()方法返回一个EventLoop对象。

下面重点分析这个chooser。(在=======以内,然后接着分析next()方法)

====================================================================

这个chooser是我们在初始化NioEventLoopGroup的时候初始化的。

回到我们初始化NioEventLoopGroup的地方:

还是这里。

下面就到了初始化chooser的地方了:

/**
     * Create a new instance.
     *
     * @param nThreads          the number of threads that will be used by this instance.
     * @param executor          the Executor to use, or {@code null} if the default should be used.
     * @param chooserFactory    the {@link EventExecutorChooserFactory} to use.
     * @param args              arguments which will passed to each {@link #newChild(Executor, Object...)} call
     */
    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());
        }

        children = new EventExecutor[nThreads];

        for (int i = 0; i < nThreads; i ++) {
            boolean success = false;
            try {
                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;
                        }
                    }
                }
            }
        }

        chooser = chooserFactory.newChooser(children);

        final FutureListener<Object> terminationListener = new FutureListener<Object>() {
            @Override
            public void operationComplete(Future<Object> future) throws Exception {
                if (terminatedChildren.incrementAndGet() == children.length) {
                    terminationFuture.setSuccess(null);
                }
            }
        };

        for (EventExecutor e: children) {
            e.terminationFuture().addListener(terminationListener);
        }

        Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
        Collections.addAll(childrenSet, children);
        readonlyChildren = Collections.unmodifiableSet(childrenSet);
    }

这个构造方法内容比较多。别的先不管,我们来看:chooser = chooserFactory.newChooser(children);

这个EventExecutorChooserFactory chooserFactory是我们上个构造方法中传过来的:

this(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args);

是一个DefaultEventExecutorChooserFactory.INSTANCE。

然后我们看他的newChooser(EventExecutor[] executors)方法。

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

这里有个判断就是:判断是否为2的次方。

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

然后根据是否为2的次方分别进行两个构造方法。分别实现了EventExecutorChooser的next()方法。

    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)];
        }
    }

这两个实现类只是对于next的方法有不同的实现。但是都是遍历每一个executors。

为什么要这样呢?

原因是位操作&  比 % 操作要高效。netty为了提高效率也是拼了。

总的来说这个DefaultEventExecutorChooserFactory非常简单,就上面这些内容。现在我们也知道了chooser是什么了,就是一个时限了遍历所有EventExecutor的next()方法的对象。功能非常简单,只有一个方法next。遍历每一个EventExecutor。

=====================================================================

时间: 2024-10-12 03:51:20

Netty4 NioEventLoopGroup 解析的相关文章

【原创】NIO框架入门(一):服务端基于Netty4的UDP双向通信Demo演示

申明:本文由作者基于日常实践整理,希望对初次接触MINA.Netty的人有所启发.如需与作者交流,见文签名,互相学习. 学习交流 更多学习资料:点此进入 推荐 移动端即时通讯交流: 215891622 推荐 前言 NIO框架的流行,使得开发大并发.高性能的互联网服务端成为可能.这其中最流行的无非就是MINA和Netty了,MINA目前的主要版本是MINA2.而Netty的主要版本是Netty3和Netty4(Netty5已经被取消开发了:详见此文). 本文将演示的是一个基于Netty4的UDP服

基于Netty4的HttpServer和HttpClient的简单实现

Netty的主页:http://netty.io/index.html 使用的Netty的版本:netty-4.0.23.Final.tar.bz2 ‐ 15-Aug-2014 (Stable, Recommended) 实现一个简单的Http请求及响应过程: 1.Client向Server发送http请求. 2.Server端对http请求进行解析. 3.Server端向client发送http响应. 4.Client对http响应进行解析. Http Server: package com.

dubbo系列四、dubbo启动过程源码解析

一.代码准备 1.示例代码 参考dubbo系列二.dubbo+zookeeper+dubboadmin分布式服务框架搭建(windows平台) 2.简单了解下spring自定义标签 https://www.jianshu.com/p/16b72c10fca8 Spring自定义标签总共可以分为以下几个步骤 定义Bean 标签解析生成接收配置的POJO. 定义schema文件,定义自定义标签的attr属性 定义解析类parser,遇到自定义标签如何解析. 定义命名空间处理类namespaceSup

【Netty】最透彻的Netty原理架构解析

这可能是目前最透彻的Netty原理架构解析 本文基于 Netty 4.1 展开介绍相关理论模型,使用场景,基本组件.整体架构,知其然且知其所以然,希望给大家在实际开发实践.学习开源项目方面提供参考. Netty 是一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端. JDK 原生 NIO 程序的问题 JDK 原生也有一套网络应用程序 API,但是存在一系列问题,主要如下: NIO 的类库和 API 繁杂,使用麻烦.你需要熟练掌握 Selector.ServerSoc

新手入门:目前为止最透彻的的Netty高性能原理和框架架构解析(阿里)

1.引言 Netty 是一个广受欢迎的异步事件驱动的Java开源网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端. 本文基于 Netty 4.1 展开介绍相关理论模型,使用场景,基本组件.整体架构,知其然且知其所以然,希望给大家在实际开发实践.学习开源项目方面提供参考. 本文作者的另两篇<高性能网络编程(五):一文读懂高性能网络编程中的I/O模型>.<高性能网络编程(六):一文读懂高性能网络编程中的线程模型>也写的很好,有兴趣的读者可以一并看看. 关于作者: 陈彩华(

用Netty解析Redis网络协议

用Netty解析Redis网络协议 根据Redis官方文档的介绍,学习了一下Redis网络通信协议.然后偶然在GitHub上发现了个用Netty实现的Redis服务器,很有趣,于是就动手实现了一下! 1.RESP协议 Redis的客户端与服务端采用一种叫做 RESP(REdis Serialization Protocol)的网络通信协议交换数据.RESP的设计权衡了实现简单.解析快速.人类可读这三个因素.Redis客户端通过RESP序列化整数.字符串.数据等数据类型,发送字符串数组表示参数的命

netty4 bind启动过程简析

请看一下简单的 一个netty4服务端启动代码样例 EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)

Netty4.x用户指导

题记 最近对netty有了兴趣,现在官方推荐版本是netty4.*,但是纵观网络,大部分都是关于netty3.x的知识. 最好的学习,莫过于通过官方文档进行学习,系统,透彻,权威,缺点是英文.本文,算做自己学习netty的第一篇,总体思路与User guide for 4.x基本一致,本篇文章不是严格意义的翻译文章.开始了... 1.前言 1.1 问题 现 在,我们使用通用的应用程序和程序库,进行互相交流.例如,我们经常使用HTTP client库从web服务器上获取信息,通过web servi

Netty4.X 获取客户端IP

最近使用netty-4.0.23.Final 版本编写服务端代码,有个获取客户端代码的小需求,以前使用servlet开发时很机械的就: String ipAddr="0.0.0.0"; if (reqest.getHeader("X-Forwarded-For") == null) {     ipAddr = reqest.getRemoteAddr();  }else{          ipAddr = req.getHeader("X-Forwar