自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

徹底搞懂管道-過濾器模式

開發(fā) 前端
在日常開發(fā)過程中,我們可以在確保主流程不受影響的基礎上,通過管道 - 過濾器模式添加各種定制化的附加流程,滿足不同的應用場景。

在面向請求/響應式的系統(tǒng)中,我們經(jīng)常會在多個請求之間實現(xiàn)一些集中而通用處理的需求,比如要對每個請求檢查數(shù)據(jù)編碼方式、記錄日志信息、壓縮輸出等。要滿足這些需求,就要在請求響應代碼的主流程中嵌入一些定制化組件。

所以,從架構設計上講,為了容易添加或刪除定制化組件,而不干擾主流程,我們需要在定制化組件與請求處理主流程之間實現(xiàn)松耦合;

同時,從提升它們的可重用性上講,我們也需要確保每個組件都能自主存在,而且組件之間能相互獨立。如下圖所示:

圖片圖片

如何實現(xiàn)這樣的效果呢?幸好,在架構設計領域中存在一種類似的模式,就是管道 - 過濾器模式。

接下來我具體講一講什么是管道 - 過濾器模式,以及如何實現(xiàn)。

什么是管道 - 過濾器模式?

管道 - 過濾器在結構上是一種組合行為,通常以切面(Aspect)的方式在主流程上添加定制化組件。當我們在閱讀一些開源框架和代碼,看到 Filter(過濾器)或 Interceptor(攔截器)等名詞時,往往就是碰到了管道 - 過濾器模式。

管道 - 過濾器結構主要包括過濾器(Filter)和管道(Pipe)兩種組件:

圖片圖片

在管道 - 過濾器結構中,過濾器負責執(zhí)行具體的業(yè)務邏輯,每個過濾器都會接收來自主流程的請求,并返回一個響應結果到主流程中。而管道則用來獲取來自過濾器的請求和響應,并傳遞到后續(xù)的過濾器中,相當于是一種通道。

管道 - 過濾器風格的一個典型應用是 Web 容器的 Filter 機制。你可以看到,在生成最終的 HTTP 響應之前,Web 容器通過添加多個 Filter 對 HTTP 響應結果進行處理:

圖片圖片

管道 - 過濾器模式示例

在介紹完管道 - 過濾器模式的基本概念之后,我們來看一個它的簡單示例,幫你更深入地認識這一模式。

設想我們存在一個 Order 對象,代表現(xiàn)實世界中的訂單概念,包含一些常規(guī)屬性比如訂單編號(orderNumber)、聯(lián)系方式(contactInfo)、收貨地址(address)和貨物信息(goods):

public class Order {
  private String orderNumber;
  private String contactInfo;
  private String address;
  private String goods;
}

基于這個 Order 對象,我們構建一個 Filter 鏈來分別完成 Order 中核心屬性的校驗:

  • GoodsNotEmptyFilter,驗證 Order 對象中“goods”字段是否為空;
  • OrderNumberNotInvalidFilter,驗證 Order 對象中“orderNumber”字段是否符合特定的命名規(guī)則;
  • AddressNotInvalidFilter,驗證 Order 對象中“address”字段是否是一個合法的收貨地址。

這些 Filter 通過對應的 Pipe 組件構成一個完成的處理鏈路:

圖片圖片

從這個例子中,你可以看到管道 - 過濾器模式的特點在于:把一系列的定制化需求轉(zhuǎn)換成一種類似數(shù)據(jù)流的處理方式,數(shù)據(jù)通過管道流經(jīng)一系列的過濾器,在每個過濾器中完成特定的業(yè)務邏輯。

顯然,每個過濾器能夠獨立完成自身的職責,不需要依賴于其他過濾器,過濾器之間沒有耦合度。

這種特性使得系統(tǒng)的擴展性得到了巨大的提升,我們很容易就能對現(xiàn)有的過濾器進行替換,而且對過濾器進行動態(tài)添加和刪除也不會對整個處理流程產(chǎn)生任何影響。

管道 - 過濾器模式在開源框架中的應用

現(xiàn)在,相信你對管道 - 過濾器的基本結構和實現(xiàn)方式已經(jīng)有了基本了解。接下來,我來講解開源框架中的管道 - 過濾器設計方法和實現(xiàn)細節(jié),進一步加深你的理解。

事實上,很多開源框架中都應用了管道 - 過濾器這個架構模式,也都提供了基于過濾器鏈的實現(xiàn)方式,例如 Dubbo 中的過濾器概念就基本符合我們對這一模式的理解。

接下來我們以 Dubbo 為例,先看一下過濾器鏈的構建過程,再介紹 Dubbo 中現(xiàn)有過濾器的實現(xiàn)方法。

圖片圖片

Dubbo 中對 Filter 的處理基于一種 Wrapper 機制。所謂 Wrapper,顧名思義,是對 Dubbo 中各種擴展點的一種包裝。(如上圖)

目前,縱觀整個 Dubbo 框架,只存在一個 Wrapper,即 ProtocolFilterWrapper。

在該類中,存在這樣一個用來構建調(diào)用鏈的 buildInvokerChain 方法:

private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
        //獲取Invoker對象
        Invoker<T> last = invoker;
        //加載過濾器列表
        List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
        if (filters.size() > 0) {
            for (int i = filters.size() - 1; i >= 0; i--) {
                final Filter filter = filters.get(i);
                final Invoker<T> next = last;
                last = new Invoker<T>() {
                       //講Filter作用于Invoker對象
                };
            }
        }
        return last;
}

