Table of Contents
1. EventLoop
1.1. 相关类
- 方框内是interface,方框外是class
- 浅蓝色是java.util.concurrent包中的executor
- 绿色是 io.netty.util.concurrent包中的EventExecutor
- 黄色是 io.netty.util.concurrent包中的EventLoop
Executor相关类主要负责(立即或者定时)执行Runnable/Callable;EventExecutor类增加了判断当前线程是否在EventLoop中的方法;EventLoop相关类提供接口将Channel register/unregister到一个EventLoop,另外返回一个返回ChannelHandlerInvoker用于在EventLoop触发register/active/write等行为或事件
| 类 | 提示 |
|---|---|
EventLoopGroup
|
EventLoop集合;register channel; 返回EventExecutor(next函数)
|
Executor
|
执行Runnable
|
ExecutorService
|
执行Callable; shutdown
|
ScheduledExecutorService
|
定时执行Runnable和Callable
|
EventExecutor
|
判断当前线程是否在本executor:inEventLoop
|
EventExecutorGroup
|
shudown; EventExector集合
|
EventLoop
|
返回ChannelHandlerInvoker,用于在EventLoop触发register,active, write等行为或事件
|
1.2. NioEventLoop相关实现
类NioEventLoop实现了EventLoop,但其具体的实现通过上层的类提供: AbstractScheduledEventExecutor和SingleThreadEventExecutor和SingleThreadEventLoop。
AbstractScheduledEventExecutor
- 实现schedule Runnable/Callable功能;
- 有一个scheduledTaskQueue,用PriorityQueue实现,头部是到期时间最早的task
SingleThreadEventExecutor
基于AbstractScheduledEventExecutor提供了addTask和pollTask的功能。
拥有两个queue:
- 本身有一个taskQueue,用来保存马上需要执行的任务
- 继承自AbstractScheduledEventExecutor的scheduledTaskQueue
函数takeTask用来获取一个需要马上执行的runnable,函数的实现如下:
- 查看scheduledTaskQueue头,如果没有任何scheduled task,则从taskQueue中take(无限等待)。
可能会感觉这里有bug,即在无限等待过程中,新加入scheduled tastk queue的task不会被执行。事实是在向其提交ScheduledTask时,会做以下操作:
因此是没有bug的
|
- 如果有scheduled task,则检查dueTime。
- 如果已经到期,则返回。
- 如果没有到期,从等待taskQueue,一直到dueTime。
- 如果dueTime到了taskQueue还没有东西,则返回scheduled task。
- 否则返回taskQueue里的东西。
boolean runAllTasks(long timeoutNanos) 会被子类用到,执行task直到timeout。
SingleThreadEventLoop
这个类没啥东西
NioEventLoop本身
依靠Java NIO(如Selector),提供了register channel的相关功能(中间需要调用Channel.register)。同时,override SingleThreadEventExecutor中的run函数,从而定义线程主循环。
主循环逻辑如下:
- select并等待唤醒(这里逻辑复杂,看不懂)
- 根据设置的io/task执行时间比例,按比例执select到的任务和task任务
select到的任务主要指socket的read/write,task任务主要指提交的Runnable和Callable
2. Channel
2.1. 相关类
2.2. NioServerSocketChannel
在使用ServerBootStrap时,需要提供一个Channel类,用来处理server socket的read操作(即accept)。使用NIO + TCP时,一般使用NioServerSocketChannel。
很奇怪的是,该类继承AbstractNioMessageChannel,这是因为AbstractNioMessageChannel实现了read函数(确切的说是实现了AbstractNioUnsafe子类),并会要求子类实现一个readMessage。而NioServerSocketChannel.readMessage则通过调用accept返回一个NioSocketChannel对象。
2.3. AbstractChannel
- 包含了register,write,bind等实现框架
- 需要子类去实现doRegister等函数,例如AbstractNioChannel实现了doRegister, NioSocketChannel实现了doWrite等
3. Pipeline
- DefaultChannelPipeLien包含了以AbstractChannelHandlerContext为元素的双线链表。该双线链表的Head和Tail都是内建不能更改的。当我们向pipeline增加ChannelHandler时(如调用addLast),实际上是创建一个AbstractChannelHandlerContext并添加到这个双向链表中。
- event类消息,从head开始向下遍历,比如fireChannelRegistered,fireChannelActive,fireChannelRead等
- action类消息,从tail开始遍历,比如write,read,connect,close等
- 内建的HeadContext会处理connect,write等调用,并调用AbstractChannel中相应的函数。具体的处理细节根据action和channel的类型都会不同。
- 内建的TailContext没什么特别处理,只对没人处理的ByteBuf做释放操作
4. AddressResolver
Netty中的AddressResolver负责将名字翻译成SocketAddress。为了提高速度(Or somthing else),Netty定义了AddressResolverGroup,每个EventExecutor关联一个Resolver
Netty有三种AddressResolverGroup实现:
- DefaultAddressResolverGroup: 通过Java自带的InetAddress.getByName来解析
- DnsAddressResolverGroup:Netty自己实现的一套DNS解析,有Cache功能
- NoopAddressResolverGroup: 啥都不干
在调用BootStrap.connect()时,会在当前线程调用AddressResolver.resolve(remoteAddress),而默认的实现DefaultAddressResolverGroup这个操作是 阻塞 的!
DnsAddressResolverGroup实现没看(貌似是4.1新出的功能),不过应该不会是阻塞的(但是也会在Channel的EventGroup上执行)。构造的时候需要:
- EventLoop
- name server list

0 评论:
Post a Comment