职责链模式

将对象连成一条链,使得请求可以在链中进行传递,直到有一个对象处理他为止。

 

责任链中的角色

抽象处理者角色(Handler):定义出一个处理请求的接口。如果需要,接口可以定义出一个方法以设定和返回对下家的引用。这个角色通常由一个Java抽象类或者Java接口实现。

具体处理者角色(ConcreteHandler):具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问下家。

抽象处理者角色

public abstract class Handler {  
     
   /** 
    * 持有后继的责任对象 
    */  
   protected Handler successor;  
   /** 
    * 示意处理请求的方法,虽然这个示意方法是没有传入参数的 
    * 但实际是可以传入参数的,根据具体需要来选择是否传递参数 
    */  
   public abstract void handleRequest(); 
   /** 
    * 取值方法 
    */  
   public Handler getSuccessor() {  
       return successor;  
   }  
   /** 
    * 赋值方法,设置后继的责任对象 
    */  
   public void setSuccessor(Handler successor) {  
       this.successor = successor;  
   }  
     
}

具体处理者角色

public class ConcreteHandler extendsHandler {  
   /** 
    * 处理方法,调用此方法处理请求 
    */  
   @Override  
   public void handleRequest() {  
       /** 
        * 判断是否有后继的责任对象 
        * 如果有,就转发请求给后继的责任对象 
        * 如果没有,则处理请求 
        */  
       if(getSuccessor() != null)  
       {              
           System.out.println("放过请求");  
           getSuccessor().handleRequest();              
       }else  
       {              
           System.out.println("处理请求");  
       }  
   }  
  
}

客户端类

public class Client {  
  
   public static void main(String[] args) { 
       //组装责任链  
       Handler handler1 = new ConcreteHandler();  
       Handler handler2 = new ConcreteHandler();  
       handler1.setSuccessor(handler2);  
       //提交请求  
       handler1.handleRequest();  
   }  
  
}

例子中的责任链处理逻辑很简单:当有下一个处理者的时候,则直接传递给下一个处理者,当没有的时候,则自己处理。

以上就是一般的责任链模式的处理逻辑。和我们在web开发中经常使用到的filter非常相似。下面看看在netty中是如何使用责任链模式的。

 

Netty中的责任链模式使用

在netty中,将Channel的数据管道抽象为ChannelPipeline,消息在ChannelPipeline中流动和传递。ChannelPipeline是ChannelHandler的容器,持有I/O事件拦截器ChannelHandler的链表,负责对ChannelHandler的管理和调度。由ChannelHandler对I/O事件进行拦截和处理,并可以通过接口方便地新增和删除ChannelHandler来实现不同业务逻辑的处理。

 

ChannelPipeline的责任链事件处理过程

图中展示了一个消息被ChannelPipeline链拦截和处理的过程。

(1)      底层的SocketChannel read方法读取ByteBuf,触发ChannelRead事件,由I/O线程NioEventLoop调用ChannelPipeline的fireChannelRead方法,将消息传输到ChannelPipeline中。

(2)      消息依次被HeadHandler、ChannelHandler1、ChannelHandler2……TailHandler拦截和处理,在这个过程中,任何ChannelHandler都可以中断当前的流程,结束消息的传递。

(3)      当调用ChannelHandlerContext的write方法发送消息,消息从TailHandler开始,经ChannelHandlerN……ChannelHandler1、HeadHandler,最终被添加到消息发送缓冲区中等待刷新和发送,在此过程中也可以被中断