Netty之ChannelPipeline(六)
Pipeline是什么
在之前的Netty编程中我们可以看到需要添加一个解码器或者是一个处理器或者是一个粘包拆包处理器,都需要在一个pipeline中添加进去,那么这个pipeline到底是个什么东西?
ChannelPipeline
点进pipeline()方法发现是一个ChannelPipeline对象
首先
ChannelPipeline本质上其实是一个Map<String, DefaultChannelHandlerContext>存储DefaultChannelHandlerContext(我们传进去的每一个handler都会被构造成一个DefaultChannelHandlerContext对象)的map集合。
然后
我们找到ChannelPipeline的默认实现类DefaultChannelPipeline,首先我们找到我们使用的addLast方法,下面是addLast的调用栈:
可以看到我们调用方法的时候只传了一个ChannelPipeline,所以invoker默认是null,接下来在第二个儿addLast方法中,会循环遍历handlers(也就是我们穿进来的ChannelPipeline数组),然后依次调用第三个addLast,其中generateName(h)是下图中的最后一个方法,就是根据类名自动生成一个name,默认name#0,如果重复就加1,然后我们就来到了addLast方法,由于 Channelpipeline支持运行期动态修改,因此存在两种潜在的多线程并发访问场景,IO线程和用户业务线程的并发访问、用户多个线程之间的并发访问,所以对HashMap进行操作这里是加了锁的,然后检查刚刚生成的name是否重复(检查就是看那个HashMap里面是否包含这个Channelpipeline如果包含就抛出IllegalArgumentException Duplicate handler name: 异常),接着,用我们传入的ChannelPipeline构造出DefaultChannelHandlerContext,然后就来到了addLast0方法中,这里可以看到是经典的链表插入操作,然后就看到了this.name2ctx.put(name, newCtx)将ChannelPipeline添加到我们的map中,最后this.callHandlerAdded(newCtx)发送新增 Channelhandlercontext通知消息。
接下来
我们分析一下DefaultChannelPipeline和DefaultChannelHandlerContext的结构,
DefaultChannelPipeline
- 看到一个WeakHashMap,这个是用来存储name缓存的,也就是每个被添加进来的ChannelPipeline在生成name的时候都要在这个里面判断是否已经有了,如果有了就将编号加一。
- head,指向name2ctx集合中的头,
- tail,执行name2ctx集合中的尾,
- name2ctx存放注册进来的pipeline构造成的DefaultChannelHandlerContext,
- childInvokers,存放的invoker的IdentityHashMap,IdentityHashMap是一种key可以重复的map
- invoker是什么:就是负责绑定、连接、读写等操作的一个东西。
DefaultChannelHandlerContext
找到构造方法:
可以看到构造的时候把传入的handler赋给当前对象的handler了,
注意看this.invoker = this.channel.unsafe().invoker(),invoker其实是调用Unsafe类的一个东西,类似于一个钩子吧,就是通过这个invoker来调用Unsafe类来进行事件操作的。
可以看到HeadHandler类:
包括绑定,连接,关闭,读写等操作,都是调用unsafe来操作的。
Unsafe是啥:CAS文中有提到Unsafe,用来调用本地代码。