ChannelId的那些事儿
ChannelId组成
ChannelId
默认由io.netty.channel.DefaultChannelId
实现,最终结果存储在一个data
的byte数组中,data数组内由5个字段组成,从低位到高位分别是:6或8字节的MACHINE_ID
,4字节的PROCESS_ID
,4字节的SEQUENCE
,8字节的TIMESTAMP
和4字节的RANDOM
,下表以8字节的`MACHINE_ID举例:
字段 | RANDOM | TIMESTAMP | SEQUENCE | PROCESS_ID | MACHINE_ID |
---|---|---|---|---|---|
字节 | [27-24](4字节) | [23-16](8字节) | [15-12](4字节) | [11-8](4字节) | [7-0](6或8字节) |
说明 | 随机 | 自定义 | 初值为0,每次递增1 | 优先从系统属性io.netty.processId获取,类型为int | 优先从系统属性io.netty.machineId获取,类型为String,长度为17或23 |
在DefaultChannelId的实现中,**TIMESTAMP
**字段并没有直接使用系统的时间戳,例如:System.nanoTime()
,而是自定义了一个时间戳生成方法:Long.reverse(System.nanoTime()) ^ System.currentTimeMillis()
,举例如下:
1 | final long nanoTime = System.nanoTime(); |
至于Netty为什么这么设计,只是在源码中有一句简单的注释:// timestamp (kind of)
,翻译过来就是一种(Netty式的)时间戳,可能就是想这么实现吧。
ChannelId的表示
ChannelId
有两个函数:asShortText()
和asLongText()
,
asShortText()
使用懒加载的方式,输出**RANDOM
字段转换成16进制并存储到String shortValue
,例如:60fb0e5f**asLongText()
也采用懒加载的方式,将data数组中的5个字段转换成16进制以后,从**MACHINE_ID
开始,到RANDOM
结束,用“-”连起来,最后存储到String longValue
中,例如:00000000000000e0-00003738-00000000-3a5715eac38e517e-60fb0e5f**
bind那些事儿
在上述的1. initChannel(Channel)
中,执行了了一个重要的操作:new了一个匿名的ChannelInitializer
并且addLast到传入的Channel
的ChannelPipeline
中,该ChannelInitializer
主要执行了两件事:
- 当
ChannelInitializer.initChannel
回调被调用时,将ServerBootstrap
的ChannelHandler
addList到Channel.pipeline()
,而ServerBootstrap
的ChannelHanlder
可以在构造时通过handler(ChannelHandler)
传入,例如传入一个new LoggingHandler(LogLevel.INFO)
,从而实现log输出,有两点需要注意:ChannelInitializer.initChannel
回调时,发生在ServerBootstrap.group
中(也即大家常用的BossGroup),此时还没有注册到ServerBootstrap.childGroup
中(也即大家常用的WorkerGroup)。- 该ChannelHandler全局只有一个,会被所有的EventLoop共享包括
ServerBootstrap.group
和ServerBootstrap.childGroup
在内的所有EventLoop
- 当
ChannelInitializer.initChannel
回调被调用时,调用了Channel
的EventLoop
(该EventLoop
隶属于父线程池)并执行了一个异步任务:向Channel.pipeline()
中addLast了一个new ServerBootstrapAcceptor
,ServerBootstrapAcceptor
执行了两件重要的事情:- 将
ServerBootstrap.childHandler
addLast到Channel.pipeline()
- 调用
ServerBootstrap.childGroup.register(Channel)
将Channel
注册到子线程池(所以AbstractChannel
声明成员变量eventLoop
时使用了volatile
关键字修饰)
- 将