1. 程式人生 > >怎樣實際專案中運用責任鏈模式

怎樣實際專案中運用責任鏈模式

1 模式概要

1.1 簡介

  • 責任鏈模式為請求建立一個接收者物件鏈,每個接收者都包含對另一個接收者的引用,如果一個物件不能處理該請求,那麼它會把請求傳給下一個接收者,依此類推
  • 責任鏈模式避免了請求的傳送者和接收者耦合在一起,讓多個物件都有可能接收請求,將這些物件連成一條鏈,並且沿著這條鏈傳遞請求,直到有物件處理它為止。

1.2 責任鏈模式優缺點

優點

降低耦合度。它將請求的傳送者和接收者解耦

簡化了物件,使得物件不需要知道鏈的結構 

增強給物件指派職責的靈活性,允許動態地新增或者刪除責任鏈 

增加新的請求處理類方便

缺點

不能保證請求一定被接收;

系統性能將受到一定影響,除錯時不方便,可能會造成迴圈呼叫

2 模式結構

2.1 物件定義

Handler(抽象處理者)  : 定義一個處理請求的介面,提供對後續處理者的引用 

ConcreteHandler(具體處理者)  : 抽象處理者的子類,處理使用者請求,可選將請求處理掉還是傳給下家;在具體處理者中可以訪問鏈中下一個物件,以便請求的轉發

2.2 類圖及設計

責任鏈

程式碼詳解:

抽象處理者

具體處理者 

在當前處理者物件無法處理時,將執行權傳給下一個處理者物件

Client  客戶端呼叫

ifelse 

2.3 適用場景:

  • 有多個物件可以處理同一個請求,具體哪個物件處理該請求由執行時刻自動確定
  • 在不明確指定接收者的情況下,向多個物件中的某一個物件提交一個請求
  • 可動態指定一組物件的處理請求

3 Spring中的過濾器

我們來分析Spring中Filter的 載入流程和執行流程

3.1 初始化流程

初始化過濾器載入資料流如下:

filter初始化載入時序圖

關鍵性程式碼

configure() 

不管是資料走哪裡,最終會通過 System.arraycopy  陣列擴容,增加過濾器資訊到  private FilterMap[] array 

 這個陣列中。 

最後呼叫StandardContext類中的  filterStart()  方法完成過濾器的初始化

3.2 執行過程

主要分兩步, 建立過濾器責任鏈 和 執行責任鏈

3.2.1 建立過程

建立filterChain方法主要在 ApplicationFilterFactory.createFilterChain(request, wrapper, servlet)  中,部分程式碼講解:

在StandardWrapperValue類的 invoke()  方法中呼叫ApplicationFilterChai類的  createFilterChain()  方法 

在ApplicationFilterChai類的  createFilterChain()  方法中呼叫ApplicationFilterChain類的  addFilter()  方法 

在ApplicationFilterChain類的  addFilter()  方法中給ApplicationFilterConfig陣列賦值

生成呼叫鏈

3.2.2 執行責任鏈

呼叫ApplicationFilterChain的 doFilter()  方法中最後會呼叫一個  internalDoFilter()  方法,目的就是執行ApplicationFilterChain中的全部過濾器,從程式碼中可以發現它呼叫了  doFilter  ,而在  doFilter  又會呼叫  internalDoFilter  從而使所有Filter都得以呼叫

這樣,一個完整的過濾器鏈就形成,然後進行呼叫

4 專案中的實際運用

業務場景

我們在專案中使用了阿里的MQ訊息中介軟體,來加快請求的響應時間和非同步解耦處理。RocktMQ主要可以按Topic來分割槽,然後按Tag分組,不同的業務區分不同的 tag 

比如: 在此我向大家推薦一個架構學習交流裙。交流學習裙號:687810532,裡面會分享一些資深架構師錄製的視訊錄影

簡訊類的訊息 messageTag  
手機推送訊息 pushTag  
延時任務訊息 delayTag  

等等。。。

常規寫法

ifelse 

具體設計方案如下:

設計UML類圖

類圖

抽象公共監聽器  ,主要用到了單例模式獲取常量

具體監聽器  ,監聽器主要用於MQ監聽消費Topic

consume() 

抽象處理者

具體處理者  :推送訊息Handler

具體處理者  :延時訂單處理Handler

模式工廠  HandlerFactory

getHandlerResponsibilityChain() 

客戶端呼叫

getHandlerResponsibilityChain()