適用場景:
- 對於一個請求來說,如果有個對象都有機會處理它,而且不明確到底是哪個對象會處理請求時,我們可以考慮使用責任鏈模式實現它,讓請求從鏈的頭部往后移動,直到鏈上的一個節點成功處理了它為止
優點:
- 發送者不需要知道自己發送的這個請求到底會被哪個對象處理掉,實現了發送者和接受者的解耦
- 簡化了發送者對象的設計
- 可以動態的添加節點和刪除節點
缺點:
- 所有的請求都從鏈的頭部開始遍歷,對性能有損耗
- 極差的情況,不保證請求一定會被處理
自定義一個責任鏈
在java中不再存在指針了,如果我們想創建一個鏈表,只能是在本類中添加本類屬性, 因為我們想創建一個鏈表,所以這是必須的工作
需要提供set方法,讓當前的節點可以設置自己的下一個節點
處理請求的邏輯,設計成抽象方法,讓不同的節點根據自己的需求去實現
public abstract class Approver {
Approver approver;
String name;
// todo 抽象父類中可以存在構造函數,但是當我們創建子類時,必須要有一個參數的構造函數,
// todo 讓子類一個參數的構造函數,來給這個函數初始化
public Approver (String name){
this.name=name;
}
public abstract void ProcessRequest(PurchaseRequest request);
// 如果當前的處理器處理不了,就會往下傳播
public void setApprover( Approver approver){
this.approver=approver;
}
}
PurchaseRequest,需要被處理的請求,根據自己的需要各不相同
接着就是鏈表上的不同功能的節點都要實現上面的抽象類Approver,重寫它的抽象方法,添加上他們特定的功能
測試:
// 創建出各個節點
Approver1 approver1 = new Approver1();
Approver2 approver2 = new Approver2();
Approver3 approver3 = new Approver3();
// 設置他們關系
approver1.setApprover(approver2);
approver2.setApprover(approver3);
// 發起請求
Client client = new Client();
PurchaseRequest purchaseRequest = client.sendRequest();
// 處理請求
tom.ProcessRequest(purchaseRequest);
把請求傳遞給責任鏈的第一個節點,她會自動往后傳播下去,直到有一個節點成功處理了它
Netty的責任鏈設計
netty的pipeline設計,就采用了責任鏈設計模式, 底層采用雙向鏈表的數據結構, 將鏈上的各個處理器串聯起來
客戶端每一個請求的到來,netty都認為,pipeline中的所有的處理器都有機會處理它,因此,對於入棧的請求,全部從頭節點開始往后傳播,一直傳播到尾節點(來到尾節點的msg會被釋放掉)
netty的責任鏈模式中的組件
- 責任處理器接口
- pipeline中的處理器都它的具體實現
- 添加刪除責任處理器的接口
- 上下文
- 通過這個上下文,可以獲得需要的數據,屬性
- 責任終止機制
- pipeline中的每一個節點,都可以終止事件的傳播
netty的責任處理器接口
責任處理器接口, pipeline中的所有的handler的頂級抽象接口,它規定了所有的handler統一要有添加,移除,異常捕獲的行為
public interface ChannelHandler {
// todo 當handler被添加到真實的上下文中,並且准備處理事件時被調用
// todo handler 被添加進去的回調
void handlerAdded(ChannelHandlerContext ctx) throws Exception;
// todo 是 handler 被移出的后的 回調
void handlerRemoved(ChannelHandlerContext ctx) throws Exception;
@Deprecated
void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
@Inherited
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Sharable {
// no value
}
}
netty對責任處理接口,做了更細粒度的划分, 處理器被分成了兩種, 一種是站處理器ChannelInboundHandler,另一種是出站處理器ChannelOutboundHandler,這兩個接口都繼承自ChannelHandler
添加刪除責任處理器的接口
netty中所有的處理器最終都在添加在pipeline上,所以,添加刪除責任處理器的接口的行為 netty在channelPipeline中的進行了規定
public interface ChannelPipeline
extends ChannelInboundInvoker, ChannelOutboundInvoker, Iterable<Entry<String, ChannelHandler>> {
ChannelPipeline addFirst(String name, ChannelHandler handler);
ChannelPipeline addFirst(EventExecutorGroup group, String name, ChannelHandler handler);
ChannelPipeline addLast(String name, ChannelHandler handler);
ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler);
ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler);
...
上下文
pipeline中的handler被封裝進了上下文中,如下, 通過上下文,可以輕松拿到當前節點所屬的channel, 以及它的線程執行器
// todo AttributeMap -- 讓ChannelHandlerContext 可以存儲自定義的屬性
// todo ChannelInboundInvoker -- 讓ChannelHandlerContext 可以進行 InBound事件的傳播,讀事件,read 或者是 注冊事件 active事件
// todo ChannelOutboundInvoker -- 讓ChannelHandlerContext 可以傳播寫事件
public interface ChannelHandlerContext extends AttributeMap, ChannelInboundInvoker, ChannelOutboundInvoker {
// todo 獲取ChannelHandlerContext所對應的這個Channel對象
Channel channel();
// todo 獲取事件執行器
EventExecutor executor();
...
責任終止機制
責任終止機制
- 在pipeline中的任意一個節點,只要我們不手動的往下傳播下去,這個事件就會終止傳播在當前節點
- 對於入站數據,默認會傳遞到尾節點,進行回收,如果我們不進行下一步傳播,事件就會終止在當前節點,別忘記回收msg
- 對於出站數據,用header節點的使用unsafe對象,把數據寫會客戶端也意味着事件的終止
事件的傳播
底層事件的傳播使用的就是針對鏈表的操作
private AbstractChannelHandlerContext findContextInbound() {
AbstractChannelHandlerContext ctx = this;
do {
ctx = ctx.next;
} while (!ctx.inbound);
return ctx;
}
