Netty中的責任鏈模式


適用場景:

  • 對於一個請求來說,如果有個對象都有機會處理它,而且不明確到底是哪個對象會處理請求時,我們可以考慮使用責任鏈模式實現它,讓請求從鏈的頭部往后移動,直到鏈上的一個節點成功處理了它為止

優點:

  • 發送者不需要知道自己發送的這個請求到底會被哪個對象處理掉,實現了發送者和接受者的解耦
  • 簡化了發送者對象的設計
  • 可以動態的添加節點和刪除節點

缺點:

  • 所有的請求都從鏈的頭部開始遍歷,對性能有損耗
  • 極差的情況,不保證請求一定會被處理

自定義一個責任鏈

在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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM