天天看點

責任鍊模式以及責任鍊模式在netty中的使用

職責鍊模式

将對象連成一條鍊,使得請求可以在鍊中進行傳遞,直到有一個對象處理他為止。

責任鍊中的角色

抽象處理者角色(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,最終被添加到消息發送緩沖區中等待重新整理和發送,在此過程中也可以被中斷

在Netty中将事件根據源頭的不同分為InBound事件和OutBound事件。InBound事件通常由I/O線程觸發,例如TCP鍊路建立和關閉、讀事件等等,分别會觸發相應的事件方法。而OutBound事件則一般由使用者主動發起的網絡I/O操作,例如使用者發起的連接配接操作,綁定操作和消息發送操作等,也會分别觸發相應的事件方法。由于netty中提供了一個抽象類ChannelHandlerAdapter,它預設不處理攔截的事件。是以,在實際程式設計過程中,我們隻需要繼承ChannelHandlerAdapter,在我們的自定義Handler中覆寫業務關心的事件方法即可。