一、责任链模式
适用场景:
- 对于一个请求来说,如果每个对象都有机会处理它,而且不明确到底是哪个对象会处理请求时,我们可以考虑使用责任链模式实现它,让请求从链的头部往后移动,直到链上的一个节点成功处理了它为止
优点:
- 发送者不需要知道自己发送的这个请求到底会被哪个对象处理掉,实现了发送者和接受者的解耦
- 简化了发送者对象的设计
- 可以动态的添加节点和删除节点
缺点:
- 所有的请求都从链的头部开始遍历,对性能有损耗
- 极差的情况,不保证请求一定会被处理
二、Netty中的Channel-Pipeline责任链
Netty 的 Pipeline 管道的设计,就采用了责任链设计模式。
- ChannelPipeline 管道 保存了Channel通道所有处理器信息
- 创建新 Channel 时自动创建一个专有的 ChannelPipeline
- ChannelPipeline里面是一个由多个ChannelHandlerContext串联起来的双向链表
- 每个ChannelHandlerContext有一个后继指针next和前驱指针prev
- ChannelHandler则是被包装在ChannelHandlerContext中
1.ChannelHandler
有两个重要的子接口:
ChannelInboundHandler
:用于拦截入站事件(如数据被接收、新的连接建立等)。ChannelOutboundHandler
:用于拦截出站事件(如数据被发送、连接关闭请求等)。
ChannelDuplexHandler 既继承了 ChannelInboundHandlerAdapter,又实现ChannelOutboundHandler 的接口,所以既能入站,也可以出站。
2.ChannelHandlerContext
是 ChannelHandler
的上下文信息。ChannelHandlerContext
负责保存处理器的状态,并且提供了方法来访问 Channel
、ChannelPipeline
以及其他 ChannelHandler
。
3.责任传播和终止机制
ChannelHandlerContext 提供了一系列 fireXXX 方法,用于将事件传播给链中的下一个处理器。例如:fireChannelRead(Object msg):当新的数据被读取时,调用这个方法将事件传递给下一个入站处理器。
如果开发者在自定义的 ChannelHandler 中重写了某个事件处理方法,并且没有调用对应的 fireXXX 方法,那么事件的传播就会在该处理器处终止。
- 在pipeline中的任意一个节点,只要我们不手动的往下传播下去,这个事件就会终止传播在当前节点
- 对于入站数据,默认会传递到尾节点,进行回收,如果我们不进行下一步传播,事件就会终止在当前节点
4.Netty中事件的定义
5.Pipeline中的handler增添方法
ChannelPipeline是线程安全的,ChannelHandler可以在任何时候添加或删除。
6.Handler的执行分析
当入站事件时,执行顺序是 1 、 2 、 3 、 4 、 5
当出站事件时,执行顺序是 5 、 4 、 3 、 2 、 1
在这一原则之上, ChannelPipeline 在执行时会进行选择
3 和 4 为出站处理器,因此入站事件的实际执行是 :1 、 2 、 5
1 和 2 为入站处理器,因此出站事件的实际执行是 :5 、 4 、 3
不同的入站事件会触发 handler 不同的方法执行:
上下文对象中 fire** 开头的方法,代表入站事件传播和处理
其余的方法代表出站事件的传播和处理。
三、ChannelPipeline 的创建过程
整个过程如下:
- 任何一个SocketChannel创建的同时都会创建一个绑定的ChannelPipeline。同时创建 tail 节点和 head 节点,形成最初的双向链表。
- 在调用 ChannelPipeline 的 addLast等方法的时候,会根据给定的 handler 创建一个 Context, 然后,将这个 Context 插入到链表的尾端(tail 前面)
- Context 包装 handler,多个 Context 在 pipeline 中形成双向链表
ServerBootstrap serverBootstrap = new ServerBootstrap(); //新建服务器端启动类
serverBootstrap.group(bossGroup, workGroup); //设置EventLoopGroup线程组
serverBootstrap.channel(NioServerSocketChannel.class) //设置通道类型:同步非阻塞.handler(new LoggingHandler(LogLevel.DEBUG)).childHandler(new ChannelInitializer<Channel>() { //初始化通道@Overrideprotected void initChannel(Channel channel) throws Exception {//1.创建ChannelPipeline 和 tail 节点、head 节点ChannelPipeline pipeline = channel.pipeline();//2.创建ChannelPipelineContext//3.用ChannelPipelineContext来包装Handlerpipeline.addLast(new HttpServerCodec()); //添加的Handlerpipeline.addLast(new HttpObjectAggregator(64 * 1024));pipeline.addLast(new IdleStateHandler(60, 0, 0, TimeUnit.SECONDS));pipeline.addLast(new HandlerHeartBeat());} });
源码推导见下:
Netty17——Pipeline、Handler和HandlerContext的创建_pipeline handlercontext-CSDN博客
四、参考
【图解IO与Netty系列】Netty源码解析——ChannelPipeline中的责任链模式_netty责任链源码分析-CSDN博客
深入netty19-netty中的设计模式-工厂、责任链、观察者详解_netty 责任链-CSDN博客
Netty框架之责任链模式及其应用_netty责任链-CSDN博客