springboot-spring源码系列(十二)-MVC

150 阅读11分钟

上篇文章分析了springMVC的初始化流程,本篇分析一下对request的处理

对于一个请求tomcat会先对他进行过滤(执行Filter),然后根据路径找到对应的servlet,然后在执行service()方法,至于为什么?Tomcat的知识在这就不多讲了

	/**
	 * 请求在被Servlet处理之前会先被过滤器处理
     * 过滤器并不是spring负责执行,tomcat负责找出过滤器并且执行 ,tomcat如过没找到过滤器则直接返回
     * 如果有,它会找到所有的过滤器,按照责任链的顺序依次执行,如果全部执行完了
	 * 会调用Servlet的service方法来对相应的请求进行处理响应,然后在传回给tomcat,执行别的流程
	 * 也就是说发送请求被tomcat拦截后,先执行过滤器,所有过滤器执行完毕后,会执行service方法
     * 该方法存在于DispatcherServlet的父类FrameworkServlet中
	 */
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//根据请求的方法类型转换对应的枚举类
        //GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE;
		HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
		if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
			processRequest(request, response);
		}
		else {
        	//如果不是PATCH类型就调用父类的service方法
			super.service(request, response);
		}
	}
 //这个方法不用多说了,根据请求的类型去执行FrameworkServlet中的方法,以Get请求举例子
 protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String method = req.getMethod();

        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < lastModified) {
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }
        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);

        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);
            
        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);
            
        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);
            
        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);
            
        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);
            
        } else {
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);            
            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }
   protected final void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
	   //service - > httpServlet -> doGet(doPost) -> processRequest
		processRequest(request, response);
	}
    
    
   //处理此请求,不管结果如何,都要发布事件。
   protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//记录请求处理的开始时间
		long startTime = System.currentTimeMillis();
		Throwable failureCause = null;
		//国际化
		LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
		LocaleContext localeContext = buildLocaleContext(request);
		//构建ServletRequestAttributes对象
		RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
		//异步管理
		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
		//初始化ContextHolders
		initContextHolders(request, localeContext, requestAttributes);
		try {
		    //执行doService完成请求处理的操作
			doService(request, response);
		}
		finally {
			//重新设置ContextHolders
			resetContextHolders(request, previousLocaleContext, previousAttributes);
		}
			//不管请求是否处理成功,都发布一个事件标识请求处理结束
			publishRequestHandledEvent(request, response, startTime, failureCause);
		}
	}
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
		//保留请求属性的快照,以防出现include,
		//能够在include之后恢复原始属性。
		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设置国际化解析器
		request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
		//给request设置主题解析器
		request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
		//给request设置主题
		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设置重定向解析器
			request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
		}
		try {
			//
			doDispatch(request, response);
		} finally {
        	//拿到该请求的异步管理器判断他是否是正在被处理
			if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
				//如果存在属性快照,还原原始属性快照
				if (attributesSnapshot != null) {
					restoreAttributesAfterInclude(request, attributesSnapshot);
				}
			}
		}
	}

接下来就到了springMVC的核心,仔细看,先上一个流程图

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		//用HttpServletRequest接收请求
		HttpServletRequest processedRequest = request;
        //创建一个映射处理器.此时为null
		HandlerExecutionChain mappedHandler = null;
        //定义一个标识,是否有文件上传
		boolean multipartRequestParsed = false;
		//根据请求拿到异步管理器
		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		try {
        	//创建模型视图解析器
			ModelAndView mv = null;
            //创建请求处理时发生的异常
			Exception dispatchException = null;
			try {
				//检查请求是否有文件上传操作
				processedRequest = checkMultipart(request);
	protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
		/**
		 * 先判断是否设置了文件上传解析器,初始化的时候设置的
		 * 在判断当前request请求是否是文件上传
         * 通过CommonsMultipartResolver.isMultipart()方法进行判断
         *    ServletFileUpload.isMultipartContent(request);
         * 		ServletFileUpload文件上传工具包
         *	    先判断一下是不是POST请求,如果不是POST请求直接返回false
         * 		如果请求是POST请求,并且请求头中的Context-Type是以multipart/开头的就认为是文件上传的请求
		 */
		if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
			/**
			 * 继续判断这个请求是不是已经被转换为MultipartHttpServletRequest类型了。
			 * 在Spring-Web这个jar中有一个过滤器org.springframework.web.multipart.support.MultipartFilter
			 * 如果在web.xml中配置这个过滤器的话,则会在过滤器中提前判断是不是文件上传的请求,
			 * 并将请求转换为MultipartHttpServletRequest类型。
			 */
			if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
				logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " +
						"this typically results from an additional MultipartFilter in web.xml");
			} else if (hasMultipartException(request)) {
				logger.debug("Multipart resolution failed for current request before - " +
						"skipping re-resolution for undisturbed error rendering");
			} else {
				try {
					//将请求转换为MultipartHttpServletRequest类型,然后返回
					return this.multipartResolver.resolveMultipart(request);
				} catch (MultipartException ex) {
					if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null) {
						logger.debug("Multipart resolution failed for error dispatch", ex);
						// Keep processing error dispatch with regular request handle below
					} else {
						throw ex;
					}
				}
			}
		}	
		//如果没有文件上传,返回原来的request
		return request;
	}
				/**
				 * 如果是文件上传操作,返回的就不是request本身
				 * 而是经过了封装的request
                 * 修改标识符
				 */
				multipartRequestParsed = (processedRequest != request);
				/**
				 * 去找Handler的类型,也就是当前请求的是哪种类型的controller
				 * 返回一个HandlerExecutionChain对象
				 * 该对象封装了handler和interceptors,包含了请求对应的Controller方法
				 */
				mappedHandler = getHandler(processedRequest);

