👉 這是一個或許對你有用的社群
《專案實戰(影片)》:從書中學,往事上“練” 《網際網路高頻面試題》:面朝簡歷學習,春暖花開 《架構 x 系統設計》:摧枯拉朽,掌控面試高頻場景題 《精進 Java 學習指南》:系統學習,網際網路主流技術棧 《必讀 Java 原始碼專欄》:知其然,知其所以然

👉這是一個或許對你有用的開源專案
國產 Star 破 10w+ 的開源專案,前端包括管理後臺 + 微信小程式,後端支援單體和微服務架構。
功能涵蓋 RBAC 許可權、SaaS 多租戶、資料許可權、商城、支付、工作流、大屏報表、微信公眾號、CRM 等等功能:
-
Boot 倉庫:https://gitee.com/zhijiantianya/ruoyi-vue-pro -
Cloud 倉庫:https://gitee.com/zhijiantianya/yudao-cloud -
影片教程:https://doc.iocoder.cn
一、什麼是責任鏈模式?
責任鏈模式(Chain of Responsibility Pattern),顧名思義,為請求者和接受者之間建立一條物件處理鏈路,避免請求傳送者與接收者耦合在一起!

責任鏈模式,是一種實用性非常強的設計模式,比較典型的應用場景有:
-
Apache Tomcat 對 Encoding 編碼處理的處理 -
SpringBoot ⾥⾯的攔截器、過濾器鏈 -
netty 中的處理鏈 -
支付風控的機制 -
⽇志處理級別
尤其是當程式的處理流程很長的時候,採用責任鏈設計模式,不僅實現優雅,而且易複用可擴充套件!
今天我們就一起來了解一下在 SpringBoot 中如何應用責任鏈模式!
基於 Spring Boot + MyBatis Plus + Vue & Element 實現的後臺管理系統 + 使用者小程式,支援 RBAC 動態許可權、多租戶、資料許可權、工作流、三方登入、支付、簡訊、商城等功能
專案地址:https://github.com/YunaiV/ruoyi-vue-pro 影片教程:https://doc.iocoder.cn/video/
二、程式碼實踐
在 SpringBoot 中,責任鏈模式的實踐方式有好幾種,今天我們主要抽三種實踐方式給大家介紹。
我們以某下單流程為例,將其切成多個獨立檢查邏輯,可能會經過的資料驗證處理流程如下:

