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}事件型別。 */ publicstatic 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 }
今天想更新到這裡 明天繼續搞起