首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Tomcat 系統架構與設計模式(第 2 部分):設計模式深度分析

     編輯:Java 相關知識

本文繼續深入探討 Tomcat 內部採用的核心設計模式,包括外觀模式、觀察者模式、命令模式與責任鏈模式,並透過原始碼層級的類圖與關鍵程式碼片段,解析這些模式如何支撐 Tomcat 的高效運作。

外觀模式

外觀模式在 Tomcat 中有多處使用,在 Request 和 Response 物件封裝中、Standard Wrapper 到 ServletConfig 封裝中、ApplicationContext 到 ServletContext 封裝中等都用到了這種設計模式。

外觀模式的原理

這麼多場合都用到了這種設計模式,那這種設計模式究竟能有什麼作用呢?顧名思義,就是將一個東西封裝成一個外觀好與人家更容易進行交流,就像一個國家的外交部一樣。這種設計模式主要用在一個大的系統中有多個子系統組成時,這多個子系統肯定要涉及到相互通訊,但是每個子系統又不能將自己的內部資料過多的暴露給其它系統,不然就沒有必要劃分子系統了。每個子系統都會設計一個外觀,把別的系統感興趣的資料封裝起來,通過這個外觀來進行存取。這就是外觀設計模式存在的意義。

外觀模式示意圖如下:

外觀示意圖

圖 1. 外觀示意圖

Client 只能存取到 Facade 中提供的資料是外觀模式的關鍵,至於 Client 如何存取 Facade 和 Subsystem 如何提供 Facade 外觀模式並沒有規定死。

Tomcat 的外觀模式範例

Tomcat 中外觀模式使用的很多,因為 Tomcat 中有很多不同組件,每個組件要相互交互資料,用外觀模式隔離資料是個很好的方法。下面是 Request 上使用的外觀模式:

Request 的外觀模式類圖

圖 2. Request 的外觀模式類圖

從圖中可以看出 HttpRequestFacade 類別封裝了 HttpRequest 介面能夠提供資料,通過 HttpRequestFacade 存取到的資料都被代理到 HttpRequest 中,通常被封裝的物件都被設為 Private 或者 Protected 存取修飾,以防止在 Facade 中被直接存取。

觀察者模式

這種設計模式也是常用的設計方法通常也叫發布-訂閱模式,也就是事件監聽機制,通常在某個事件發生的前後會觸發一些操作。

觀察者模式的原理

觀察者模式原理也很簡單,就是你在做事的時候旁邊總有一個人在盯著你,當你做的事情是它感興趣的時候,它就會跟著做另外一些事情。但是盯著你的人必須要到你那去登記,不然你無法通知它。觀察者模式通常包含下面這幾個角色:

  • Subject(抽象主題): 它負責管理所有觀察者的引用,同時定義主要的事件操作。
  • ConcreteSubject(具體主題): 它實作了抽象主題的所有定義的介面,當自己發生變化時,會通知所有觀察者。
  • Observer(觀察者): 監聽主題發生變化相應的操作介面。

Tomcat 的觀察者模式範例

Tomcat 中觀察者模式也有多處使用,前面講的控制組件生命週期的 Lifecycle 就是這種模式的體現,還有對 Servlet 實例的建立、Session 的管理、Container 等都是同樣的原理。下面主要看一下 Lifecycle 的具體實作。

Lifecycle 的觀察者模式結構圖:

Lifecycle 的觀察者模式結構圖

圖 3. Lifecycle 的觀察者模式結構圖

上面的結構圖中,LifecycleListener 代表的是抽象觀察者,它定義一個 lifecycleEvent 方法,這個方法就是當主題變化時要執行的方法。ServerLifecycleListener 代表的是具體的觀察者,它實作了 LifecycleListener 介面的方法,就是這個具體的觀察者具體的實作方式。Lifecycle 介面代表的是抽象主題,它定義了管理觀察者的方法和它要所做的其它方法。而 StandardServer 代表的是具體主題,它實作了抽象主題的所有方法。這裡 Tomcat 對觀察者做了擴展,增加了另外兩個類別:LifecycleSupport、LifecycleEvent,它們作為輔助類別擴展了觀察者的功能。LifecycleEvent 使得可以定義事件類別,不同的事件可區別處理,更加靈活。LifecycleSupport 類別代理了主題對多觀察者的管理,將這個管理抽出來統一實作,以後如果修改只要修改 LifecycleSupport 類別就可以了,不需要去修改所有具體主題,因為所有具體主題的對觀察者的操作都被代理給 LifecycleSupport 類別了。這可以認為是觀察者模式的改進版。

LifecycleSupport 呼叫觀察者的方法程式碼

