SpringMVC 请求处理流程源码分析

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_45505313/article/details/100782887

1. SpringMVC 配置

使用 SpringMVC 框架需要在 web.xml 文件中声明其核心的前端分发器 DispatcherServlet ,并指定其匹配 URL 的 mapping 规则,以便所有请求通过匹配 / 路径 进入框架,从而完成处理

<!-- Spring MVC servlet -->
	<servlet>
		<servlet-name>SpringMVC</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:spring-mvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
		<async-supported>true</async-supported>
	</servlet>
	<servlet-mapping>
		<servlet-name>SpringMVC</servlet-name>
		<!-- 此处可以可以配置成*.do,对应struts的后缀习惯 -->
		<url-pattern>/</url-pattern>
	</servlet-mapping>

2. 请求处理流程

在这里插入图片描述

2.1 DispathcerServlet 初始化

大致流程可参见另一篇文章 Spring 启动流程,此处主要讨论 DispathcerServlet 内部 initStrategies() 方法所做的工作。从源码来看,此处主要做一些组件初始化工作:

  • multipartResolver 处理文件上传的表单的解析器

  • localeResolver 提供国际化功能 :zh_CN -> 中文提示信息 ,en_US -> 美国英语

  • handlerMapping 处理浏览器的请求路径,对应控制器中哪个方法

  • handlerAdapter 用来真正执行控制器中的方法

  • handlerExceptionResolver (异常解析器) 负责处理控制器方法中异常, @ExceptionHandler

  • viewNameTranslator 解析视图名称, 例如:把方法的返回结果字符串当成视图名

  • viewResolver 视图解析器,将视图名解析为视图对象(如jsp视图对象)

     protected void initStrategies(ApplicationContext context) {
     	initMultipartResolver(context);
     	initLocaleResolver(context);
     	initThemeResolver(context);
     	initHandlerMappings(context);
     	initHandlerAdapters(context);
     	initHandlerExceptionResolvers(context);
     	initRequestToViewNameTranslator(context);
     	initViewResolvers(context);
     	initFlashMapManager(context);
     }
    

2.2 请求处理

  1. request 请求到来时,首先根据请求的类型(Get / Post 等) 在 DispathcerServlet 父类 FrameworkServlet 执行对应的方法。以 get 请求为例,调用链如下, FrameworkServlet 中主要完成了一些保存最初属性的工作,真正对请求的处理是在 doService 方法中完成的。而该方法由 DispathcerServlet 重写,此处进入了 DispathcerServlet 实现

    FrameworkServlet # doGet--> processRequest --> doService
    
    @Override
     protected final void doGet(HttpServletRequest request, HttpServletResponse response)
     		throws ServletException, IOException {
     	processRequest(request, response);
    }
     // 	FrameworkServlet 执行
     protected final void processRequest(HttpServletRequest request,HttpServletResponse response)
     		throws ServletException, IOException {
         ......
     	try {
     		doService(request, response);
     	}
     	......
      }
    
  2. DispathcerServlet 在 doService() 方法中完成了一些保存属性的工作,对请求的分发处理逻辑在 doDispatch() 方法中

    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
         ......
     	// 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());
    
     	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);
     	}
     	......
     }
    
  3. 进入 doDispatch 方法,可以看到该方法大致做了以下工作:
    【1】checkMultipart()判断这个请求是否是Multipart,比如文件上传就是Multipart请求
    【2】getHandler() 根据 request 进入 handlerMapping 进行路径匹配,匹配结束返回 HandlerExecutionChain 执行链。如该执行链为空或者其中的成员变量 handler为空的话,抛出NoHandlerFoundException异常,并结束此次请求处理
    【3】getHandlerAdapter() 根据 handler 获取 handlerAdapter对象, 由它来调用控制器
    【4】mappedHandler.applyPreHandle()执行链里会调用拦截器的 preHandle()方法,如果有任一个拦截器该方法返回 false,就不会调用postHandle(),直接清理资源,然后返回
    【5】ha.handle() 处理适配器(handlerAdapter)执行 handlerMethod,也就是 @Controller 中的功能方法 并返回一个 ModelAndView对象
    【6】applyDefaultViewName() 设置视图(view)的默认名称
    【7】mappedHandler.applyPostHandle()调用执行链中所有的拦截器的 postHandle()方法,对 handlerMethod 返回的结果进行加强处理
    【8】processDispatchResult() 进入返回处理结果的步骤,通过 render(mv, request, response) 调用 resolveViewName()方法使用视图解析器(ViewResolver)解析 ModelAndView 对象获得一个视图对象 View,之后调用 View 对象 render() 方法,将数据填充到视图中,产生一个响应结果返回给客户端

    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 || mappedHandler.getHandler() == 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 (logger.isDebugEnabled()) {
     					logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
     				}
     				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;
     		}
     		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
     	}
     	catch (Exception ex) {
     		triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
     	}
     	catch (Error err) {
     		triggerAfterCompletionWithError(processedRequest, response, mappedHandler, 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);
     			}
     		}
     	}
     }
    

猜你喜欢

转载自blog.csdn.net/weixin_45505313/article/details/100782887