目錄
1、責任鏈模式概念
1.1、定義介紹
1.2、流程圖
1.3、優缺點
2、實現
3、應用場景
3.1、Springmvc流程
3.2、mybatis的執行流程
3.3、Spring的過濾器和攔截器
3.4、sentinel限流熔斷
3.5、aop的加載和使用
4、舉例
前言
???????是一種?行為型設計模式,它通過將請求沿著一條處理鏈傳遞,直到某個對象處理它為止。這種模式的核心思想是?解耦請求的發送者和接收者,使多個對象都有機會處理請求,避免請求發送者與具體處理者之間的緊耦合。
????????核心思想是將請求的處理職責沿著對象鏈傳遞,而不明確指定具體哪個對象處理。
如下圖所示:
這種模式特別適用于需要多級處理的場景,例如工作流管理系統、審批流程、過濾器鏈等。
如下圖所示:
1、責任鏈模式概念
????????主要目的是解耦請求的發送者和接收者,使得多個對象都有機會處理請求。
1.1、定義介紹
????????職責鏈模式是一種行為型設計模式,它允許將請求沿著一個處理鏈傳遞,直到鏈中的某個對象處理它。
????????將鏈中的每一個結點看做是一個對象,每個結點處理請求均不同,且內部自動維護一個下一個結點對象。當請求從鏈條的首端出發時,會沿著鏈的路徑依次傳遞給每一個結點的對象,直到有對象處理這個請求為止。
????????每個結點會處理一件事情,如果結點間出現異常,那么鏈路就會中斷。
1.2、流程圖
如下圖所示:
1.3、優缺點
1、優點:
降低耦合度:請求發送者與處理者解耦,發送者不需要知道具體哪個處理者會處理請求。
動態組合:可以靈活地修改責任鏈的結構,增加或減少處理器。
職責分離:將請求處理的各個步驟分散到不同的處理者中,符合單一職責原則。
2、缺點:
可能無處理結果:如果鏈上的所有處理者都不能處理該請求,那么該請求將被丟棄。
性能問題:責任鏈過長可能會影響系統性能,因為請求會依次傳遞給鏈上的每一個處理者。
2、實現
????????在Java中,職責鏈模式通常通過定義一個抽象處理器類來實現,該類包含處理請求的方法以及持有下一個處理器的引用。
如下圖所示:
代碼示例:
abstract class Handler {protected Handler nextHandler;public void setNextHandler(Handler nextHandler) {this.nextHandler = nextHandler;}public abstract void handleRequest(Request request);
}
????????具體的處理器類繼承自這個抽象類,并根據自己的能力決定是否處理請求或將其傳遞給下一個處理器。
代碼示例:
class ConcreteHandler1 extends Handler {@Overridepublic void handleRequest(Request request) {if (request.getLevel() == 1) {System.out.println("ConcreteHandler1 handled the request.");} else if (nextHandler != null) {nextHandler.handleRequest(request);}}
}class ConcreteHandler2 extends Handler {@Overridepublic void handleRequest(Request request) {if (request.getLevel() == 2) {System.out.println("ConcreteHandler2 handled the request.");} else if (nextHandler != null) {nextHandler.handleRequest(request);}}
}
測試:
class Request {private int level;public Request(int level) {this.level = level;}public int getLevel() {return level;}
}public class ChainOfResponsibilityPatternExample {public static void main(String[] args) {Handler handler1 = new ConcreteHandler1();Handler handler2 = new ConcreteHandler2();handler1.setNextHandler(handler2);Request request1 = new Request(1);Request request2 = new Request(2);handler1.handleRequest(request1);handler1.handleRequest(request2);}
}?
3、應用場景
????????責任鏈模式適用于需要將請求的處理邏輯分散到多個對象中的場景。
????????例如,在Java的Servlet中,當一個HTTP請求到達服務器時,可能需要經過多個Filter的處理,這種場景就可以使用職責鏈模式來實現。
????????此外,職責鏈模式還可以用于實現工作流管理系統、審批流程等需要多級處理的場景。
????????在Spring MVC中,HandlerInterceptor
接口允許開發者在請求處理的不同階段插入自定義邏輯。
3.1、Springmvc流程
????????這個springMvc的執行流程來說,全部流程就組成了一個鏈條。每一個步驟就是一個結點,每個結點都會有對應的處理方法,每個結點處理完成之后,就會進入下一個結點。
????????一旦某個結點出現異常,那么當前的鏈路就會停止,當前請求中斷。
3.2、mybatis的執行流程
????????mybatis的執行流程也是通過這個責任鏈模式,首先會創建這個SqlSessionFactory,然后通過這個工廠創建一個SqlSession,這個SqlSession只是一個門面模式,會通過Executer執行增刪改查的操作,然后一個Handler用于設置參數,一個Handler用于返回結果集,最后通過這個StatementHandler將執行結果獲取。
????????里面的整個步驟就相當于形成了一個鏈條,執行完當前結點就會進入下一個結點,如果出現異常,鏈條終止往下執行。
3.3、Spring的過濾器和攔截器
Spring里面的這個過濾器鏈路的調用,以及攔截器的鏈路調用,也是采用這種責任鏈模式。
3.4、sentinel限流熔斷
????????sentinel里面的每一個規則對應一個槽點,如流控規則,授權規則,熔斷規則,熱點規則,系統規則等。
????????里面也是利用這個責任鏈模式,每個插槽對應一個規則,每個規則處理一個事件。如果出現異常,那么就會進行對應的限流降級。
3.5、aop的加載和使用
????????aop依賴與ioc,在生產bean并進行實例化之前,先通過bean的第一個后置處理器找到所有在類上面加@AspectJ這個注解的所有類,并在這個類的里面找到所有的befeore,after等注解的方法,每一個before,after等都會生成一個對應的advisor,每個advisor包括advise和pointcut,advise主要是用來作為一個增強器的使用,pointcut是為了進行匹配,匹配成功才進行最終的動態代理的生成。
????????最后獲取到所有的advisors,由于可能有大量的advisor,因此在bean的最后一個后置處理器才對這些所有的advisor進行處理,即在bean進行初始化之后才進行處理。
????????最后會去循環遍歷這些advisors,通過advisors里面封裝的pointcut和生成的advisor進行比較,如果匹配成功,則說明bean需要創建動態代理。主要是通過責任鏈的方式實現。
4、舉例
????????假設有一個學校有一個采購審批的需要,采購項目需要給領導審批,不同金錢范圍,對應的審批領導的等級不同,如下:
1、金額小于5000,由教學主任審批
2、金額小于等于5000,由院長審批
3、金額小于等于30000,由副校長任審批
4、金額大于30000,由校長審批
流程圖如下:
1、首先定義一個實體類ApproverRequest
/***/
public class ApproverRequest {private int type = 0; //請求類型private float price = 0.0f; //請求金額private int id = 0;//構造器public ApproverRequest(int type, float price, int id) {this.type = type;this.price = price;this.id = id;}public int getType() { return type; }public float getPrice() { return price; }public int getId() { return id; }
}
2、定義一個抽象類,用于定義全局,作為子類的規范。
鏈條中所有的結點都需要繼承子類,實現子類里面的抽象方法。
/*** 定義全局*/
public abstract class Approver {//下一個調用者Approver next ;//需要傳入的名字String name ;public Approver(String name){this.name = name;}//設置下一個調用者public void setNext(Approver next) {this.next = next;}public abstract void processApprover(ApproveRequest approveRequest);
}
3、然后開始寫一個鏈條中的第一個結點,由教學主任負責審批。
如果金額太大,教學主任審批不了,那么就由這個院長審批。
/***/
public class DepartmentApprover extends Approver {public DepartmentApprover(String name){super(name);}@Overridepublic void processApprover(ApproverRequest approveRequest) {if(approveRequest.getPrice() <= 5000) {System.out.println(" 請求編號 id= " + approveRequest.getId() + " 被 " + this.name + " 處理");}else {next.processApprover(approveRequest);}}}
4、然后開始寫一個鏈條中的第二個結點,由院長負責審批。
如果金額太大,院長審批不了,那么就由這個副校長審批
/***/
public class CollegeApprover extends Approver{public CollegeApprover(String name) {super(name); }@Overridepublic void processApprover(ApproverRequest approveRequest) {if(approveRequest.getPrice() > 5000 && approveRequest.getPrice() <= 10000) {System.out.println(" 請求編號 id= " + approveRequest.getId() + " 被 " + this.name + " 處理");}else {next.processApprover(approveRequest);}}
}
5、然后開始寫一個鏈條中的第三個結點,由副長負責審批。
如果金額太大副校長審批不了,那么就由這個校長審批
/***/
public class ViceSchoolMasterApprover extends Approver{public ViceSchoolMasterApprover(String name) {super(name); }@Overridepublic void processApprover(ApproverRequest approveRequest) {if(approveRequest.getPrice() > 10000 && approveRequest.getPrice() <= 30000) {System.out.println(" 請求編號 id= " + approveRequest.getId() + " 被 " + this.name + " 處理");}else {next.processApprover(approveRequest);}}
}
6、然后開始寫最后一個結點,由校長審批。
/***/
public class SchoolMasterApprover extends Approver{public SchoolMasterApprover(String name) {super(name); }@Overridepublic void processApprover(ApproverRequest approveRequest) {if(approveRequest.getPrice() > 30000) {System.out.println(" 請求編號 id= " + approveRequest.getId() + " 被 " + this.name + " 處理");}else {next.processApprover(approveRequest);}}
}
7、編寫一個測試類
/***/
public class Main {public static void main(String[] args) {//創建一個請求ApproverRequest approveRequest = new ApproverRequest(1, 29000, 1);//創建相關的審批人DepartmentApprover departmentApprover = new DepartmentApprover("張主任");CollegeApprover collegeApprover = new CollegeApprover("李院長");ViceSchoolMasterApprover viceSchoolMasterApprover = new ViceSchoolMasterApprover("王副校");SchoolMasterApprover schoolMasterApprover = new SchoolMasterApprover("佟校長");//需要將各個審批級別的下一個設置好departmentApprover.setNext(collegeApprover);collegeApprover.setNext(viceSchoolMasterApprover);viceSchoolMasterApprover.setNext(schoolMasterApprover);//單向責任鏈這里可以不加schoolMasterApprover.setNext(departmentApprover);departmentApprover.processApprover(approveRequest);viceSchoolMasterApprover.processApprover(approveRequest);}
}
總結
????????責任鏈模式通過將請求傳遞給鏈上的下一個處理者,解耦了請求發送者和接收者,并且可以根據需要動態組合責任鏈的結構,使得請求處理更加靈活和可擴展。
參考文章:
1、Java設計模式之責任鏈模式_java責任鏈-CSDN博客https://blog.csdn.net/qq_27656927/article/details/141589649?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522ca442c1bb491a8a574936eb9ae4c884d%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=ca442c1bb491a8a574936eb9ae4c884d&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-2-141589649-null-null.142^v102^pc_search_result_base1&utm_term=java%E4%B8%AD%E7%9A%84%E8%B4%A3%E4%BB%BB%E9%93%BE%E6%A8%A1%E5%BC%8F&spm=1018.2226.3001.4187