tomcat4.0版本。

Host容器的职责是根据url的context来匹配特定的context容器处理请求。host在url中就是域名。

host的构造方法会加入basic的valve:

/**
* Create a new StandardHost component with the default basic Valve.
*/
public StandardHost() {

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

}


在start方法加入了一个errorReport的valve:

/**
* Start this host.
*
* @exception LifecycleException if this component detects a fatal error
* that prevents it from being started
*/
public synchronized void start() throws LifecycleException {

// Set error report valve
if ((errorReportValveClass != null)
&& (!errorReportValveClass.equals(""))) {
try {
Valve valve = (Valve) Class.forName(errorReportValveClass)
.newInstance();
addValve(valve);
} catch (Throwable t) {
log(sm.getString
("standardHost.invalidErrorReportValveClass",
errorReportValveClass));
}
}

// Set dispatcher valve
addValve(new ErrorDispatcherValve());

super.start();

}

最终匹配context的方法在stardardhostvalve中的invoke方法:

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);

Thread.currentThread().setContextClassLoader
(StandardHostValve.class.getClassLoader());

}


其中会调用host的map方法匹配一个context,调用context的invoke方法处理请求:

/**
* 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) {

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);

}