Spring 깊이 분석 - 20, DispatcherServlet 요청 처리 방법

어제 Dispatcher Servlet 초기 화 과정 을 설 명 했 습 니 다. Dispatcher Servlet 은 HttpServlet 에서 계승 되 었 기 때문에 초기 화 할 때 HttpServlet 의 init 방법 으로 시 작 했 습 니 다. 전체 과정 은 대체적으로 ServletContext 의 설정 파 라미 터 를 읽 고 컨 텍스트 를 초기 화 하 며 Spring mvc 에 필요 한 대상 을 초기 화 합 니 다. 예 를 들 어 Handler Mapping 등 입 니 다.Dispatcher Servlet 은 HttpServlet 에서 계승 되 기 때문에 Dispatcher Servlet 을 통 해 HttpServlet 의 API 로 호출 할 수 있 습 니 다. HttpServlet 의 초기 화 를 제외 하고 Dispatcher Servlet 는 요청 을 처리 할 수 있 습 니 다. doGet 과 doPost 방법 부터 전단 의 get 요청 을 받 을 때 doGet 방법 을 사용 하고 전단 의 post 요청 을 받 을 때 doPost 방법 을 사용 합 니 다.이 두 가지 방법 은 모두 Dispatcher Servlet 의 부모 클래스 Framework Servlet 에서 재 작성 되 었 으 며, processRequest 로 호출 되 었 으 며, processRequest 에서 doService 로 호출 되 었 습 니 다.
	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
		logRequest(request);

		// Keep a snapshot of the request attributes in case of an include,
		// to be able to restore the original attributes after the include.
		Map attributesSnapshot = null;
		if (WebUtils.isIncludeRequest(request)) {
			attributesSnapshot = new HashMap<>();
			Enumeration> attrNames = request.getAttributeNames();
			while (attrNames.hasMoreElements()) {
				String attrName = (String) attrNames.nextElement();
				if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
					attributesSnapshot.put(attrName, request.getAttribute(attrName));
				}
			}
		}

		// Make framework objects available to handlers and view objects.
		request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
		request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
		request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
		request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

		if (this.flashMapManager != null) {
			FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
			if (inputFlashMap != null) {
				request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
			}
			request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
			request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
		}

		try {
			doDispatch(request, response);
		}
		finally {
			if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
				// Restore the original attribute snapshot, in case of an include.
				if (attributesSnapshot != null) {
					restoreAttributesAfterInclude(request, attributesSnapshot);
				}
			}
		}
	}

doService 에 서 는 요청 에 속성 을 설정 한 다음 에 구체 적 인 요청 처 리 를 doDispatch 에 맡 깁 니 다.
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

				// Determine handler for the current request.
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				applyDefaultViewName(processedRequest, mv);
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				// As of 4.3, we're processing Errors thrown from handler methods as well,
				// making them available for @ExceptionHandler methods and other scenarios.
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new NestedServletException("Handler processing failed", err));
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// Clean up any resources used by a multipart request.
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

doDispatch 에서 주요 한 작업 은 요청 에 따라 구체 적 인 HandlerExecutionChain 을 가 져 오 는 것 입 니 다. HandlerExecutionChain 은 일련의 차단기 와 구체 적 인 Controller 를 포함 합 니 다.
먼저 차단기 사전 처 리 를 하고 false 로 돌아 가면 내 려 가지 않 고 return 으로 요청 한 데이터 문 제 를 검사 합 니 다.
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

그리고 구체 적 인 controller 를 호출 하여 Model AndView 를 가 져 옵 니 다.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

마지막 으로 차단 기 를 호출 한 후 로 그 를 작성 하여 다른 작업 을 가 져 올 수 있 습 니 다.
mappedHandler.applyPostHandle(processedRequest, response, mv);

좋은 웹페이지 즐겨찾기