Netty 必知必会(四)—— Channel-Pipeline 责任链

一、责任链模式

适用场景:

  • 对于一个请求来说,如果每个对象都有机会处理它,而且不明确到底是哪个对象会处理请求时,我们可以考虑使用责任链模式实现它,让请求从链的头部往后移动,直到链上的一个节点成功处理了它为止

优点:

  • 发送者不需要知道自己发送的这个请求到底会被哪个对象处理掉,实现了发送者和接受者的解耦
  • 简化了发送者对象的设计
  • 可以动态的添加节点和删除节点

缺点:

  • 所有的请求都从链的头部开始遍历,对性能有损耗
  • 极差的情况,不保证请求一定会被处理

二、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 负责保存处理器的状态,并且提供了方法来访问 ChannelChannelPipeline 以及其他 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>() {  //初始化通道
                        @Override
                        protected void initChannel(Channel channel) throws Exception {
                            
                            //1.创建ChannelPipeline 和 tail 节点、head 节点
                            ChannelPipeline pipeline = channel.pipeline();
                            
                            //2.创建ChannelPipelineContext
                            //3.用ChannelPipelineContext来包装Handler
                            pipeline.addLast(new HttpServerCodec());   //添加的Handler
                            pipeline.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博客

  • 8
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值