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類的構造器函式會將一個基礎閥的例項 新增到其管道對相中。
/** * * 建立一個帶有基礎閥的 {@codeStandardHost}例項 */ 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*/ 8public synchronized void start() throws LifecycleException { 9// 如果 errorReportValveClass 閥的 完全限定名 不為空 的話 10if ((errorReportValveClass != null) && (!errorReportValveClass.equals(""))) { 11try { 12Valve valve = (Valve) Class.forName(errorReportValveClass).newInstance(); 13//新增這個ErrorReportValve閥 14addValve(valve); 15} catch (Throwable t) { 16log(sm.getString("standardHost.invalidErrorReportValveClass", errorReportValveClass)); 17} 18} 19 20//新增一個ErrorDispatcherValve閥 21addValve(new ErrorDispatcherValve()); 22 23super.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*/ 8public Context map(String uri) { 9 10if (debug > 0) 11log("Mapping request URI '" + uri + "'"); 12if (uri == null) 13return (null); 14 15// Match on the longest possible context path prefix 16// 匹配可能是最長的Context路徑字首 17if (debug > 1) 18log("Trying the longest context path prefix"); 19Context context = null; 20String mapuri = uri; 21while (true) { 22// 不斷嘗試根據路徑去子容器中找對應的Context 23context = (Context) findChild(mapuri); 24if (context != null) 25break; 26int slash = mapuri.lastIndexOf('/'); 27if (slash < 0) 28break; 29// 不斷擷取路徑最後一個/之前的路徑 做匹配路徑 30mapuri = mapuri.substring(0, slash); 31} 32 33 34// 如果沒有匹配到Context 則選擇 預設的Context 35if (context == null) { 36if (debug > 1) 37log("Trying the default context"); 38context = (Context) findChild(""); 39} 40 41//如果還是沒有選中的 Context 直接返回null 並返回 錯誤資訊 42if (context == null) { 43log(sm.getString("standardHost.mappingError", uri)); 44return (null); 45} 46 47// 返回對映的上下文(如果有的話) 48if (debug > 0) 49log(" Mapped to context '" + context.getPath() + "'"); 50return (context); 51 52}
今天想更新到這裡 明天繼續搞起