採用責任鏈設計模式來程式設計,程式碼實踐如下!
2.1、方式一
首先,我們定義一個簡易版的下單物件
OrderContext
。publicclassOrderContext{/** * 請求唯一序列ID */private String seqId;/** * 使用者ID */private String userId;/** * 產品skuId */private Long skuId;/** * 下單數量 */private Integer amount;/** * 使用者收貨地址ID */private String userAddressId;//..set、get}
然後,我們定義一個數據處理介面
OrderHandleIntercept
,用於標準化執行!publicinterfaceOrderHandleIntercept{/** * 指定執行順序 * @return */intsort();/** * 對引數進行處理 * @param context * @return */OrderAddContext handle(OrderAddContext context);}
接著,我們分別建立三個不同的介面實現類,並指定執行順序,內容如下:
-
RepeatOrderHandleInterceptService
:用於重複下單的邏輯驗證 -
ValidOrderHandleInterceptService
:用於驗證請求引數是否合法 -
BankOrderHandleInterceptService
:用於檢查客戶賬戶餘額是否充足
@ComponentpublicclassRepeatOrderHandleInterceptServiceimplementsOrderHandleIntercept{@Overridepublicintsort(){//用於重複下單的邏輯驗證,在執行順序為1return1; }@Overridepublic OrderAddContext handle(OrderAddContext context){ System.out.println("透過seqId,檢查客戶是否重複下單");return context; }}@ComponentpublicclassValidOrderHandleInterceptServiceimplementsOrderHandleIntercept{@Overridepublicintsort(){//用於驗證請求引數是否合法,執行順序為2return2; }@Overridepublic OrderAddContext handle(OrderAddContext context){ System.out.println("檢查請求引數,是否合法,並且獲取客戶的銀行賬戶");return context; }}@ComponentpublicclassBankOrderHandleInterceptServiceimplementsOrderHandleIntercept{@Overridepublicintsort(){//用於檢查客戶賬戶餘額是否充足,在執行順序為3return3; }@Overridepublic OrderAddContext handle(OrderAddContext context){ System.out.println("檢查銀行賬戶是否合法,呼叫銀行系統檢查銀行賬戶餘額是否滿足下單金額");return context; }}
再然後,我們還需要建立一個訂單資料驗證管理器
OrderHandleChainService
,用於管理這些實現類。@ComponentpublicclassOrderHandleChainServiceimplementsApplicationContextAware{private List<OrderHandleIntercept> handleList = new ArrayList<>();@OverridepublicvoidsetApplicationContext(ApplicationContext applicationContext)throws BeansException {//獲取指定的介面實現類,並按照sort進行排序,放入List中 Map<String, OrderHandleIntercept> serviceMap = applicationContext.getBeansOfType(OrderHandleIntercept.class); handleList = serviceMap.values().stream() .sorted(Comparator.comparing(OrderHandleIntercept::sort)) .collect(Collectors.toList()); }/** * 執行處理 * @param context * @return */public OrderAddContext execute(OrderAddContext context){for (OrderHandleIntercept handleIntercept : handleList) { context =handleIntercept.handle(context); }return context; }}
最後,我們編寫單元測試來看看效果如何!
@RunWith(SpringRunner.class)@SpringBootTestpublicclassCalculatorServiceTest{@Autowiredprivate OrderHandleChainService orderHandleChainService;@Testpublicvoidtest(){ orderHandleChainService.execute(new OrderAddContext()); }}
執行結果如下:
透過seqId,檢查客戶是否重複下單檢查請求引數,是否合法,並且獲取客戶的銀行賬戶檢查銀行賬戶是否合法,呼叫銀行系統檢查銀行賬戶餘額是否滿足下單金額
如果需要繼續加驗證流程或者處理流程,只需要重新實現
OrderHandleIntercept
介面就行,其他的程式碼無需改動!當然,有的同學可能覺得這種方法用的不習慣,不喜歡透過
sort()
來指定順序,也可以透過如下方式進行手動add
排序。@ComponentpublicclassOrderHandleChainService{private List<OrderHandleIntercept> handleList = new ArrayList<>();@Autowiredprivate ValidOrderHandleInterceptService validOrderHandleInterceptService;@Autowiredprivate RepeatOrderHandleInterceptService repeatOrderHandleInterceptService;@Autowiredprivate BankOrderHandleInterceptService bankOrderHandleInterceptService;@PostConstructpublicvoidinit(){//依次手動add物件 handleList.add(repeatOrderHandleInterceptService); handleList.add(validOrderHandleInterceptService); handleList.add(bankOrderHandleInterceptService); }/** * 執行處理 * @param context * @return */public OrderAddContext execute(OrderAddContext context){for (OrderHandleIntercept handleIntercept : handleList) { context =handleIntercept.handle(context); }return context; }}
2.2、方式二
第二種實現方式,就更簡單了,我們透過註解
@Order
來指定排序,代替手動方法排序sort()
,操作方式如下:/** * 指定注入順序為1 * */@Order(1)@ComponentpublicclassRepeatOrderHandleInterceptServiceimplementsOrderHandleIntercept{//...省略}/** * 指定注入順序為2 * */@Order(2)@ComponentpublicclassValidOrderHandleInterceptServiceimplementsOrderHandleIntercept{//...省略}/** * 指定注入順序為3 * */@Order(3)@ComponentpublicclassBankOrderHandleInterceptServiceimplementsOrderHandleIntercept{//...省略}@ComponentpublicclassOrderHandleChainService{@Autowiredprivate List<OrderHandleIntercept> handleList;/** * 執行處理 * @param context * @return */public OrderAddContext execute(OrderAddContext context){for (OrderHandleIntercept handleIntercept : handleList) { context =handleIntercept.handle(context); }return context; }}
執行單元測試,你會發現結果與上面執行的結果一致,原因
Spring
的ioc
容器,支援透過Map
或者List
來直接注入物件,省去自己排序。2.3、方式三
透過定義抽象類來實現責任鏈設計模式,還是以上面的案例為例,我們需要先定義一個抽象類,比如
AbstractOrderHandle
。publicabstractclassAbstractOrderHandle{/** * 責任鏈,下一個連結節點 */private AbstractOrderHandle next;/** * 執行入口 * @param context * @return */public OrderAddContext execute(OrderAddContext context){ context = handle(context);// 判斷是否還有下個責任鏈節點,沒有的話,說明已經是最後一個節點if(getNext() != null){ getNext().execute(context); }return context; }/** * 對引數進行處理 * @param context * @return */publicabstract OrderAddContext handle(OrderAddContext context);public AbstractOrderHandle getNext(){return next; }publicvoidsetNext(AbstractOrderHandle next){this.next = next; }}
然後,分別建立三個處理類,並排好序號。
@Order(1)@ComponentpublicclassRepeatOrderHandleextendsAbstractOrderHandle{@Overridepublic OrderAddContext handle(OrderAddContext context){ System.out.println("透過seqId,檢查客戶是否重複下單");return context; }}@Order(2)@ComponentpublicclassValidOrderHandleextendsAbstractOrderHandle{@Overridepublic OrderAddContext handle(OrderAddContext context){ System.out.println("檢查請求引數,是否合法,並且獲取客戶的銀行賬戶");return context; }}@Order(3)@ComponentpublicclassBankOrderHandleextendsAbstractOrderHandle{@Overridepublic OrderAddContext handle(OrderAddContext context){ System.out.println("檢查銀行賬戶是否合法,呼叫銀行系統檢查銀行賬戶餘額是否滿足下單金額");return context; }}
接著,建立一個責任鏈管理器,比如
OrderHandleManager
。@ComponentpublicclassOrderHandleManager{@Autowiredprivate List<AbstractOrderHandle> orderHandleList;@PostConstructpublicvoidinit(){//如果List沒有按照@Order註解方式排序,可以透過如下方式手動排序 Collections.sort(orderHandleList, AnnotationAwareOrderComparator.INSTANCE);int size = orderHandleList.size();for (int i = 0; i < size; i++) {if(i == size -1){ orderHandleList.get(i).setNext(null); } else { orderHandleList.get(i).setNext(orderHandleList.get(i + 1)); } } }/** * 執行處理 * @param context * @return */public OrderAddContext execute(OrderAddContext context){ context = orderHandleList.get(0).execute(context);return context; }}
最後,我們編寫單元測試,來看看效果。
@RunWith(SpringRunner.class)@SpringBootTestpublicclassCalculatorServiceTest{@Autowiredprivate OrderHandleManager orderHandleManager;@Testpublicvoidtest(){ orderHandleManager.execute(new OrderAddContext()); }}
執行結果與預期一致!
透過seqId,檢查客戶是否重複下單檢查請求引數,是否合法,並且獲取客戶的銀行賬戶檢查銀行賬戶是否合法,呼叫銀行系統檢查銀行賬戶餘額是否滿足下單金額
基於 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現的後臺管理系統 + 使用者小程式,支援 RBAC 動態許可權、多租戶、資料許可權、工作流、三方登入、支付、簡訊、商城等功能
專案地址:https://github.com/YunaiV/yudao-cloud 影片教程:https://doc.iocoder.cn/video/
三、小結
本文主要圍繞在 SpringBoot 中如何引入責任鏈設計模式,介紹了三種玩法,其中第二種用法最多,其次就是第一種,第三種用的比較少,第三種本質是一種鏈式寫法,可能理解上不如第一種直觀,但是效果是一樣的。
有效的使用責任鏈設計模式,可以顯著降低業務程式碼的複雜度,可讀性更好,更容易擴充套件,希望對大家有幫助!
歡迎加入我的知識星球,全面提升技術能力。
👉 加入方式,“長按”或“掃描”下方二維碼噢:

星球的內容包括:專案實戰、面試招聘、原始碼解析、學習路線。





文章有幫助的話,在看,轉發吧。
謝謝支援喲 (*^__^*)