Netty服务端启动组件初始化-Channel,ChannelPipeline,NioEventLoopGroup原创
金蝶云社区-艾贺521
艾贺521
84人赞赏了该文章 784次浏览 未经作者许可,禁止转载编辑于2019年01月18日 18:56:54

我们都了解Netty的组件设计,主要由Channel,ChannelPipeLine,ChannelHandler,NioEventLoop组成,各个组件之间关系密切,这里我们探索下这几个组件的初始化工作


Channel

1. Channel的创建

ServerBootStrap.bind -> doBind(SocketAddress) -> initAndRegister() -> 

channel = channelFactory.newChannel();

在ServerBootStrap中的initAndRegister方法里,channel是通过ChannelFactory进行创建的。


2. ChannelFactory的设置,既然Channel通过ChannelFactory创建的,那么ChannelFactory是在哪里设置的呢?

点击ChannelFactory可以看到如下使用ChannelFactory的地方,在116行的地方有。

image.png


另外在我们的程序之中,只有channel方法设置了Channel:然后往下看

ServerBootStrap.channel(Class<? extends C> channelClass)

-> channelFactory(new ReflectiveChannelFactory<C>(channelClass))

-> channelFactory(ChannelFactory<? extends C> channelFactory)

-> this.channelFactory = channelFactory;


3. Channel的初始化操作,创建Channel之后我们可以看到在ServerBootStrap中对其调用init(channel)方法。

image.png

image.png

4. 在init方法处理Channel之前,我们看一下Channel的构造方法,因为我们传的是NioServerSocketChannel.class,看一下它的构造方法

image.png

这不是NIO编程常看到的:

DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider()

-> newSocket(SelectorProvider provider)

->provider.openServerSocketChannel()


image.png

image.png

image.png

最终在NioServerSocketChannel中:

- ch: provider.openServerSocketChannel()

- readInterestoP: SelectionKey.OP_ACCEPT

- id:DefaultChannelId.newInstance()

- unSafe: new NioMessageUnsafe()

- pipeLine: new DefaultChannelPipeline(this)

- config: new NioServerSocketChannelConfig(this, javaChannel().socket())

到这里是完成了channel的构造工作。


5. 看一下ServerBootStrap的config属性。

image.png


这里就看完了Channel的初始化工作


NioEventLoopGroup初始化

在使用Netty的时候,不管是客户端还是服务端应用,都要配置EventLoopGroup,而常用的是NioEventLoopGroup,那来看一下NioEventLoopGroup在应用中的初始化工作。


1. 首先新建一个NioEventLoopGroup实例。新建的时候可以指定具体的线程数,如果不传入线程的数量,线程的数量则从系统属性中获取io.netty.eventLoopThreads,如果获取不到那么启动的线程数量为系统的cpu核数的2倍。


```java

// 实例化

EventLoopGroup bossGroup = new NioEventLoopGroup();

...

// 默认线程数量

DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(

                "io.netty.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2));

                

// 具体启动几个线程

 super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);                

```


2. 父类实例化的细节,NioEventLoopGroup实例化的过程会不断的实例化其父类,逻辑大都位于MultithreadEventExecutorGroup父类中,它的实例化过程如下:

- 新建ThreadPerTaskExecutor线程执行器,默认的ThreadFactory为DefaultThreadFactory(getClass())

- children未新建n个EventExecutor,如果是Nio的则为

```java

protected EventLoop newChild(Executor executor, Object... args) throws Exception {

        return new NioEventLoop(this, executor, (SelectorProvider) args[0],

            ((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);

    }

```


- 将children作为参数,新建EventExecutorChooser。

```java

 public EventExecutorChooser newChooser(EventExecutor[] executors) {

        if (isPowerOfTwo(executors.length)) {

            return new PowerOfTowEventExecutorChooser(executors);

        } else {

            return new GenericEventExecutorChooser(executors);

        }

    }

```            

- 配置children也就是(EventExecutor)的terminationFuture监听器

- 设置只读children          

以上就完成了NioEventLoopGroup的创建工作。


Pipeline初始化

Netty的ChannelPipeline是ChannelHandler的容器,它负责ChannelHandler的管理和事件拦截与调度。

1. ChannelPipeline的创建工作,ChannelPipeline是在AbstractChannel的newChannelPipeline方法中创建,并且将当前对象传递进去。

而调用newChannelPipeline的时候是Channel进行创建的时候,所以Channel与Pipeline基本上是同时创建的。或者说Pipeline在Channel内部创建。


image.png


2. DefaultChannelPipeline的构造器。在构造DefaultChannelPipeline的时候,重点是创建了TailContext与HeadContext,并且Context的构造参数都是pipline。


image.png


image.png


image.png

- HeadContext多了unsafe,inbound为false,outbound为true

- TailContext的inbound为true,outbound为false

setComplete涉及到cas的用法,就是标记一下状态位。


3. ChannelPipeline的构造工作很少,但是它既然是ChannelHandler的容器,当对ChannelHandler进行管理的时候是什么样的呢。先看看ChannelHandler都会有handlerAdded和handlerRemoved方法。


image.png


最后

这篇文章,我们探讨了几个常见的Netty组件的初始化工作,希望能帮到大家


注:

本文独家发布自金蝶云社区


赞 84