netty学习笔记 源码一

243 阅读2分钟

Netty实现了Reactor模型,下面两图整体说明了一下netty的处理流程 image.png

image.png 先贴一下netty常用的编码模式:

public static void main(String[] args) {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new MyServerInitializer());

            ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

以 EventLoopGroup 为切入口跟一下源码。

image.png 类图如上,EventLoopGroup 主要定义了:

//Return the next EventLoop to use  
EventLoop next();  
//Register a Channel with this EventLoop. The returned ChannelFuture will get notified once the registration was complete.  
ChannelFuture register(Channel channel);   

NioEventLoopGroup类的初始化:
默认会调用到:

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

会默认起2*核心CPU数量的线程(nThreads)。 最终调用的初始化方法:

Create a new instance.
Params:
nThreads – the number of threads that will be used by this instance.
executor – the Executor to use, or null if the default should be used.
chooserFactory – the EventExecutorChooserFactory to use.
args – arguments which will passed to each 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);
    }

启动 nThreads 个EventExecutor,newChild方法在我们的代码中调用的就是 NioEventLoopGroup的newChild方法。

image.png ServerBootstrap 是启动的辅助类,主要是给ServerBootstrap类的成员变量赋值,调用bind的时候会用到。
serverBootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new MyServerInitializer());
指定的NioServerSocketChannel.class通过反射生成类的实例:

@Override
   public T newChannel() {
       try {
           return clazz.getConstructor().newInstance();
       } catch (Throwable t) {
           throw new ChannelException("Unable to create Channel from class " + clazz, t);
       }
   }

netty中的不少类都是直接封装的Java类库中的类,比如ByteBuf->ByteBUffer、Future->Future,netty中的Future添加了addListener方法,在future isDone的时候,对应的listener会立即收到通知。
Future的sync方法-->等待future完成。Waits for this future until it is done, and rethrows the cause of the failure if this future failed.