Controller一共有三种类型

  • 1.实现了Controller接口
  • 2.实现了HttpRequestHandler接口
  • 3.类上面加一个@Controller注解
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		/**
		 * 拿到spring ioc中的所有实现controller和HttpRequestHandler接口的实现类
		 * Spring MVC默认加载两个handlerMapping  按顺序去找,只要找到一个就返回
		 * handlerMappings集合中有两个 1.RequestMappingHandlerMapping
		 * 							  2.BeanNameUrlHandlerMapping
         * springboot为什么能处理静态页面,就是因为他扩展了handlerMappings类,手动添加了一个映射  *.html对应/resource/*.html
		 */
		if (this.handlerMappings != null) {
			for (HandlerMapping hm : this.handlerMappings) {
				//进行判断是否是请求的当前类型的路径,如果是就执行然后返回结果,如果都不是就返回null
				HandlerExecutionChain handler = hm.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}
    
//继续跟进getHandler()方法
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		/**
		 * 获取handler,也就是Controller类和Method方法的对象
         * 拿到Controller类里面的所有方法,找到和url匹配的方法
         * 从urlLookup的Map中拿,至于为什么这里头会存在,简单说一下
         * 因为我们使用@Controller标识,而controller又是RequestMappingHandlerMapping,它实现了Aware接口的类
         * 所以会调用Aware的方法:invokeAwareMethods(),这里完成@requestingMapping上的value+@Controller上的value作为key,对应的mapping作为value
         * 再根据mapping从registy集合中拿到handler 
		 */
		Object handler = getHandlerInternal(request);
		// 如果没找到url对应的映射,则使用默认处理器
		if (handler == null) {
			handler = getDefaultHandler();
		}		
		 //没有默认处理器返回null
		if (handler == null) {
			return null;
		}
		// Bean名称还是解析处理程序
		if (handler instanceof String) {
			String handlerName = (String) handler;
			handler = obtainApplicationContext().getBean(handlerName);
		}
		// 包装为执行器链
		HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
		// 是不是跨域请求
		if (CorsUtils.isCorsRequest(request)) {
			CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
			CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
			CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
			executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
		}
        //返回执行器链
		return executionChain;
	}
				// 如果当前请求找不到对应的handler,返回404
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}
				/**
				 * 根据handler不同的类型寻找对应的适配器
				 *
				 * 遍历适配器
				 * 1.SimpleControllerHandlerAdapter 实现Controller接口的Handler
				 * 2.AbstractHandlerMethodAdapter  @RequestMapping注解
				 * 3.HttpRequestHandlerAdapter	  实现HttpRequestHandler接口的Handler
				 * 4.SimpleServletHandlerAdapter  适配Servlet实现类的
				 * 5.AnnotationMethodHandlerAdapter  xml方式
				 * 成功返回一个适配器用来处理 handler
				 */

				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
				//拿到request请求的头信息(即 POST/GET/.... )
				String method = request.getMethod();
				/**
				 * 如果是GET请求,并且请求信息没有发生改变,直接返回
				 * 处理 last-modified 请求头
				 */
				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;
					}
				}
				/**
				 * 调用执行器链中的拦截器,就是循环装配好的执行器链
				 * 重点是 PreHandle()方法 true代表放行 false代表拦截
				 */
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

