Tomcat要求処理(五)--容器間の流れを要求する
要求がTomcatでCoyoteAdapterのサービス()メソッドに転送されると、#サービス()メソッドの文に示すように、Pipelineに入る準備ができます.
connector.getContainer().getPipeline().getFirst().invoke(request, response);
ここのContainerはEngineで、それからそのPipelineオブジェクトを得て、それから彼の最初のValveを得て、もし配置がなければ最初のValveはBasicで、ここはorgです.apache.catalina.core.StandardEngineValveは、最後にその#invoke()メソッドを呼び出し、ソースコードは以下のようになります.
このValveは実質的なものではなく、要求を伝え続けるだけで、もちろん自分のValveを定義して特殊な行為を実現することができます.
やはりリクエストの処理を継続するには、上のEngineの場合と同様に、リクエストは今回org.apache.catalina.core.StandardHostValveの#invoke()メソッドです.ソースコードは次のとおりです.
意外なことに、お願いして下に着いたorg.apache.catalina.core.StandardContextValve、ソースコードは次のとおりです.
このValveにはListenerの呼び出しが含まれていることが重要で、最後にWrapperのValve呼び出し(org.apache.catalina.core.StandardWrapperValve)を見てみましょう.
このコードのキーは、サーブレットインスタンスの構築(servlet=wrapper.allocate();Filter Chainの呼び出し(filterChain.doFilter(request.getRequest()、response.getResponse());),具体的には方法の内部に入ってよく見てみましょう.comet方式は後で詳しく見ます.
connector.getContainer().getPipeline().getFirst().invoke(request, response);
ここのContainerはEngineで、それからそのPipelineオブジェクトを得て、それから彼の最初のValveを得て、もし配置がなければ最初のValveはBasicで、ここはorgです.apache.catalina.core.StandardEngineValveは、最後にその#invoke()メソッドを呼び出し、ソースコードは以下のようになります.
public final void invoke(Request request, Response response) throws IOException,
ServletException {
// Host
Host host = request.getHost();
if (host == null) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, sm.getString(
"standardEngine.noHost", request.getServerName()));
return;
}
// Host
host.getPipeline().getFirst().invoke(request, response);
}
このValveは実質的なものではなく、要求を伝え続けるだけで、もちろん自分のValveを定義して特殊な行為を実現することができます.
やはりリクエストの処理を継続するには、上のEngineの場合と同様に、リクエストは今回org.apache.catalina.core.StandardHostValveの#invoke()メソッドです.ソースコードは次のとおりです.
public final void invoke(Request request, Response response) throws IOException,
ServletException {
// Context
Context context = request.getContext();
if (context == null) {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, sm
.getString("standardHost.noContext"));
return;
}
// Loader, context ClassLoader
if (context.getLoader() != null) {
Thread.currentThread().setContextClassLoader(context.getLoader().getClassLoader());
}
// Pipeline Context
context.getPipeline().getFirst().invoke(request, response);
if (Globals.STRICT_SERVLET_COMPLIANCE) {
request.getSession(false);
}
//
response.setSuspended(false);
Throwable t = (Throwable) request.getAttribute(Globals.EXCEPTION_ATTR);
if (t != null) {
throwable(request, response, t);
} else {
status(request, response);
}
// ClassLoader
Thread.currentThread().setContextClassLoader(StandardHostValve.class.getClassLoader());
}
意外なことに、お願いして下に着いたorg.apache.catalina.core.StandardContextValve、ソースコードは次のとおりです.
public final void invoke(Request request, Response response) throws IOException,
ServletException {
// META-INF WEB-INF 。
MessageBytes requestPathMB = request.getRequestPathMB();
if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0))
|| (requestPathMB.equalsIgnoreCase("/META-INF"))
|| (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0))
|| (requestPathMB.equalsIgnoreCase("/WEB-INF"))) {
notFound(response);
return;
}
// , 。
boolean reloaded = false;
while (context.getPaused()) {
reloaded = true;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
;
}
}
// , WebappClassLoader
if (reloaded && context.getLoader() != null && context.getLoader().getClassLoader() != null) {
Thread.currentThread().setContextClassLoader(context.getLoader().getClassLoader());
}
// Wrapper
Wrapper wrapper = request.getWrapper();
if (wrapper == null) {
notFound(response);
return;
} else if (wrapper.isUnavailable()) {
wrapper = (Wrapper) container.findChild(wrapper.getName());
if (wrapper == null) {
notFound(response);
return;
}
}
// Listener
Object instances[] = context.getApplicationEventListeners();
ServletRequestEvent event = null;
if ((instances != null) && (instances.length > 0)) {
event = new ServletRequestEvent(((StandardContext) container).getServletContext(),
request.getRequest());
for (int i = 0; i < instances.length; i++) {
if (instances[i] == null)
continue;
if (!(instances[i] instanceof ServletRequestListener))
continue;
ServletRequestListener listener = (ServletRequestListener) instances[i];
try {
//
listener.requestInitialized(event);
} catch (Throwable t) {
container.getLogger().error(
sm.getString("standardContext.requestListener.requestInit",
instances[i].getClass().getName()), t);
ServletRequest sreq = request.getRequest();
sreq.setAttribute(Globals.EXCEPTION_ATTR, t);
return;
}
}
}
// Wrapper Valve
wrapper.getPipeline().getFirst().invoke(request, response);
if ((instances != null) && (instances.length > 0)) {
for (int i = 0; i < instances.length; i++) {
if (instances[i] == null)
continue;
if (!(instances[i] instanceof ServletRequestListener))
continue;
ServletRequestListener listener = (ServletRequestListener) instances[i];
try {
//
listener.requestDestroyed(event);
} catch (Throwable t) {
container.getLogger().error(
sm.getString("standardContext.requestListener.requestDestroy",
instances[i].getClass().getName()), t);
ServletRequest sreq = request.getRequest();
sreq.setAttribute(Globals.EXCEPTION_ATTR, t);
}
}
}
}
このValveにはListenerの呼び出しが含まれていることが重要で、最後にWrapperのValve呼び出し(org.apache.catalina.core.StandardWrapperValve)を見てみましょう.
public final void invoke(Request request, Response response) throws IOException,
ServletException {
boolean unavailable = false;
Throwable throwable = null;
long t1 = System.currentTimeMillis();
requestCount++;
// Wrapper
StandardWrapper wrapper = (StandardWrapper) getContainer();
// Servlet
Servlet servlet = null;
// Context
Context context = (Context) wrapper.getParent();
if (!context.getAvailable()) {
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm
.getString("standardContext.isUnavailable"));
unavailable = true;
}
if (!unavailable && wrapper.isUnavailable()) {
container.getLogger().info(
sm.getString("standardWrapper.isUnavailable", wrapper.getName()));
long available = wrapper.getAvailable();
if ((available > 0L) && (available < Long.MAX_VALUE)) {
response.setDateHeader("Retry-After", available);
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm.getString(
"standardWrapper.isUnavailable", wrapper.getName()));
} else if (available == Long.MAX_VALUE) {
response.sendError(HttpServletResponse.SC_NOT_FOUND, sm.getString(
"standardWrapper.notFound", wrapper.getName()));
}
unavailable = true;
}
try {
if (!unavailable) {
// Servelt
servlet = wrapper.allocate();
}
} catch (UnavailableException e) {
container.getLogger().error(
sm.getString("standardWrapper.allocateException", wrapper.getName()), e);
long available = wrapper.getAvailable();
if ((available > 0L) && (available < Long.MAX_VALUE)) {
response.setDateHeader("Retry-After", available);
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm.getString(
"standardWrapper.isUnavailable", wrapper.getName()));
} else if (available == Long.MAX_VALUE) {
response.sendError(HttpServletResponse.SC_NOT_FOUND, sm.getString(
"standardWrapper.notFound", wrapper.getName()));
}
} catch (ServletException e) {
container.getLogger().error(
sm.getString("standardWrapper.allocateException", wrapper.getName()),
StandardWrapper.getRootCause(e));
throwable = e;
exception(request, response, e);
servlet = null;
} catch (Throwable e) {
container.getLogger().error(
sm.getString("standardWrapper.allocateException", wrapper.getName()), e);
throwable = e;
exception(request, response, e);
servlet = null;
}
boolean comet = false;
if (servlet instanceof CometProcessor
&& request.getAttribute("org.apache.tomcat.comet.support") == Boolean.TRUE) {
comet = true;
request.setComet(true);
}
// Request
try {
response.sendAcknowledgement();
} catch (IOException e) {
request.removeAttribute(Globals.JSP_FILE_ATTR);
container.getLogger().warn(
sm.getString("standardWrapper.acknowledgeException", wrapper.getName()), e);
throwable = e;
exception(request, response, e);
} catch (Throwable e) {
container.getLogger().error(
sm.getString("standardWrapper.acknowledgeException", wrapper.getName()), e);
throwable = e;
exception(request, response, e);
servlet = null;
}
MessageBytes requestPathMB = null;
if (request != null) {
requestPathMB = request.getRequestPathMB();
}
request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
ApplicationFilterFactory.REQUEST_INTEGER);
request.setAttribute(ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, requestPathMB);
// FilterChain
ApplicationFilterFactory factory = ApplicationFilterFactory.getInstance();
ApplicationFilterChain filterChain = factory.createFilterChain(request, wrapper, servlet);
request.setComet(false);
try {
// web.xml <jsp-file>
String jspFile = wrapper.getJspFile();
if (jspFile != null)
request.setAttribute(Globals.JSP_FILE_ATTR, jspFile);
else
request.removeAttribute(Globals.JSP_FILE_ATTR);
// Filter
if ((servlet != null) && (filterChain != null)) {
if (context.getSwallowOutput()) {
try {
SystemLogHandler.startCapture();
if (comet) {
filterChain.doFilterEvent(request.getEvent());
request.setComet(true);
} else {
filterChain.doFilter(request.getRequest(), response.getResponse());
}
} finally {
String log = SystemLogHandler.stopCapture();
if (log != null && log.length() > 0) {
context.getLogger().info(log);
}
}
} else {
if (comet) {
request.setComet(true);
filterChain.doFilterEvent(request.getEvent());
} else {
filterChain.doFilter(request.getRequest(), response.getResponse());
}
}
}
request.removeAttribute(Globals.JSP_FILE_ATTR);
} catch (ClientAbortException e) {
request.removeAttribute(Globals.JSP_FILE_ATTR);
throwable = e;
exception(request, response, e);
} catch (IOException e) {
request.removeAttribute(Globals.JSP_FILE_ATTR);
container.getLogger().error(
sm.getString("standardWrapper.serviceException", wrapper.getName()), e);
throwable = e;
exception(request, response, e);
} catch (UnavailableException e) {
request.removeAttribute(Globals.JSP_FILE_ATTR);
container.getLogger().error(
sm.getString("standardWrapper.serviceException", wrapper.getName()), e);
wrapper.unavailable(e);
long available = wrapper.getAvailable();
if ((available > 0L) && (available < Long.MAX_VALUE)) {
response.setDateHeader("Retry-After", available);
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm.getString(
"standardWrapper.isUnavailable", wrapper.getName()));
} else if (available == Long.MAX_VALUE) {
response.sendError(HttpServletResponse.SC_NOT_FOUND, sm.getString(
"standardWrapper.notFound", wrapper.getName()));
}
} catch (ServletException e) {
request.removeAttribute(Globals.JSP_FILE_ATTR);
Throwable rootCause = StandardWrapper.getRootCause(e);
if (!(rootCause instanceof ClientAbortException)) {
container.getLogger().error(
sm.getString("standardWrapper.serviceException", wrapper.getName()),
rootCause);
}
throwable = e;
exception(request, response, e);
} catch (Throwable e) {
request.removeAttribute(Globals.JSP_FILE_ATTR);
container.getLogger().error(
sm.getString("standardWrapper.serviceException", wrapper.getName()), e);
throwable = e;
exception(request, response, e);
}
if (filterChain != null) {
if (request.isComet()) {
filterChain.reuse();
} else {
filterChain.release();
}
}
// Servlet
try {
if (servlet != null) {
wrapper.deallocate(servlet);
}
} catch (Throwable e) {
container.getLogger().error(
sm.getString("standardWrapper.deallocateException", wrapper.getName()), e);
if (throwable == null) {
throwable = e;
exception(request, response, e);
}
}
try {
if ((servlet != null) && (wrapper.getAvailable() == Long.MAX_VALUE)) {
wrapper.unload();
}
} catch (Throwable e) {
container.getLogger().error(
sm.getString("standardWrapper.unloadException", wrapper.getName()), e);
if (throwable == null) {
throwable = e;
exception(request, response, e);
}
}
long t2 = System.currentTimeMillis();
long time = t2 - t1;
processingTime += time;
if (time > maxTime)
maxTime = time;
if (time < minTime)
minTime = time;
}
このコードのキーは、サーブレットインスタンスの構築(servlet=wrapper.allocate();Filter Chainの呼び出し(filterChain.doFilter(request.getRequest()、response.getResponse());),具体的には方法の内部に入ってよく見てみましょう.comet方式は後で詳しく見ます.