2013-11-10java
StandardWrapperValve是StandardWrapper容器的BasicValve,tomcat使用容器的BasicValve來控制處理請求,StandardWrapperValve的做用是負責爲請求選擇Wrapper,調用Servlet處理請求,控制請求處理流程。寄生於StandardWrapper中,StandardWrapperValve做爲BasicValve是如何完成便可功能的呢。tomcat
StandardWrapperValve在方法invoke(Request, Response)中完成便可功能,在StandardCOntextValve的invoke(Request, Response)方法中調用。invoke(Request, Response)中作了不少邏輯操做,方法被標記爲final,不容許更改方法。app
invoke(Request, Response)
負責選擇Wrapper過濾Filter,調用servlet處理請求,在方法中有不少邏輯操做,詳細以下:less
/** * Process a Comet event. The main differences here are to not use sendError * (the response is committed), to avoid creating a new filter chain (which * would work but be pointless), and a few very minor tweaks. * * @param request * The servlet request to be processed * @param response * The servlet response to be created * * @exception IOException * if an input/output error occurs, or is thrown by a * subsequently invoked Valve, Filter, or Servlet * @exception ServletException * if a servlet error occurs, or is thrown by a subsequently * invoked Valve, Filter, or Servlet */ public void event(Request request, Response response, CometEvent event) throws IOException, ServletException { // Initialize local variables we may need Throwable throwable = null; // This should be a Request attribute... long t1 = System.currentTimeMillis(); // FIXME: Add a flag to count the total amount of events processed ? // requestCount++; StandardWrapper wrapper = (StandardWrapper) getContainer(); Servlet servlet = null; Context context = (Context) wrapper.getParent(); // Check for the application being marked unavailable boolean unavailable = !context.getAvailable() || wrapper.isUnavailable(); // Allocate a servlet instance to process this request try { if (!unavailable) { servlet = wrapper.allocate(); } } catch (UnavailableException e) { // The response is already committed, so it's not possible to do // anything } 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; } 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); // Get the current (unchanged) filter chain for this request ApplicationFilterChain filterChain = (ApplicationFilterChain) request .getFilterChain(); // Call the filter chain for this request // NOTE: This also calls the servlet's event() method try { String jspFile = wrapper.getJspFile(); if (jspFile != null) request.setAttribute(Globals.JSP_FILE_ATTR, jspFile); else request.removeAttribute(Globals.JSP_FILE_ATTR); if ((servlet != null) && (filterChain != null)) { // Swallow output if needed if (context.getSwallowOutput()) { try { SystemLogHandler.startCapture(); filterChain.doFilterEvent(request.getEvent()); } finally { String log = SystemLogHandler.stopCapture(); if (log != null && log.length() > 0) { context.getLogger().info(log); } } } else { filterChain.doFilterEvent(request.getEvent()); } } 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); // Do not save exception in 'throwable', because we // do not want to do exception(request, response, e) processing } 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); } // Release the filter chain (if any) for this request if (filterChain != null) { filterChain.reuse(); } // Deallocate the allocated servlet instance 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); } } // If this servlet has been marked permanently unavailable, // unload it and release this instance 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; }
以上是invoke(Request,Response)方法的源碼,代碼中發現有不少的異常處理邏輯,針對不一樣的異常處理邏輯,響應給請求的內容頁不同。從上面能夠看出invoke方法控制了請求的傳遞過程,在方法並無直接調用servlet的方法,而是將調用servlet中的方法放到FilterChain中。jsp
再堅持this