public void fireLifecycleEvent(String type, Object data) {
    LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
    LifecycleListener interested[] = null;
    synchronized (listeners) {
        interested = (LifecycleListener[]) listeners.clone();
    }
    for (int i = 0; i < interested.length; i++)
        interested[i].lifecycleEvent(event);
}

主題如何通知觀察者

public void start() throws LifecycleException {
    lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
    lifecycle.fireLifecycleEvent(START_EVENT, null);
    started = true;
    synchronized (services) {
        for (int i = 0; i < services.length; i++) {
            if (services[i] instanceof Lifecycle)
                ((Lifecycle) services[i]).start();
        }
    }
    lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}

命令模式

前面把 Tomcat 中兩個核心組件 Connector 和 Container,比作一對夫妻。男的將接受過來的請求以命令的方式交給女主人。對應到 Connector 和 Container,Connector 也是透過命令模式呼叫 Container 的。

命令模式的原理

命令模式主要作用就是封裝命令,把發出命令的責任和執行命令的責任分開。也是一種功能的分工。不同的模組可以對同一個命令做出不同解釋。下面是命令模式通常包含下面幾個角色:

  • Client: 建立一個命令,並決定接受者
  • Command(命令): 命令介面定義一個抽象方法
  • ConcreteCommand(具體命令): 負責呼叫接受者的相應操作
  • Invoker(請求者): 負責呼叫命令物件執行請求
  • Receiver(接受者): 負責具體實施和執行一次請求

Tomcat 中的命令模式範例

Tomcat 中命令模式在 Connector 和 Container 組件之間有體現,Tomcat 作為一個應用伺服器,無疑會接受到很多請求,如何分配和執行這些請求是必須的功能。下面看一下 Tomcat 是如何實作命令模式的,下面是 Tomcat 命令模式的結構圖:

Tomcat 命令模式的結構圖

圖 4. Tomcat 命令模式的結構圖

Connector 作為抽象請求者,HttpConnector 作為具體請求者。HttpProcessor 作為命令。Container 作為命令的抽象接受者,ContainerBase 作為具體的接受者。客戶端就是應用伺服器 Server 組件了。Server 首先建立命令請求者 HttpConnector 物件,然後建立命令 HttpProcessor 命令物件。再把命令物件交給命令接受者 ContainerBase 容器來處理命令。命令的最終是被 Tomcat 的 Container 執行的。命令可以以佇列的方式進來,Container 也可以以不同的方式來處理請求,如 HTTP1.0 協議和 HTTP1.1 的處理方式就會不同。

責任鏈模式

Tomcat 中一個最容易發現的設計模式就是責任鏈模式,這個設計模式也是 Tomcat 中 Container 設計的基礎,整個容器的就是通過一個鏈連接在一起,這個鏈一直將請求正確的傳遞給最終處理請求的那個 Servlet。

責任鏈模式的原理

責任鏈模式,就是很多物件有每個物件對其下家的引用而連接起來形成一條鏈,請求在這條鏈上傳遞,直到鏈上的某個物件處理此請求,或者每個物件都可以處理請求,並傳給下一家,直到最終鏈上每個物件都處理完。這樣可以不影響客戶端而能夠在鏈上增加任意的處理節點。通常責任鏈模式包含下面幾個角色:

  • Handler(抽象處理者): 定義一個處理請求的介面
  • ConcreteHandler(具體處理者): 處理請求的具體類別,或者傳給下家

Tomcat 中責任鏈模式範例

在 tomcat 中這種設計模式幾乎被完整的使用,tomcat 的容器設置就是責任鏈模式,從 Engine 到 Host 再到 Context 一直到 Wrapper 都是通過一個鏈傳遞請求。Tomcat 中責任鏈模式的類別結構圖如下:

Tomcat 責任鏈模式的結構圖

圖 5. Tomcat 責任鏈模式的結構圖

上圖基本描述了四個子容器使用責任鏈模式的類別結構圖,對應的責任鏈模式的角色,Container 扮演抽象處理者角色,具體處理者由 StandardEngine 等子容器扮演。與標準的責任鏈不同的是,這裡引入了 Pipeline 和 Valve 介面。他們有什麼作用呢?

實際上 Pipeline 和 Valve 是擴展了這個鏈的功能,使得在鏈往下傳遞過程中,能夠接受外界的干預。Pipeline 就是連接每個子容器的管子,裡面傳遞的 Request 和 Response 物件好比管子裡流的水,而 Valve 就是這個管子上開的一個個小口子,讓你有機會能夠接觸到裡面的水,做一些額外的事情。為了防止水被引出來而不能流到下一個容器中,每一段管子最後總有一個節點保證它一定能流到下一個子容器,所以每個容器都有一個 StandardXXXValve。只要涉及到這種有鏈式處理流程這是一個非常值得借鑒的模式。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved