014. Netty 职责链 Pipeline 详解

1. 设计模式 - 责任链模式


1. 概念讲解
  • 责任链模式(Chain of Responsibility Pattern)为请求创建了一个处理对象的链。

  • 发起请求和具体处理请求的过程解耦:职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无需关心请求的处理细节和请求的传递。

img

2. 实现责任链模式
  • 实现责任链模式 4 个要素:处理器抽象类、具体的处理器实现类、保存处理器信息、处理执行。

img

img

3. 责任链代码演示
// --- 链表形式调用 --- netty 就是类似的这种形式
public class PipelineDemo {
    /**
     * 初始化的时候造一个 head,作为责任链的开始,但是并没有具体处理
     */
    public HandlerChainContext head = new HandlerChainContext(new AbstractHandler() {
        @Override
        void doHandler(HandlerChainContext handlerChanContext, Object arg0) {
            handlerChanContext.runNext(arg0);
        }
    });

    public void addLast(AbstractHandler handler) {
        HandlerChainContext context = head;
        while (context.next != null) {
            context = context.next;
        }
        context.next = new HandlerChainContext(handler);
    }

    public void requestProcess(Object arg0) {
        this.head.handler(arg0);
    }

    public static void main(String[] args) {
        PipelineDemo piplineDemo = new PipelineDemo();
        piplineDemo.addLast(new Handler2());
        piplineDemo.addLast(new Handler1());
        piplineDemo.addLast(new Handler1());
        piplineDemo.addLast(new Handler2());
        piplineDemo.requestProcess("火车呜呜呜~~");
    }
}

/**
 * handler 上下文,主要维护链和链的执行
 */
class HandlerChainContext {
    HandlerChainContext next; // 下一个节点
    AbstractHandler handler;

    public HandlerChainContext(AbstractHandler handler) {
        this.handler = handler;
    }

    void handler(Object arg0) {
        this.handler.doHandler(this, arg0);
    }

    // 继续执行下一个
    void runNext(Object arg0) {
        if (this.next != null) {
            this.next.handler(arg0);
        }
    }
}

/**
 * 处理器抽象类
 */
abstract class AbstractHandler {
    /**
     * 处理器,这个处理器就做一件事情,在传入的字符串中增加一个尾巴。
     */
    abstract void doHandler(HandlerChainContext handlerChanContext, Object arg0); // handler 方法
}

// 处理器具体实现类
class Handler1 extends AbstractHandler {
    @Override
    void doHandler(HandlerChainContext handlerChainContext, Object arg0) {
        arg0 = arg0.toString() + ".. handler1 的小尾巴 .....";
        System.out.println("我是 Handler1 的实例,我在处理:" + arg0);
        // 继续执行下一个
        handlerChainContext.runNext(arg0);
    }
}

// 处理器具体实现类
class Handler2 extends AbstractHandler {
    @Override
    void doHandler(HandlerChainContext handlerChainContext, Object arg0) {
        arg0 = arg0.toString() + ".. handler2 的小尾巴 .....";
        System.out.println("我是 Handler2 的实例,我在处理:" + arg0);
        // 继续执行下一个
        handlerChainContext.runNext(arg0);
    }
}

2. Netty 中的 ChannelPipeline 责任链


img

  • Pipeline 管道保存了通道所有处理器信息。
  • 创建新 Channel 时自动创建一个专有的 pipeline。
  • 入站事件和出站操作会调用 pipeline 上的处理器。
1. 入站事件和出站事件
  • 入站事件:通常指 I/O 线程生成了入站数据。(通俗理解:从 socket 底层自己往上冒上来的事件都是入站)比如 EventLoop 收到 selector 的 OP_READ 事件,入站处理器调用 socketChannel.read(ByteBuffer) 接收到数据后,这将导致通道的 ChannelPipeline 中包含的下一个中的 channelRead 方法被调用。

  • 出站事件:通常是指 I/O 程序执行实际的输出操作。(通俗理解:想主动往 socket 底层操作的事件都是出站)比如 bind 方法用意是请求 server socket 绑定到给定的 SocketAddress ,这将导致通道的 ChannePipeline 中包含的下一个出站处理器中的 bind() 方法被调用。

2. Netty 中事件的定义

img

3. Pipeline 的 handler 是什么
  • ChannelHandler:用于处理 I/O 事件或者拦截 I/O 操作,并转发到 ChannelPipeline 中的下一个处理器。这个顶级接口定义功能很弱,实际使用时会去实现下面两大子接口:

    • 处理入站 I/O 事件的 ChannelInboundHandler
    • 处理出站 I/O 操作的 ChannelOutboundHandler
  • 适配器类:为了开发方便,避免所有的 handler 去实现一遍接口方法,Netty 提供了简单的实现类。

    • ChannelInboundHandlerAdapter 处理入站 I/O 事件
    • ChannelOutboundHandlerAdapter 处理出站 I/O 操作
    • ChannelDuplexHandler 来支持同时处理入站和出站事件
  • ChannelHandlerContext:实际存储在 Pipeline 中的对象并非 ChannelHandler,而是上下文对象。将 handler,包裹在上下文对象中,通过上下文对象与它所属的 ChannelPipeline 交互,向上或向下传递事件或者修改 pipeline 都是通过上下文对象。

4. 维护 Pipeline 中的 handler
  • ChannelPipeline 是线程安全的,ChannelHandler 可以在任何时候添加或删除。
  • 例如,你可以在即将交换敏感信息时插入加密处理程序,并在交换后删除它。
  • 一般操作,初始化的时候添加进去,较少删除。

img

5. handler 的执行分析

img

  • 当入站事件时,执行顺序是 1、2、3、4、5
  • 当出站事件时,执行顺序是 5、4、3、2、1
  • 在这一原则之上,ChannelPipeline 在执行时会进行选择
  • 3 和 4 为出站处理器,因此入站事件的实际执行是:1、2、5
  • 1 和 2 为入站处理器,因此出站事件的实际执行是:5、4、3
  • 不同的入站事件会出发 handler 不通的方法执行:上下文对象中 fire** 开头的方法,代表入站事件传播和处理,其余的方法代表出站事件的传播和处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值