Java网络编程--Netty中的责任链

2019-09-30 07:06:30来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

Java网络编程--Netty中的责任链

Netty中的责任链

设计模式 - 责任链模式

责任链模式(Chain of Responsibility Pattern)是一种是行为型设计模式,它为请求创建了一个处理对象的链。其链中每一个节点都看作是一个对象,每个节点处理的请求均不同,且内部自动维护一个下一节点对象。当一个请求从链式的首端发出时,会沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求为止。

责任链模式主要解决了发起请求和具体处理请求的过程解耦,职责链上的处理者负责处理请求,用户只需将请求发送到职责链上即可,无需关心请求的处理细节和请求的传递。

img

责任链模式的实现

责任链模式的实现主要有四个要素:处理器抽象类,具体的处理器实现类,保存处理器信息,处理执行。

伪代码示例:

// *** 集合形式存储 类似tomcat中的filters ***
// 处理器抽象类
class AbstractHandler{void doHandler(Object arg0)}

// 处理器具体实现类
class Handler1 extends AbstractHandler{assert coutine;}
class Handler2 extends AbstractHandler{assert coutine;}
class Handler3 extends AbstractHandler{assert coutine;}

// 创建集合并存储所有处理器实例信息
List handlers = new List();
handlers.add(handler1, handler2, handler3);

// 处理请求,调用处理器
void process(request){
  for(handler in handlers){
    handler.doHandler(request);
  }
}

// 发起请求调用,通过责任链处理请求
call.process(request);

// *** 链表形式调用 netty中的用法 ***
// 处理器抽象类
class AbstractHandler{
  AbstractHandler next;//下一节点
  void doHandler(Object arg0)
}

// 处理器具体实现类
class Handler1 extends AbstractHandler{assert coutine;}
class Handler2 extends AbstractHandler{assert coutine;}
class Handler3 extends AbstractHandler{assert coutine;}

// 将处理器串成链表存储
pipeline = 头[handler1 -> handler2 -> handler3]尾;

// 处理请求,从头到尾调用处理器
void process(request){
  handler = pipeline.findOne; //查找第一个
  while(handler != null){
    handler.doHandler(request);
    handler = handler.next;
  }
}

链表形式的责任链实现的具体代码示例:

// 链表形式调用 netty中的用法
public class PipelineDemo {
  // 初始化的时候造一个head,作为责任链的开始,但是并没有具体的处理
  public HandlerChainContext head =
      new HandlerChainContext(
          new AbstractHandler() {
            @Override
            void doHandler(HandlerChainContext handlerChainContext, Object arg0) {
              handlerChainContext.runNext(arg0);
            }
          });

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

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

  public static void main(String[] args) {
    PipelineDemo pipelineChainDemo = new PipelineDemo();
    pipelineChainDemo.addLast(new Handler2());
    pipelineChainDemo.addLast(new Handler1());
    pipelineChainDemo.addLast(new Handler1());
    pipelineChainDemo.addLast(new Handler2());

    // 发起请求
    pipelineChainDemo.processRequest("火车呜呜呜~~");
  }
}

// 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 handlerChainContext, Object arg0);
}

// 处理器具体实现类
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);
  }
}

// 输出结果:
我是Handler2的实例,我在处理:火车呜呜呜~~..handler2的小尾巴.....
我是Handler1的实例,我在处理:火车呜呜呜~~..handler2的小尾巴.......handler1的小尾巴.....
我是Handler1的实例,我在处理:火车呜呜呜~~..handler2的小尾巴.......handler1的小尾巴.......handler1的小尾巴.....
我是Handler2的实例,我在处理:火车呜呜呜~~..handler2的小尾巴.......handler1的小尾巴.......handler1的小尾巴.......handler2的小尾巴.....

Netty中的ChannelPipeline责任链

pipeline管道保存了通道所有处理器信息,创建channel时自动创建一个专有的pipeline,入站事件和出站事件会调用pipeline上的处理器

img

入站事件和出站事件

入站事件:通常指IO线程生成了入站数据
(通俗理解:从socket底层自己往上冒上来的事件都是入站)
比如EventLoop收到selector的OP_READ事件,入站处理器调用socketChannel.read(ByteBuffer)接受到数据后,这将导致通道的ChannelPipeline中包含的下一个中的channelRead方法被调用

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

img

Pipeline中的handler

ChannelHandler:用于处理IO事件或拦截IO操作,并转发到ChannelPipeline中的下一个处理器。这个顶级接口定义功能很弱,事件使用时会实现下面两大子接口:处理入站IO事件的ChannelInBoundHandler,处理出站IO事件的ChannelOutBoundHandler

适配器:为了开发的方便,避免所有的handler去实现一遍接口方法,Netty提供了简单的实现类:
ChannelInBoundHandlerAdapter处理入站IO事件,
ChannelOutBoundHandlerAdapter处理出站IO事件,
ChannelDuplexHandler支持同时处理入站和出站事件

ChannelHandlerContext:实际存储在Pipeline中的对象并非ChannelHandler,而是上下文对象,将handler包裹在上下文对象中,通过上下文属的ChannelPipeline交互,向上或向下传递事件或者修改pipeline都是通过上下文对象。

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

Pipeline中管理handler的API:

img

handler的执行分析

img

分析register入站事件的处理

img

分析bind出站事件的处理

img

分析accept入站事件的处理

img

分析read入站事件的处理

img

小结

用户在管道中有一个或多个channelhandler来接受IO事件和请求IO操作

一个典型的服务器会在每个通道的管道中都有以下处理程序,但是根据协议和业务逻辑的复杂性和特征,可能会有所不同:
协议解码器 - 将二进制数据转换为Java对象
协议编码器 - 将Java对象转换成二进制数据
业务逻辑处理器 - 执行实际的业务逻辑

责任链模式的运用,保证了Netty的高度可扩展性

?

原文链接:https://www.cnblogs.com/coding-diary/p/11594426.html
如有疑问请与原作者联系

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:java知识精要(一)

下一篇:看完你就知道的乐观锁和悲观锁