我們可以看到用于獲取擴展點的 ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension() 方法。注意,這里對通過擴展點加載的過濾器進行了排序,從而確保過濾器鏈按設想的順序進行執(zhí)行。

看完過濾器鏈,我們來看一下過濾器。Dubbo 中的 Filter 接口定義是這樣的:

@SPI
public interface Filter {
    Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException;
}

可以看到 Filter 接口能夠獲取傳入的 Invoker,從而對其進行攔截和處理。針對 Filter 接口,Dubbo 中一共存在一大批個實現(xiàn)類,類層結構如下圖所示:

圖片圖片

這些過濾器可以大致分成兩類:

  • 面向服務提供者的過濾器
  • 面向服務消費者的過濾器

其中面向服務提供者的過濾器只會在服務暴露時對 Invoker 進行過濾,例如上圖中的 TimeoutFilter 和 TraceFilter。

而面向服務消費者的過濾器發(fā)生作用的階段是在服務引用時,例如上圖中的 ConsumerContextFilter 和 FutureFilter。

一般的過濾器只能屬于這兩種類型中的一種,但是 MonitorFilter 是個例外,它可以同時作用于服務暴露和服務引用階段,因為它需要對這兩個階段都進行監(jiān)控。

我挑選一個有代表性的 TokenFilter 給你介紹一下。

TokenFilter 的作用很明確,就是通過 Token 進行訪問鑒權,通過對比 Invoker 中的 Token 和傳入?yún)?shù)中的 Token 來判斷是否是合法的請求,其代碼如下所示:

@Activate(group = Constants.PROVIDER, value = Constants.TOKEN_KEY)
public class TokenFilter implements Filter {
    public Result invoke(Invoker<?> invoker, Invocation inv)
            throws RpcException {
        //獲取Token
        String token = invoker.getUrl().getParameter(Constants.TOKEN_KEY);
        if (ConfigUtils.isNotEmpty(token)) {
            Class<?> serviceType = invoker.getInterface();
            //獲取請求的輔助信息
            Map<String, String> attachments = inv.getAttachments();
            //獲取遠程Token
            String remoteToken = attachments == null ? null : attachments.get(Constants.TOKEN_KEY);
            //判斷本地Token和遠程Token是否一致
            if (!token.equals(remoteToken)) {
                throw new RpcException("Invalid token! Forbid invoke remote service " + serviceType + " method " + inv.getMethodName() + "() from consumer " + RpcContext.getContext().getRemoteHost() + " to provider " + RpcContext.getContext().getLocalHost());
            }
        }
        return invoker.invoke(inv);
    }
}

在代碼中可以看到,通過 invoker.getUrl() 方法獲取了 Invoker 中的 URL 對象,而我們知道 Dubbo 中的 URL 作為統(tǒng)一數(shù)據(jù)模型,它包含了所有服務調(diào)用過程中的參數(shù),這里的 Invocation 對象則封裝了請求數(shù)據(jù)。

這樣,一方面我們通過 URL 對象獲取本地 Token 參數(shù),另一方面通過 Invocation 的 Attachments 也獲取了 RemoteToken,可以執(zhí)行對比和校驗操作。這也是在 Dubbo 中處理調(diào)用信息傳遞的很常見的一種做法,你可以在很多地方看到類似的代碼。

總結

可以說,如何動態(tài)把握請求的處理流程是任何系統(tǒng)開發(fā)面臨的一大問題,而今天講解的管道 - 過濾器模式就為解決這一問題提供了有效的方案。

在日常開發(fā)過程中,我們可以在確保主流程不受影響的基礎上,通過管道 - 過濾器模式添加各種定制化的附加流程,滿足不同的應用場景。

從架構設計上,管道 - 過濾器可以說是高內(nèi)聚、低耦合思想的典型實現(xiàn)方案,也符合開放 - 關閉原則。各個過濾器各司其職,相互獨立,多個過濾器之間集成也比較簡單,在功能重用性和維護性上都具備優(yōu)勢。

另一方面,我們也應該認識到管道 - 過濾器的最大問題在于,導致系統(tǒng)形成一種成批操作行為,因此在使用過程中需要設計并協(xié)調(diào)數(shù)據(jù)的流向

責任編輯:武曉燕 來源: 程序員技術充電站
相關推薦

2024-01-05 09:04:35

隆過濾器數(shù)據(jù)結構哈希函數(shù)

2021-07-05 15:22:03

Servlet過濾器客戶端

2024-11-04 08:45:48

布隆過濾器元數(shù)據(jù)指紋值

2009-07-08 15:30:56

Servlet過濾器

2009-07-08 16:07:04

Servlet過濾器配

2009-09-29 13:55:23

Hibernate設置

2009-07-14 09:09:08

Swing模型過濾器

2011-06-29 16:14:59

Qt 事件 過濾器

2009-06-18 10:13:00

Hibernate過濾

2017-07-18 14:10:31

大數(shù)據(jù)Apache Flum過濾器

2009-07-08 17:33:37

Servlet過濾器

2009-09-25 15:19:44

Hibernate過濾

2020-08-28 13:02:17

布隆過濾器算法

2009-07-06 13:02:49

Servlet過濾器

2024-03-15 11:21:22

布隆過濾器數(shù)據(jù)庫數(shù)據(jù)

2023-01-26 01:41:27

核心全局過濾器

2016-12-07 09:56:13

JavaFilter過濾器

2010-03-01 14:45:07

Linux文件重定向

2017-04-12 14:43:01

Spring ClouZuul過濾器

2009-07-03 18:26:11

Servlet過濾器
點贊
收藏

51CTO技術棧公眾號