Tomcat 中的 Host
Host 定义
public interface Host extends Container {
public static final String ADD_ALIAS_EVENT = "addAlias";
public static final String REMOVE_ALIAS_EVENT = "removeAlias";
public String getXmlBase();
public void setXmlBase(String xmlBase);
public File getConfigBaseFile();
public String getAppBase();
public File getAppBaseFile();
public void setAppBase(String appBase);
public boolean getAutoDeploy();
public void setAutoDeploy(boolean autoDeploy);
public String getConfigClass();
public void setConfigClass(String configClass);
public boolean getDeployOnStartup();
public void setDeployOnStartup(boolean deployOnStartup);
public String getDeployIgnore();
public Pattern getDeployIgnorePattern();
public void setDeployIgnore(String deployIgnore);
public ExecutorService getStartStopExecutor();
public boolean getCreateDirs();
public void setCreateDirs(boolean createDirs);
public boolean getUndeployOldVersions();
public void setUndeployOldVersions(boolean undeployOldVersions);
public void addAlias(String alias);
public String[] findAliases();
public void removeAlias(String alias);
}
从定义中可以看出
- Host 继承了 Container 接口,而 Container 接口继承了 Lifecycle 接口
- Host 有部署服务功能
- Host 的实现类是 StandardHost
StandardHost 的构造方法
public StandardHost() {
super();
//设置基础阀 StandardHostValve
pipeline.setBasic(new StandardHostValve());
}
StandardHost 的 startInternal 方法
protected synchronized void startInternal() throws LifecycleException {
// Set error report valve
//在 pipeline 中添加 org.apache.catalina.valves.ErrorReportValve
String errorValve = getErrorReportValveClass();
if ((errorValve != null) && (!errorValve.equals(""))) {
try {
boolean found = false;
Valve[] valves = getPipeline().getValves();
for (Valve valve : valves) {
if (errorValve.equals(valve.getClass().getName())) {
found = true;
break;
}
}
if(!found) {
Valve valve =
(Valve) Class.forName(errorValve).getConstructor().newInstance();
getPipeline().addValve(valve);
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
log.error(sm.getString(
"standardHost.invalidErrorReportValveClass",
errorValve), t);
}
}
//直接调用父类的方法,这里需要注意在父类的 startInternal 方法中会加载Host的子容器 Context
super.startInternal();
}
StandardHost 的基础阀 -- StandardHostValve
public final void invoke(Request request, Response response)
throws IOException, ServletException {
// Select the Context to be used for this Request
//从 request 中获取 Context 对象
Context context = request.getContext();
if (context == null) {
return;
}
if (request.isAsyncSupported()) {
request.setAsyncSupported(context.getPipeline().isAsyncSupported());
}
boolean asyncAtStart = request.isAsync();
try {
context.bind(Globals.IS_SECURITY_ENABLED, MY_CLASSLOADER);
if (!asyncAtStart && !context.fireRequestInitEvent(request.getRequest())) {
// Don't fire listeners during async processing (the listener
// fired for the request that called startAsync()).
// If a request init listener throws an exception, the request
// is aborted.
return;
}
// Ask this Context to process this request. Requests that are
// already in error must have been routed here to check for
// application defined error pages so DO NOT forward them to the the
// application for processing.
try {
if (!response.isErrorReportRequired()) {
//调用 Context 的pipeline
context.getPipeline().getFirst().invoke(request, response);
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
container.getLogger().error("Exception Processing " + request.getRequestURI(), t);
// If a new error occurred while trying to report a previous
// error allow the original error to be reported.
if (!response.isErrorReportRequired()) {
request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t);
throwable(request, response, t);
}
}
// Now that the request/response pair is back under container
// control lift the suspension so that the error handling can
// complete and/or the container can flush any remaining data
response.setSuspended(false);
Throwable t = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
// Protect against NPEs if the context was destroyed during a
// long running request.
if (!context.getState().isAvailable()) {
return;
}
// Look for (and render if found) an application level error page
if (response.isErrorReportRequired()) {
// If an error has occurred that prevents further I/O, don't waste time
// producing an error report that will never be read
AtomicBoolean result = new AtomicBoolean(false);
response.getCoyoteResponse().action(ActionCode.IS_IO_ALLOWED, result);
if (result.get()) {
if (t != null) {
throwable(request, response, t);
} else {
status(request, response);
}
}
}
if (!request.isAsync() && !asyncAtStart) {
context.fireRequestDestroyEvent(request.getRequest());
}
} finally {
// Access a session (if present) to update last accessed time, based
// on a strict interpretation of the specification
if (ACCESS_SESSION) {
request.getSession(false);
}
context.unbind(Globals.IS_SECURITY_ENABLED, MY_CLASSLOADER);
}
}
- StandardHostValve 中只需要关心调用了 Context 的pipeline
小结
- Host 中有部署的功能,部署先跳过,这里关心对子容器 Context 的操作