SpringMVC处理请求(二):DispatcherServlet

DispatcherServlet里面执行处理的入口方法应该是doService,不过doService并没有直接处理,而是交给doDispatch进行具体的处理

doService主要是对request设置了一些属性,如果是include请求还会对request当前的属性做快照备份,并在处理结束后恢复,最后将请求转发给doDispatch方法.

package org.springframework.web.servlet.DispatcherServlet;

   /**
    * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
    * for the actual dispatching.
    */
   @Override
   protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
   	if (logger.isDebugEnabled()) {
   		String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
   		logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
   				" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
   	}

   	// 当include请求时对request的attribute做快照备份
   	Map<String, Object> 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));
   			}
   		}
   	}

   	// 对request设置一些属性
   	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) {
   			//inputFlashMap用于保存上次请求中转发过来的属性
   			request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
   		}
   		//outputFlashMap用于保存本次请求需要转发的属性
   		request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
   		//FlashMapManager用于管理他们
   		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) {
   				// 还原request快照的属性
   				restoreAttributesAfterInclude(request, attributesSnapshot);
   			}
   		}
   	}
   }
doDispatch核心代码:

//根据request找到Handler
mappedHandler = getHandler(processedRequest);

//根据Handler找到对应的HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

//用HandlerAdapter处理handler
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

//调用processDispatchResult方法处理上面处理之后的结果(包含找到view并渲染输出给用户)
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);  
    /**
    * Process the actual dispatching to the handler.
    */
   protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   	//实际处理时所用的request,如果不是上传请求则直接使用接收到的request,否则封装为上传类型的request
   	HttpServletRequest processedRequest = request;
   	//处理请求的处理器链(包含处理器和对应的拦截器)
   	HandlerExecutionChain mappedHandler = null;
   	//是不是 上传请求 的标志
   	boolean multipartRequestParsed = false;

   	WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

   	try {
   		//封装Model和View的容器
   		ModelAndView mv = null;
   		//处理请求过程中抛出的异常,它并不包含渲染过程抛出的异常
   		Exception dispatchException = null;

   		try {
   			//检查是不是上传请求,如果是上传请求,则将request转换为MultipartHttpServletRequest
   			processedRequest = checkMultipart(request);
   			//如果是上传请求,将multipartRequestParsed标志设为true
   			multipartRequestParsed = (processedRequest != request);

   			//根据request找到Handler处理器链
   			mappedHandler = getHandler(processedRequest);
   			if (mappedHandler == null) {
   				noHandlerFound(processedRequest, response);
   				return;
   			}

   			//根据Handler找到对应的HandlerAdapter
   			HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

   			// 处理GET,HEAD请求的last-modified
   			String method = request.getMethod();
   			boolean isGet = "GET".equals(method);
   			if (isGet || "HEAD".equals(method)) {
   				long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
   				if (logger.isDebugEnabled()) {
   					logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
   				}
   				if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
   					return;
   				}
   			}

   			//执行相应的Interceptor的preHandle
   			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
   				return;
   			}

   			//用HandlerAdapter处理handler,Controller就是在这个地方执行的
   			mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
   			
   			//如果需要异步处理,直接返回
   			if (asyncManager.isConcurrentHandlingStarted()) {
   				return;
   			}

   			//当view为空时,根据request设置默认的view
   			applyDefaultViewName(processedRequest, mv);
   			//执行相应Interceptor的postHandle
   			mappedHandler.applyPostHandle(processedRequest, response, mv);
   		}
   		catch (Exception ex) {
   			dispatchException = ex;
   		}
   		catch (Throwable err) {
   			dispatchException = new NestedServletException("Handler dispatch failed", err);
   		}
   		//处理返回结果.包括处理异常,渲染页面,发出完成通知触发Interceptor的afterCompletion
   		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()) {
   			if (mappedHandler != null) {
   				mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
   			}
   		}
   		else {
   			// 删除上传请求过程中产生的临时资源
   			if (multipartRequestParsed) {
   				cleanupMultipart(processedRequest);
   			}
   		}
   	}
   }
/**
    * Handle the result of handler selection and handler invocation, which is
    * either a ModelAndView or an Exception to be resolved to a ModelAndView.
    */
   private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
   		@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
   		@Nullable Exception exception) throws Exception {

   	boolean errorView = false;

   	//如果请求处理过程中有异常抛出则处理异常
   	if (exception != null) {
   		if (exception instanceof ModelAndViewDefiningException) {
   			logger.debug("ModelAndViewDefiningException encountered", exception);
   			mv = ((ModelAndViewDefiningException) exception).getModelAndView();
   		}
   		else {
   			Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
   			mv = processHandlerException(request, response, handler, exception);
   			errorView = (mv != null);
   		}
   	}

   	// 渲染页面
   	if (mv != null && !mv.wasCleared()) {
   		//渲染页面具体方法
   		render(mv, request, response);
   		if (errorView) {
   			WebUtils.clearErrorRequestAttributes(request);
   		}
   	}
   	else {
   		if (logger.isDebugEnabled()) {
   			logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
   					"': assuming HandlerAdapter completed request handling");
   		}
   	}

   	if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
   		// 如果启动了异步处理则返回
   		return;
   	}

   	//发出请求处理完成的通知,触发Interceptor的afterCompletion
   	if (mappedHandler != null) {
   		mappedHandler.triggerAfterCompletion(request, response, null);
   	}
   }
/**
    * Render the given ModelAndView.
    * <p>This is the last stage in handling a request. It may involve resolving the view by name.
    * @param mv the ModelAndView to render
    * @param request current HTTP servlet request
    * @param response current HTTP servlet response
    * @throws ServletException if view is missing or cannot be resolved
    * @throws Exception if there's a problem rendering the view
    */
   protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
   	// Determine locale for request and apply it to the response.
   	Locale locale =
   			(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
   	//对response设置了locale
   	response.setLocale(locale);

   	View view;
   	String viewName = mv.getViewName();
   	if (viewName != null) {
   		// We need to resolve the view name.
   		view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
   		if (view == null) {
   			throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
   					"' in servlet with name '" + getServletName() + "'");
   		}
   	}
   	else {
   		// No need to lookup: the ModelAndView object contains the actual View object.
   		view = mv.getView();
   		if (view == null) {
   			throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
   					"View object in servlet with name '" + getServletName() + "'");
   		}
   	}

   	// Delegate to the View object for rendering.
   	if (logger.isDebugEnabled()) {
   		logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
   	}
   	try {
   		if (mv.getStatus() != null) {
   			response.setStatus(mv.getStatus().value());
   		}
   		view.render(mv.getModelInternal(), request, response);
   	}
   	catch (Exception ex) {
   		if (logger.isDebugEnabled()) {
   			logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
   					getServletName() + "'", ex);
   		}
   		throw ex;
   	}
   }

doDispatch方法处理流程图:
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值