StandardWrapperValve分析-tomcat6.x源碼閱讀

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

  • 驗證Wrapper和Context的可用性
  • 經過wrapper的allocate()方法來獲取servlet
  • 判斷是否爲Comet
  • 調用response.sendAcknowledgement();發送"HTTP/1.1 100 Continue" + CRLF + CRLF
  • 獲取在該Servlet上面註冊的全部Filter,組成FilterChain
  • 若是爲JSP,設置屬性
  • 在Servlet上面調用FilterChain過濾,在FilterChain鏈完成對Servlet方法的調用,處理請求
  • 重置FilterChain鏈
  • 調用wrapper.deallocate(servlet);歸還Wrapper
  • 判斷Servlet仍是否能夠用,若是不可用,調用wrapper.unload();卸載Servlet
/**
	 * 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

相關文章
相關標籤/搜索