什么是拦截器

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
		//从web容器中拿到所有拦截器
		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			//循环遍历所有拦截器
			for (int i = 0; i < interceptors.length; i++) {
				HandlerInterceptor interceptor = interceptors[i];
				/**
				 * 1.当preHandle方法返回false时,从当前拦截器往回执行所有拦截器的afterCompletion方法,
				 * 再退出拦截器链。也就是说,请求不继续往下传了,直接沿着来的链往回跑。
				 *
				 * 2.当preHandle方法全为true时,执行下一个拦截器,直到所有拦截器执行完。
				 * 再运行被拦截的Controller。然后进入拦截器链,运行所有拦截器的postHandle方法
				 * 完后从最后一个拦截器往回执行所有拦截器的afterCompletion方法.
				 */
				if (!interceptor.preHandle(request, response, this.handler)) {
					triggerAfterCompletion(request, response, null);
					return false;
				}
				this.interceptorIndex = i;
			}
		}
		return true;
	}
				/**
				 * 根据不同的适配器执行handle
				 * 也就是说该方法执行完毕后,业务逻辑方法就执行完毕了
				 * 接下来要做的就是,通过反射获取该方法上的注解和参数,解析方法和参数上的注解,
				 * 最后反射调用方法获取ModelAndView结果视图
				 * 信息封装到页面渲染展示给用户
				 *
				 * SpringMVC中提供两种request参数到方法中参数的绑定方式:
				 *   ① 通过注解进行绑定 @RequestParam
				 *   ② 通过参数名称进行绑定
				 *
				 * 使用注解进行绑定,我们只要在方法参数前面声明@RequestParam("a"),
				 * 因为声明了注解,所以spring能保存起来,既而能根据name从request中找
				 * 就可以将request中参数a的值绑定到方法的该参数上。
				 * 使用参数名称进行绑定的前提是必须要获取方法中参数的名称,
				 * Java反射只提供了获取方法的参数的类型,并没有提供获取参数名称的方法。
				 * 也就是说通过反射你只能拿到Class实例中方法的类别,比如说 setName(String name,int id)
				 * 你只能知道 setName(String ,int ) 也就是两个类型,这时候你不可能反射调用
				 * 因为你拿到了值不知道按什么顺序添加进参数中,
				 * SpringMVC解决这个问题的方法是用asm框架直接读取字节码文件(class文件而不是Class实例),
				 * 来获取方法的参数名称。
				 *
				 * 如果是JSON格式不进行渲染
				 */
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
	public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		return handleInternal(request, response, (HandlerMethod) handler);
	}
    
	protected ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
		/**
		 * ModelAndView中的Model代表模型,View代表视图,这个名字就很好地解释了该类的作用。
		 * 业务处理器调用模型层处理完用户请求后,
		 * 把结果数据存储在该类的model属性中,把要返回的视图信息存储在该类的view属性中
		 * 它既能返回视图(html页面),还能携带该html页面所需要的数据,
		 * 那我只要把html页面连同数据一起返回给前端,我们后端的工作就结束了
		 */
		ModelAndView mav;
		//检查是不是所支持的请求类型、是不是要求session
		checkRequest(request);
		/**
		 *  session中是不是要求同步执行
		 *  如果是同步执行,则上锁
		 *  反正不管是同步还是异步,重点都是 invokeHandlerMethod() 方法
		 */
		if (this.synchronizeOnSession) {
			HttpSession session = request.getSession(false);
			if (session != null) {
				Object mutex = WebUtils.getSessionMutex(session);
				synchronized (mutex) {
					// 如果需要同步,则在同步块中执行 invokeHandlerMethod
					mav = invokeHandlerMethod(request, response, handlerMethod);
				}
			}
			else {
				// 如果没有可用的 HttpSession 那么就没有必要使用 Session 互斥锁
				mav = invokeHandlerMethod(request, response, handlerMethod);
			}
		}
		else {
			// 如果根本不需要 Session 上的同步,那么直接调用 invokeHandlerMethod 方法
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}
		// 处理响应缓存
		if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
			if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
				applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
			}
			else {
				prepareResponse(response);
			}
		}
		return mav;
	}
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
		// 将请求信息和响应信息包装为 ServletWebRequest 实例对象
		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		try {
			WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
			ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
			// 创建可被调用的 ServletInvocableHandlerMethod 对象来包装原始的 HandlerMethod
			ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
			// 如果存在参数解析器则设置参数解析器
			if (this.argumentResolvers != null) {
				invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
			}
			// 如果存在返回值处理器则设置返回值处理器
			if (this.returnValueHandlers != null) {
				invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
			}
			invocableMethod.setDataBinderFactory(binderFactory);
			invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
			// 创建数据和视图容器并进行初始化工作
			ModelAndViewContainer mavContainer = new ModelAndViewContainer();
			mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
			modelFactory.initModel(webRequest, mavContainer, invocableMethod);
			mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
			// 使用异步请求处理方法扩展 NativeWebRequest
			AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
			asyncWebRequest.setTimeout(this.asyncRequestTimeout);
			// 创建用于管理异步请求处理的中央类 WebAsyncManager 并进行属性设置
			WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
			// 配置 AsyncTaskExecutor 用于 startCallableProcessing 方法的并发执行
			asyncManager.setTaskExecutor(this.taskExecutor);
			// 配置 AsyncWebRequest
			asyncManager.setAsyncWebRequest(asyncWebRequest);
			// 注册回调拦截器 CallableProcessingInterceptor
			asyncManager.registerCallableInterceptors(this.callableInterceptors);
			// 注册 DeferredResultProcessingInterceptor
			asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
			// 如果结果值作为并发处理的结果而存在
			if (asyncManager.hasConcurrentResult()) {
				// 获取并发处理的结果
				Object result = asyncManager.getConcurrentResult();
				// 获取并发处理开始时保存的其它处理上下文
				mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
				// 清除 asyncManager 中的 concurrentResult 和 concurrentResultContext
				asyncManager.clearConcurrentResult();
				if (logger.isDebugEnabled()) {
					logger.debug("Found concurrent result value [" + result + "]");
				}
				// 创建一个嵌套的 ServletInvocableHandlerMethod 子类 ConcurrentResultHandlerMethod
				invocableMethod = invocableMethod.wrapConcurrentResult(result);
			}
			//进行请求处理器方法调用,对返回结果进行处理
			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			// 调用结束后返回到这里
			if (asyncManager.isConcurrentHandlingStarted()) {
				return null;
			}
			 //获取数据和视图
			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally {
			webRequest.requestCompleted();
		}
	}
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
		/**
		 * 找到所有支持的参数类型
		 * 无论你在Header里、Cookie里、Body里、还是Path里,无论是什么类型的参数都能给你解析。
         * 获取方法上的参数值,如果有@RequestParam注解,则直接赋值
         * 如果没有使用asm技术,按照顺序进行赋值
		 * 反射执行方法并返回执行结果
		 */
		Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
		// 设置响应状态
		setResponseStatus(webRequest);
		 // 拿到返回的结果,进行判断
		if (returnValue == null) {
			if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
				mavContainer.setRequestHandled(true);
				return;
			}
		}
		else if (StringUtils.hasText(getResponseStatusReason())) {
			mavContainer.setRequestHandled(true);
			return;
		}
		mavContainer.setRequestHandled(false);
		Assert.state(this.returnValueHandlers != null, "No return value handlers");
		try {
			/**
			 * 当拿到返回的结果对象要进行处理,但是处理的方式有很多种 比如:转Json、跳到页面、重定向......
			 * spring是如何解决的,它使用了观察者设计模式
			 */
			this.returnValueHandlers.handleReturnValue(
					returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
		}
		catch (Exception ex) {
			if (logger.isTraceEnabled()) {
				logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
			}
			throw ex;
		}
	}
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
		// 拿到返回结果处理程序
		HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
		// 如果没有处理程序匹配,就报错!!!!!!!
		if (handler == null) {
			throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
		}
		//通过处理程序对返回结果进行处理
		handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
	}
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
		// 判断是否为异步返回值
		boolean isAsyncValue = isAsyncReturnValue(value, returnType);
		/**
		 * spring当中维护了一个map,专门用来存放,处理结果的所有处理程序,它们都是一个类
		 * 循环所有处理程序
		 */
		for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
			//如果它是异步返回值,那么只要处理器不是异步处理程序直接循环下一个
			if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
				continue;
			}
			/**
			 * 观察者模式体现的淋漓尽致。。。
			 *  spring会先对所有处理程序进行排序。
			 *  按照顺序执行所有处理程序的 supportsReturnType() 方法,只要有一个返回true
			 *  那么就认为找到了处理程序,把该处理器返回
			 *
			 *  最简单的情况即我们只返回了一个视图名称,此时返回 ViewNameMethodReturnValueHandler
 			 */
			if (handler.supportsReturnType(returnType)) {
				return handler;
			}
		}
		return null;
	}
  • 这些都是结果处理器
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
			ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
		// 将model中的属性列表添加到session的SessionAttributes中(级别提升)
		modelFactory.updateModel(webRequest, mavContainer);
		// 如果请求已经被处理了则直接返回
		if (mavContainer.isRequestHandled()) {
			return null;
		}
		// 从返回值容器中获取数据
		ModelMap model = mavContainer.getModel();
		// 将处理结果封装到 ModelAndView 对象中
		ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
		if (!mavContainer.isViewReference()) {
			/**
			 * isViewReference 直接判断 mavContainer 的 view 属性值是否为 String 类型
			 * 如果 mavContainer 保存的 view 是一个 View 对象而非 String 则将其直接保存到 ModelAndView 对象中
			 */
			mav.setView((View) mavContainer.getView());
		}
		// 重定向逻辑
		if (model instanceof RedirectAttributes) {
			Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
			HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
			if (request != null) {
				RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
			}
		}
		return mav;
	}
				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
				applyDefaultViewName(processedRequest, mv);
				// 调用拦截器的 postHandle 方法
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			} catch (Exception ex) {
				dispatchException = ex;
			} catch (Throwable err) {
				//从4.3开始,我们也在处理处理程序方法抛出的错误,
				//使它们可用于@ExceptionHandler方法和其他方案。
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
			/**
			 * 最后一步,页面返回给用户
			 * 如果出现异常,返回异常页面。如果没有异常,ModelAndView不为null,
			 * 则正常渲染页面,调用拦截器的afterCompletion方法
			 *
			 * 这一步完成后SpringMVC就基本上完成自己的使命了,当找到对应的url路径,
			 * springmvc就继续访问url对应的servlet,剩下的渲染工作就交由Servlet去处理了,
			 * 所以由此我们不难看出,springmvc实际是在tomcat和servlet中间加了一层,
			 * 处理request将浏览器传递的参数封装成model再由应用来加工处理这些数据后,
			 * 再将这些数据传递给servlet让servlet将这些经过应用处理的数据在页面上表现出来,从而完成web请求,
			 * 目的在于页面和数据分离即页面表现和业务逻辑的分离,
			 * 使开发中可以集中精力处理业务逻辑提高开发效率。
			 */
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
									   @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
									   @Nullable Exception exception) throws Exception {
		 //如果ModelAndView不为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");
			}
		}
		//调用处理拦截器的afterCompletion方法
		if (mappedHandler != null) {
			mappedHandler.triggerAfterCompletion(request, response, null);
		}
	}
    
    protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
		// 通过解析request的语言环境,并设置response的local
		Locale locale =
				(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
		response.setLocale(locale);
		View view;
		String viewName = mv.getViewName();
		if (viewName != null) {
            /**
             * 拿到需要的视图解析器
			 * 循环遍历所有视图解析器,默认只有一个
			 * springboot中扩展的解析器
			 * 		    1.Thymeleaf
			 *  		2.Freemaker
			 *  		3.JSP
			 * 		    4.Velocity
			 * 		    5.JSON
			 *  		6.XML
			 *  		7.其他
			 */
			view = resolveViewName(viewName, mv.getModelInternal(), locale, request);		
		try {
			//设置响应的状态码
			if (mv.getStatus() != null) {
				response.setStatus(mv.getStatus().value());
			}
			//开始渲染:调用具体的View对象,进行视图渲染
			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;
		}
	}

		} 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);
				}
			}
		}
	}
		/**
		 *  1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获;
		 *  2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;
		 *  3. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(...)方法)
		 *  4.  提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
		 *       HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
		 *       数据转换:对请求消息进行数据转换。如String转换成IntegerDouble等
		 *       数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
		 *       数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
		 *  5.  Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;
		 *  6.  根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet ;
		 *  7. ViewResolver 结合Model和View,来渲染视图
		 *  8. 将渲染结果返回给客户端
		 */

Spring MVC使用优化建议
上面我们已经对SpringMVC的工作原理和源码进行了分析,在这个过程发现了几个优化点:
1、Controller如果能保持单例,尽量使用单例
	这样可以减少创建对象和回收对象的开销。也就是说,如果Controller的类变量和实例
	变量可以以方法形参声明的尽量以方法的形参声明,不要以类变量和实例变量声明,这
	样可以避免线程安全问题。
2、处理Request的方法中的形参务必加上@RequestParam注解
	这样可以避免Spring MVC使用asm框架读取class文件获取方法参数名的过程。即便
	Spring MVC对读取出的方法参数名进行了缓存,如果不要读取class文件当然是更好。 
3、缓存URL
	阅读源码的过程中,我们发现Spring MVC并没有对处理 url的方法进行缓存,也就是
	说每次都要根据请求url去匹配Controller中的方法url,如果把url和Method的关系缓存起来,
    会不会带来性能上的提升呢?有点恶心的是,
    负责解析url和Method对应关系的 ServletHandlerMethodResolver是一个 private的内部类,
    不能直接继承该类增强代码,必须要该代码后重新编译。
    当然,如果缓存起来,必须要考虑缓存的线程安全问题。