Netty責任鏈模式

責任鏈模式

責任鏈模式的定義:使多個對象都有機會處理請求,從而避免請求的發送者和接受者之間的耦合關係, 將這個對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理他爲止。責任鏈模式的重點在“鏈上”,由一條鏈去處理相似的請求,在鏈中決定誰來處理這個請求,並返回相應的結果。    

Netty的責任鏈設計

 netty的pipeline設計,就採用了責任鏈設計模式, 底層採用雙向鏈表的數據結構, 將鏈上的各個處理器串聯起來

 客戶端每一個請求的到來,netty都認爲,pipeline中的所有的處理器都有機會處理它,因此,對於入棧的請求,全部從頭節點開始往後傳播,一直傳播到尾節點(來到尾節點的msg會被釋放掉)

netty的責任鏈模式中的組件

a.責任處理器接口:pipeline中的處理器都有它的具體實現
b.添加刪除責任處理器的接口

c.上下文:通過這個上下文,可以獲得需要的數據,屬性
d.責任終止機制:pipeline中的每一個節點,都可以終止事件的傳播

netty的責任處理器接口

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package io.netty.channel;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public interface ChannelHandler {

    //  當handler被添加到真實的上下文中,並且準備處理事件時被調用
    //  handler 被添加進去的回調
    void handlerAdded(ChannelHandlerContext var1) throws Exception;

    //  是 handler 被移出的後的 回調
    void handlerRemoved(ChannelHandlerContext var1) throws Exception;

    /** @deprecated */
    @Deprecated
    void exceptionCaught(ChannelHandlerContext var1, Throwable var2) throws Exception;

    @Inherited
    @Documented
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Sharable {
    }
}

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, 以及它的線程執行器

package io.netty.channel;

import io.netty.buffer.ByteBufAllocator;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.AttributeMap;
import io.netty.util.concurrent.EventExecutor;
// todo AttributeMap:讓ChannelHandlerContext 可以存儲自定義的屬性
// ChannelInboundInvoker:讓ChannelHandlerContext 可以進行InBound事件的傳播,
//讀事件,read 或者是  註冊事件 active事件
// ChannelOutboundInvoker -- 讓ChannelHandlerContext 可以傳播寫事件
public interface ChannelHandlerContext extends AttributeMap, ChannelInboundInvoker, ChannelOutboundInvoker {
    Channel channel();

    EventExecutor executor();

    .....
}

 責任終止機制

在pipeline中的任意一個節點,只要我們不手動的往下傳播下去,這個事件就會終止傳播在當前節點
對於入站數據,默認會傳遞到尾節點,進行回收,如果我們不進行下一步傳播,事件就會終止在當前節點,別忘記回收msg
對於出站數據,用header節點的使用unsafe對象,把數據寫會客戶端也意味着事件的終止

Netty的責任鏈模式各個類的職責如下: 
Channel:封裝了jdk原生的channel,提供統一的API,作爲其它各個功能組件的容器。

ChannelPipeline:責任鏈模式的核心組件,ChannelHandler的容器,按順序組織各個ChannelHandler,並在它們之間轉發事件。

ChannelHandlerContext:封裝一個具體的ChannelHandler,併爲ChannelHandler的執行提供一個線程環境(ChannelHandlerInvoker)可以理解爲ChannelPipeline鏈路上的一個節點,節點裏麪包含有指向前後節點的指針,事件在各個ChannelHandler之間傳遞,靠的就是ChannelHandlerContext。

ChannelHandlerInvoker:顧名思義,是ChannelHandler的一個Invoker,它存在的意義是爲ChannelHandler提供一個運行的線程環境,默認的實現DefaultChannelHandlerInvoker有一個EventExecutor類型的成員,就是Netty的EventLoop線程,所以默認ChannelHandler的處理邏輯在EventLoop線程內。當然也可以提供不同的實現,替換默認的線程模型。

ChannelHandler: 真正對IO事件作出響應和處理的地方,也是Netty暴露給業務代碼的一個擴展點。一般來說,主要業務邏輯就是以自定義ChannelHandler的方式來實現的。

總結:

關於Netty責任鏈模式,重點應瞭解ChannelPipeline,及DefaultChannelPipeline這個默認的實現類,這其實就是一個鏈表管理類,管理者每一個ChannelHandlerContext類型的節點,從它的addFirst、addLast、remove等成員方法就可以看出來。

ChannelHandler是一個頂級接口,有兩個子接口ChannelInboundHandler和ChannelOutboundHandler分別處理read和write相關的IO事件,爲了便於業務方實現,兩個子接口分別有一個簡單的Adapter實現類,所有方法的默認實現都是代理給ChannelHandlerContext類(其實是不關心事件,直接轉發給pipeline中下一個節點的handler來處理)。業務方實現自己的ChannelHandler時,推薦繼承相應的Adapter類,只實現自己關心的事件的處理方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章