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