1. 程式人生 > >Tomcat中的Host和Engine級別的servlet容器

Tomcat中的Host和Engine級別的servlet容器

  這邊文章主要介紹的是Host容器 和 Engine容器。如果你想在同一個Tomcat上部署執行多個Context容器的話,你就需要使用Host容器,從理論上來講,如果你的Tomcat只想要部署一個Context容器的話,你可以不使用Host容器。

在org.apache.catalina.Context介面的描述有下一段話:

  Context容器的父容器通常是Host容器,也有可能是其他實現,或者如果不是必要的話,就可以不使用父容器。

  但是 在tomcat的實際部署中,總會使用一個Host容器,在下面在解釋原因,

  Engine容器表示Catalina的整個Servlet引擎,如果使用了Engine容器,那麼它總是處於容器層級的最頂層,新增到Enginer容器中的子容器通常是org.apache.catalina.Host 或者 org.apahce.catalina.Context的實現,預設情況下Tomcat會使用一個Engine容器並且使用一個Host容器作為其子容器,

Host介面 

  host容器是 org.apahce.catalina.Host介面的例項,Host介面繼承自Container介面

package org.apache.catalina;

/**
 * 
 * <p>
 * <b>Title:Host.java</b>
 * </p>
 * <p>
 * Copyright:ChenDong 2018
 * </p>
 * <p>
 * Company:僅學習時使用
 * </p>
 * <p>
 * 類功能描述:Host是表示Catalina servlet引擎中的虛擬主機的容器。它在以下型別的場景中很有用:
 * 
 * 
 * 
 * 您希望使用攔截器來檢視此特定虛擬主機處理的每個請求。
 * 
 * 您希望使用獨立的HTTP聯結器執行Catalina,但是仍然希望支援多個虛擬主機。
 * 
 * 通常,在部署連線到Web伺服器(如Apache)的Catalina時,您不會使用主機,因為聯結器將利用Web伺服器的設施來確定應該使用哪個上下文(
 * 或者甚至哪個包裝器)來處理這個請求。
 * 
 * 附加到主機的父容器通常是一個引擎,但是可以是一些其他的實現,或者如果不必要的話可以省略。
 * 
 * 
 * 
 * 附加到主機的子容器通常是上下文的實現(表示單個servlet上下文)。
 * </p>
 * 
 * 
@author * @date 2018年12月15日 下午9:28:58 * @version 1.0 */ public interface Host extends Container { // ----------------------------------------------------- Manifest Constants /** * * * 當使用<code>addAlias()</code>方法新增新的別名時傳送的 {@code ContainerEvent}事件型別。 */ public
static final String ADD_ALIAS_EVENT = "addAlias"; /** * 當使用<code>removeAlias()</code>移除一箇舊的別名時 觸發的 {@code ContainerEvent}事件型別 */ public static final String REMOVE_ALIAS_EVENT = "removeAlias"; // ------------------------------------------------------------- Properties /** * 返回此{@code Host}容器的 根路徑,它可以是 絕對路徑、相對路徑、或者URL */ public String getAppBase(); /** * * 為這個{@code Host}容器 設定一個根路徑,它可以是 絕對路徑、相對路徑、或者URL * * @param appBase * 新的容器根路徑 */ public void setAppBase(String appBase); /** * Return the value of the auto deploy flag. If true, it indicates that this * host's child webapps should be discovred and automatically deployed. */ public boolean getAutoDeploy(); /** * Set the auto deploy flag value for this host. * * @param autoDeploy * The new auto deploy flag */ public void setAutoDeploy(boolean autoDeploy); /** * * 為新的web應用程式設定 {@code DefaultContext}。 * * @param defaultContext * 新的 DefaultContext */ public void addDefaultContext(DefaultContext defaultContext); /** * 為新的web應用程式檢索 並返回 DefaultContext. */ public DefaultContext getDefaultContext(); /** * 返回此容器表示的虛擬主機的規範、完全限定的名稱 */ public String getName(); /** * 設定此容器表示的虛擬主機的規範、完全限定的名稱 * * @param name * 虛擬主機的名稱 * * @exception IllegalArgumentException * 如果這個名字是 {@code null} */ public void setName(String name); // --------------------------------------------------------- Public Methods /** * * 將DefaultContext 的 config 匯入到web應用程式上下文中。 * * @param context * 匯入預設Context的web應用程式Context */ public void importDefaultContext(Context context); /** * 新增應該對映到同一主機的別名 * * @param alias * 要被新增的別名 */ public void addAlias(String alias); /** * * 返回此主機的別名集。如果沒有定義,則返回一個零長度陣列 */ public String[] findAliases(); /** * * 返回一個用來處理引用Http請求的 Context 根據 請求的URI 若果不存在則返回 * * @param uri * Request URI to be mapped */ public Context map(String uri); /** * 從此主機的別名中刪除指定的別名 * * @param alias * 要被刪除的別名 */ public void removeAlias(String alias); }

下面說下它在Tomat中的標準實現

StandardHost類

  在Catalina中的  org.apache.catalina.core.StandardHost類 是 org.apache.catalin.Host介面的標準實現,該類繼承自 org.apache.catalina.core.ContainerBase類 ,實現了 Host 和 Deployer介面。

與StandardContext 和 StandardWrapper 類 相似,StandardHost類的構造器函式會將一個基礎閥的例項 新增到其管道對相中。

    /**
     * 
     * 建立一個帶有基礎閥的 {@code  StandardHost}例項
     */
    public StandardHost() {

        super();
        pipeline.setBasic(new StandardHostValve());

    }

那麼 它的基礎閥 就是 org.apahce.catalina.core.StandardHostValue類的例項,

  當呼叫 StandardHost 類的 start()方法時,StandardHost例項 會新新增兩個閥,分別是 ErrorReportValue類 和 ErrorDispatcherValue類的例項,這個兩個閥均位於org.apahce.catalina.values包下,

 1 /**
 2      * 啟動這個Host.
 3      *
 4      * @exception LifecycleException
 5      *                如果此元件檢測到阻止其啟動的致命錯誤
 6      * 
 7      */
 8     public synchronized void start() throws LifecycleException {
 9         // 如果 errorReportValveClass 閥的 完全限定名 不為空 的話 
10         if ((errorReportValveClass != null) && (!errorReportValveClass.equals(""))) {
11             try {
12                 Valve valve = (Valve) Class.forName(errorReportValveClass).newInstance();
13                 //新增這個ErrorReportValve閥
14                 addValve(valve);
15             } catch (Throwable t) {
16                 log(sm.getString("standardHost.invalidErrorReportValveClass", errorReportValveClass));
17             }
18         }
19 
20         //新增一個ErrorDispatcherValve閥
21         addValve(new ErrorDispatcherValve());
22 
23         super.start();
24 
25     }

變數 errorReportValueClass的值 定義在StandardHost類中;

private String errorReportValveClass = "org.apache.catalina.valves.ErrorReportValve";

  每當引入一個Http請求的時候,都會呼叫StandardHost例項的 invoke方法,由於StandardHost類並沒有提供invoke方法的實現,因此它會呼叫父類 ContainerBase 類的 invoke方法,而ContainerBase類 的invoke方法將會呼叫StandardHost類的 基礎閥StandardHostValue例項的invoke方法,StandardHostValue的invoke方法將會呼叫StandardHostr類的map方法來獲取響應的Context例項來處理Http請求。

 1 /**
 2      * 
 3      * 返回一個Context例項 來處理這個 相對於Host容器的 相對URI所代表的請求,如果沒有則返回 <code>null</code>
 4      *
 5      * @param uri
 6      *            要被對映的請求URI
 7      */
 8     public Context map(String uri) {
 9 
10         if (debug > 0)
11             log("Mapping request URI '" + uri + "'");
12         if (uri == null)
13             return (null);
14 
15         // Match on the longest possible context path prefix
16         // 匹配可能是最長的Context路徑字首
17         if (debug > 1)
18             log("  Trying the longest context path prefix");
19         Context context = null;
20         String mapuri = uri;
21         while (true) {
22             // 不斷嘗試根據路徑去子容器中找對應的Context
23             context = (Context) findChild(mapuri);
24             if (context != null)
25                 break;
26             int slash = mapuri.lastIndexOf('/');
27             if (slash < 0)
28                 break;
29             // 不斷擷取路徑最後一個/之前的路徑 做匹配路徑
30             mapuri = mapuri.substring(0, slash);
31         }
32 
33         
34         // 如果沒有匹配到Context 則選擇 預設的Context
35         if (context == null) {
36             if (debug > 1)
37                 log("  Trying the default context");
38             context = (Context) findChild("");
39         }
40 
41         //如果還是沒有選中的 Context 直接返回null 並返回 錯誤資訊
42         if (context == null) {
43             log(sm.getString("standardHost.mappingError", uri));
44             return (null);
45         }
46 
47         // 返回對映的上下文(如果有的話)
48         if (debug > 0)
49             log(" Mapped to context '" + context.getPath() + "'");
50         return (context);
51 
52     }

今天想更新到這裡 明天繼續搞起