我们都了解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行的地方有。
另外在我们的程序之中,只有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)方法。
4. 在init方法处理Channel之前,我们看一下Channel的构造方法,因为我们传的是NioServerSocketChannel.class,看一下它的构造方法
这不是NIO编程常看到的:
DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider()
-> newSocket(SelectorProvider provider)
->provider.openServerSocketChannel()
最终在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属性。
这里就看完了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内部创建。
2. DefaultChannelPipeline的构造器。在构造DefaultChannelPipeline的时候,重点是创建了TailContext与HeadContext,并且Context的构造参数都是pipline。
- HeadContext多了unsafe,inbound为false,outbound为true
- TailContext的inbound为true,outbound为false
setComplete涉及到cas的用法,就是标记一下状态位。
3. ChannelPipeline的构造工作很少,但是它既然是ChannelHandler的容器,当对ChannelHandler进行管理的时候是什么样的呢。先看看ChannelHandler都会有handlerAdded和handlerRemoved方法。
最后
这篇文章,我们探讨了几个常见的Netty组件的初始化工作,希望能帮到大家
注:
本文独家发布自金蝶云社区
推荐阅读