StandardWrapper的继承关系:
从StandardWrapper的继承关系,我们根据之前的经验也可以推到出接收请求的过程了:
1, 调用了ContainerBase中的Invoke方法
2, 进而调用了实现valve接口的StandardWrapperValve的invoke方法
publicvoid invoke(Request request, Response response,
ValveContextvalveContext)
throws IOException, ServletException {
// Initialize local variables we mayneed
boolean unavailable = false;
Throwable throwable = null;
StandardWrapper wrapper =(StandardWrapper) getContainer();
ServletRequest sreq =request.getRequest();
ServletResponse sres =response.getResponse();
Servlet servlet = null;
HttpServletRequest hreq = null;
if (sreq instanceof HttpServletRequest)
hreq = (HttpServletRequest) sreq;
HttpServletResponse hres = null;
if (sres instanceofHttpServletResponse)
hres = (HttpServletResponse) sres;
// Check for the application beingmarked unavailable
if (!((Context)wrapper.getParent()).getAvailable()) {
hres.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardContext.isUnavailable"));
unavailable = true;
}
// Check for the servlet being markedunavailable
if (!unavailable &&wrapper.isUnavailable()) {
log(sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
if (hres == null) {
; // NOTE - Not much we can do generically
} else {
long available =wrapper.getAvailable();
if ((available > 0L)&& (available < Long.MAX_VALUE))
hres.setDateHeader("Retry-After", available);
hres.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
}
unavailable = true;
}
// Allocate a servlet instance toprocess this request
try {
if (!unavailable) {
servlet = wrapper.allocate();
}
} catch (ServletException e) {
log(sm.getString("standardWrapper.allocateException",
wrapper.getName()), e);
throwable = e;
exception(request, response, e);
servlet = null;
} catch (Throwable e) {
log(sm.getString("standardWrapper.allocateException",
wrapper.getName()), e);
throwable = e;
exception(request, response, e);
servlet = null;
}
// Acknowlege the request
try {
response.sendAcknowledgement();
} catch (IOException e) {
sreq.removeAttribute(Globals.JSP_FILE_ATTR);
log(sm.getString("standardWrapper.acknowledgeException",
wrapper.getName()), e);
throwable = e;
exception(request, response, e);
} catch (Throwable e) {
log(sm.getString("standardWrapper.acknowledgeException",
wrapper.getName()), e);
throwable = e;
exception(request, response, e);
servlet = null;
}
// Create the filter chain for thisrequest
ApplicationFilterChain filterChain =
createFilterChain(request,servlet);
// Call the filter chain for thisrequest
// NOTE: This also calls the servlet'sservice() method
try {
String jspFile =wrapper.getJspFile();
if (jspFile != null)
sreq.setAttribute(Globals.JSP_FILE_ATTR, jspFile);
else
sreq.removeAttribute(Globals.JSP_FILE_ATTR);
if ((servlet != null) &&(filterChain != null)) {
filterChain.doFilter(sreq,sres);
}
sreq.removeAttribute(Globals.JSP_FILE_ATTR);
} catch (IOException e) {
sreq.removeAttribute(Globals.JSP_FILE_ATTR);
log(sm.getString("standardWrapper.serviceException",
wrapper.getName()), e);
throwable = e;
exception(request, response, e);
} catch (UnavailableException e) {
sreq.removeAttribute(Globals.JSP_FILE_ATTR);
log(sm.getString("standardWrapper.serviceException",
wrapper.getName()), e);
// throwable = e;
// exception(request, response, e);
wrapper.unavailable(e);
long available =wrapper.getAvailable();
if ((available > 0L) &&(available < Long.MAX_VALUE))
hres.setDateHeader("Retry-After", available);
hres.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
// Do not save exception in'throwable', because we
// do not want to do exception(request,response, e) processing
} catch (ServletException e) {
sreq.removeAttribute(Globals.JSP_FILE_ATTR);
log(sm.getString("standardWrapper.serviceException",
wrapper.getName()), e);
throwable = e;
exception(request, response, e);
} catch (Throwable e) {
sreq.removeAttribute(Globals.JSP_FILE_ATTR);
log(sm.getString("standardWrapper.serviceException",
wrapper.getName()),e);
throwable = e;
exception(request, response, e);
}
// Release the filter chain (if any)for this request
try {
if (filterChain != null)
filterChain.release();
} catch (Throwable e) {
log(sm.getString("standardWrapper.releaseFilters",
wrapper.getName()), e);
if (throwable == null) {
throwable = e;
exception(request, response, e);
}
}
// Deallocate the allocated servletinstance
try {
if (servlet != null) {
wrapper.deallocate(servlet);
}
} catch (Throwable e) {
log(sm.getString("standardWrapper.deallocateException",
wrapper.getName()), e);
if (throwable == null) {
throwable = e;
exception(request, response,e);
}
}
// If this servlet has been markedpermanently unavailable,
// unload it and release this instance
try {
if ((servlet != null) &&
(wrapper.getAvailable() ==Long.MAX_VALUE)) {
wrapper.unload();
}
} catch (Throwable e) {
log(sm.getString("standardWrapper.unloadException",
wrapper.getName()), e);
if (throwable == null) {
throwable = e;
exception(request, response,e);
}
}
}
这个方法比较长,但是目前我们只需要抓住如下2点即可:
1) servlet = wrapper.allocate()
2) ApplicationFilterChain filterChain = createFilterChain(request,servlet);
3) filterChain.doFilter(sreq, sres);
我们根据这3点进一步分析:
第一, 我们从StandardWrapperValve的invoke方法可以早wrapper.allocate(),其实调用的就是standardWrapper中的allocate()
publicServlet allocate() throws ServletException {
if (debug >= 1)
log("Allocating aninstance");
// If we are currently unloading thisservlet, throw an exception
if (unloading)
throw new ServletException
(sm.getString("standardWrapper.unloading", getName()));
// If not SingleThreadedModel, returnthe same instance every time
if (!singleThreadModel) {
// Load and initialize our instanceif necessary
if (instance == null) {
synchronized (this) {
if (instance == null) {
try {
instance =loadServlet();
} catch(ServletException e) {
throw e;
} catch (Throwable e) {
throw newServletException
(sm.getString("standardWrapper.allocate"), e);
}
}
}
}
if (!singleThreadModel) {
if (debug >= 2)
log(" Returning non-STM instance");
countAllocated++;
return (instance);
}
}
synchronized (instancePool) {
while (countAllocated >=nInstances) {
// Allocate a new instance if possible, orelse wait
if (nInstances <maxInstances) {
try {
instancePool.push(loadServlet());
nInstances++;
} catch (ServletExceptione) {
throw e;
} catch (Throwable e) {
throw newServletException
(sm.getString("standardWrapper.allocate"), e);
}
} else {
try {
instancePool.wait();
} catch(InterruptedException e) {
;
}
}
}
if (debug >= 2)
log(" Returning allocated STM instance");
countAllocated++;
return (Servlet)instancePool.pop();
}
}
在这个方法里边,其实调用的就是loadServlet(),我们深入这个放放风的源码可以知道,其实这里就加载了一个servlet类到内存,并进行实例化,同时触发了一些事件方法,同时执行了servlet的init()方法
第二, createFilterChain,这个方法其实就是根据配置文件里边的一些filter的配置,进行过滤链的配置
第三, filterChain.doFilter(sreq,sres),执行过滤方法,我们到ApplicationFilterChain类中查看doFilter方法的时候,发现它又通过线程的方式,将请求对象request和response传递给了internalDoFilter()方法中,在这个方法里边,循环执行了配置的filter,然后再执行servlet的service()方法
根据上述的分析,我们目前的主线流程就完成了!一个前端发起的请求,由tomcat接收的流程就完成了!!其他细节有待我们根据之前分析的主线,再深入分析了解即可。
StandardWrapper请求流程图:
StandardWrapper的请求关系类图: