《how tomcat work》 搬运工 Chapter 13: Host and Engine
Host和Engine是container的其中一种。
如果想要tomcat能够包含多个网站,则需要Host来包含多个context。
1.Host
The Host 接口
public interface Host extends Container { public static final String ADD_ALIAS_EVENT = "addAlias"; public static final String REMOVE_ALIAS_EVENT = "removeAlias"; /** * Return the application root for this Host. * This can be an absolute * pathname, a relative pathname, or a URL. */ public String getAppBase(); /** * Set the application root for this Host. This can be an absolute * pathname, a relative pathname, or a URL. * * @param appBase The new application root */ 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); /** * Set the DefaultContext * for new web applications. * * @param defaultContext The new DefaultContext */ public void addDefaultContext(DefaultContext defaultContext); /** * Retrieve the DefaultContext for new web applications. */ public DefaultContext getDefaultContext(); /** * Return the canonical, fully qualified, name of the virtual host * this Container represents. */ public String getName(); /** * Set the canonical, fully qualified, name of the virtual host * this Container represents. * * @param name Virtual host name * * @exception IllegalArgumentException if name is null */ public void setName(String name); /** * Import the DefaultContext config into a web application context. * * @param context web application context to import default context */ public void importDefaultContext(Context context); /** * Add an alias name that should be mapped to this same Host. * * @param alias The alias to be added */ public void addAlias(String alias); /** * Return the set of alias names for this Host. If none are defined, * a zero length array is returned. */ public String[] findAliases(); /** * Return the Context that would be used to process the specified * host-relative request URI, if any; otherwise return * <code>null</code>. * * @param uri Request URI to be mapped */ public Context map(String uri); /** * Remove the specified alias name from the aliases for this Host. * @param alias Alias name to be removed */ public void removeAlias(String alias); }
StandardHost
像 StandardContext 和the StandardWrapper classes一样,standardHost在构造函数中添加StandardHostValve到pipeline中。每接受一个请求,standardHost都会触发它的基类baseContainer的invoke方法,而当pipeline触发到standardHostValue的invoke方法时,会通过host的map方法来查找正确的context。
public Context map(String uri) { if (debug > 0) log("Mapping request URI '" + uri + "'"); if (uri == null) return (null); // Match on the longest possible context path prefix if (debug > 1) log(" Trying the longest context path prefix"); Context context = null; String mapuri = uri; while (true) { context = (Context) findChild(mapuri); if (context != null) break; int slash = mapuri.lastIndexOf('/'); if (slash < 0) break; mapuri = mapuri.substring(0, slash); } // If no Context matches, select the default Context if (context == null) { if (debug > 1) log(" Trying the default context"); context = (Context) findChild(""); } // Complain if no Context has been selected if (context == null) { log(sm.getString("standardHost.mappingError", uri)); return (null); } // Return the mapped Context (if any) if (debug > 0) log(" Mapped to context '" + context.getPath() + "'"); return (context); }
StandardHostMapper
在ContaninerBase类中,会在start()方法调用addDefaultMapper()方法来新建一个defaulet mapper,而在standardHost中会添加一个StandardHostMapper,而StandardHostMapper也是继承ContainerBase的,所以StandardHostMapper里的map方法是调用Host的map方法。
StandardHostValve
作为pipeline的basevalue,standardHostValve的作用就是查找适当的context处理请求,查看是否有session,更新session的时间限制。
public void invoke(Request request, Response response, ValveContext valveContext) throws IOException, ServletException { // Validate the request and response object types if (!(request.getRequest() instanceof HttpServletRequest) || !(response.getResponse() instanceof HttpServletResponse)) { return; // NOTE - Not much else we can do generically } // Select the Context to be used for this Request StandardHost host = (StandardHost) getContainer(); Context context = (Context) host.map(request, true); if (context == null) { ((HttpServletResponse) response.getResponse()).sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, sm.getstring("StandardHost.noContext")); return; } // Bind the context CL to the current thread Thread.currentThread().setContextClassLoader(context.getLoader().getClassLoader()); // Update the session last access time for our session (if any) HttpServletRequest hreq = (HttpServletRequest) request.getRequest(); String sessionId = hreq.getRequestedSessionId(); if (sessionId != null) { Manager manager = context.getManager(); if (manager != null) { Session session = manager.findSession(sessionId); if ((session != null) && session.isValid()) session.access(); } } // Ask this Context to process this request context.invoke(request, response); }
2.Engine
Engine就代表了整个 Catalina servlet,你使用Engine就可以用多个host
The Engine 接口
public interface Engine extends Container { /** * Return the default hostname for this Engine. */ public String getDefaultHost(); /** * Set the default hostname for this Engine. * * @param defaultHost The new default host */ public void setDefaultHost(String defaultHost); /** * Retrieve the JvmRouteId for this engine. */ public String getJvmRoute(); /** * Set the JvmRouteId for this engine. * * @param jvmRouteId the (new) JVM Route ID. Each Engine within a * cluster must have a unique JVM Route ID. */ public void setJvmRoute(String jvmRouteId); /** * Return the <code>Service</code> with which we are associated (if * any). */ public Service getService(); /** * Set the <code>Service</code> with which we are associated (if * any). * * @param service The service that owns this Engine */ public void setService(Service service); /** * Set the DefaultContext * for new web applications. * * @param defaultContext The new DefaultContext */ public void addDefaultContext(DefaultContext defaultContext); /** * Retrieve the DefaultContext for new web applications. */ public DefaultContext getDefaultContext(); /** * Import the DefaultContext config into a web application context. * * @param context web application context to import default context */ public void importDefaultContext(Context context); }
StandardEngineValve
这个和standardHostValve差不多,查找正确的Host来处理请求
public void invoke(Request request, Response response,ValveContext valveContext) throws IOException, ServletException { // Validate the request and response object types if (!(request.getRequest() instanceof HttpServletRequest) || !(response.getResponse() instanceof HttpServletResponse)) { return; // NOTE - Not much else we can do generically } // Validate that any HTTP/1.1 request included a host header HttpServletRequest hrequest = (HttpServletRequest) request; if ("HTTP/1.1".equals(hrequest.getProtocol()) && (hrequest.getServerName() == null)) { ((HttpServletResponse)response.getResponse()).sendError(HttpServletResponse.SC_BAD_REQUEST,sm.getString("standardEngine.noHostHeader", request.getRequest().getServerName())); return; } // Select the Host to be used for this Request StandardEngine engine = (StandardEngine) getContainer(); Host host = (Host) engine.map(request, true); if (host == null) { ((HttpServletResponse) response.getResponse()).sendError(HttpServletResponse.SC_BAD_REQUEST,sm.getString("standardEngine.noHost",request.getRequest().getServerName())); return; } // Ask this Host to process this request host.invoke(request, response); }