Netty入門簡介

    Netty是基於NIO的一個異步網絡框架,它將NIO的selector、channel、buffer封裝在底層,提供了一層易於使用的api。

   模型結構

如上圖所示,netty的入口是AbstractBootstrap:

  • 服務端使用的是ServerBootstrap,接收2個NioEventLoopGroup實例,按照職責劃分成boss和work,boss負責處理accept請求,work負責處理read、write請求
  • 客戶端使用的是Bootstrap,接收一個NioEventLoopGroup實例,負責處理read、write請求

NioEventLoopGroup裏面管理着多個eventLoop,創建NioEventLoopGroup實例時,默認會創建處理器數量的兩倍的eventLoop實例,每個eventLoop會維護一個selector和taskQueue,selector即是NIO裏面的多路複用器,taskQueue是存放請求任務的隊列。

代碼如下:

/*MultithreadEventLoopGroup爲EventLoopGroup的父類,創建實例時會調用以下方法,其中DEFAULT_EVENT_LOOP_THREADS爲處理器數量的兩倍*/
    protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
        super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
    }

    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];
        //這裏遍歷了nThreads次,調用了nThreads次newChild方法,創建了nThreads個NioEventLoop實例
        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);
    }
//創建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]);
    }

到這裏,就已經創建了NIO裏的多路複用器selector,接下來就是把channel註冊到selector裏去,netty的處理有點複雜,我也沒有完全摸透,這裏簡單講下我的理解(建議去看看狼哥的博客,講得很詳細,以下圖片也來源於他的博客)

上圖是Bootstrap創建的流程,我們重點看下initAndRegister方法

 final ChannelFuture initAndRegister() {
        Channel channel = null;
        try {
            //這裏的channel是netty對NIO的channel自己封裝的對象
            channel = channelFactory.newChannel();
            init(channel);
        } catch (Throwable t) {
            if (channel != null) {               
                channel.unsafe().closeForcibly();               
                return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
            }
            
            return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
        }
        //這裏的group就是上面講到的EventLoopGroup
        ChannelFuture regFuture = config().group().register(channel);
        if (regFuture.cause() != null) {
            if (channel.isRegistered()) {
                channel.close();
            } else {
                channel.unsafe().closeForcibly();
            }
        }

        return regFuture;
    }


    //因爲EventLoopGroup中維護了多個eventLoop,next方法會調用chooser策略找到下一個eventLoop,並執行eventLoop的register方法註冊到eventLoop裏的selector
    public ChannelFuture register(Channel channel) {
        return next().register(channel);
    }
    public EventLoop next() {
        return (EventLoop) super.next();
    }
    public EventExecutor next() {
        return chooser.next();
    }

在initAndRegister方法裏,netty先創建了一個自已對NIO的ServerSocketChannel封裝的channel對象,然後通過chooser策略找到EventLoopGroup裏的某個EventLoop,將channel註冊到EventLoop的selector中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章