SpringMVC运行流程源码分析
springMVC的核心:DispatchServlet; 请求转发器,前端控制器
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--DispatchServlet可以绑定spring的配置文件-->
<init-param>
<!-- 指定SpringMVC配置文件位置 -->
<param-name>contextConfigLocation</param-name>
<!--如果不指定 默认 /WEB-INF/上面的名字-servlet.xml-->
<param-value>classpath:spring-servlet.xml</param-value>
</init-param>
<!--启动级别1: 跟服务器一起启动-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--
所有请求都会被springmvc拦截
在springMVC中,/ 和 /*的区别
/ : 只匹配所有的请求,不会去匹配jsp页面
/* : 匹配所有的请求,也会匹配jsp页面
-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
DispatchServlet 是一个Servlet 继承关系图如下
doDispatch是SpringMVC的核心类DispatcherServlet中的核心方法,源码如下
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.
// 根据当前的请求地址找到能处理这个请求的目标处理器类(控制类) 也就是我们写的Controller类,用@Controller注解标注的类。 mappedHandler = getHandler(processedRequest);
// 如果没有相应的处理器/控制器,则抛出一个异常或者404; if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // 拿到能执行这个类的所有方法的适配器;
// 根据当前处理器类获取到能执行这个处理器方法的适配器 如果使用的是注解@Controller,则就是AnnotationMethodHandlerAdapter适配器 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. 使用适配器执行目标方法 并返回一个ModelAndView对象。 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()里几个重要方法
1、getHandler() 根据当前请求在HandlerMapping中找到这个请求的映射信息,获取到目标处理器类
@Nullable protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// handlerMapping存储了所有的请求的Handler,包括注解的和配置的,遍历所有的请求,找到符合当前请求的handler 如果不为空,直接返回 if (this.handlerMappings != null) { for (HandlerMapping mapping : this.handlerMappings) { HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null) { return handler; } } } return null; }
2、getHandlerAdapter() 根据当前处理器类,找到当前类的HandlerAdapter(适配器)
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
// 遍历所有的适配器,包括 AbstractHandlerMethodAdapter(由RequestMappingHandlerAdapter继承,正常注解拿到的就是这个适配器)
// HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、SimpleServletHandlerAdapter
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
// 判断当前适配器是否是请求所需要的适配器,多数是用的instance of来进行判断
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }
3、mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); 执行目标方法 最难的一步 主要看看目标方法在何时,在哪执行的
正常注解类的请求会走 RequestMappingHandlerAdapter类下的 handleInternal() 方法
该方法核心一步就是
mav = invokeHandlerMethod(request, response, handlerMethod);
该方法中的核心方法 invocableMethod.invokeAndHandle(webRequest, mavContainer);
接着进入这个方法 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); 这个方法用来invoke请求
进入这个方法
@Nullable public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 设置所有目标方法参数 进入这个方法你可以看到,该方法申请了一个长度跟目标参数个数相等的Object数组,并把目标参数放入放入数组中 然后返回该数组 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) { logger.trace("Arguments: " + Arrays.toString(args)); }
// 执行目标方法 return doInvoke(args); }
进入doInvoke方法
@Nullable protected Object doInvoke(Object... args) throws Exception { ReflectionUtils.makeAccessible(getBridgedMethod()); try {
// 终于在这里 SpringMVC调用了反射底层的invoke方法 目标方法得以执行 return getBridgedMethod().invoke(getBean(), args); } catch (IllegalArgumentException ex) { assertTargetBean(getBridgedMethod(), getBean(), args); String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument"); throw new IllegalStateException(formatInvokeError(text, args), ex); } catch (InvocationTargetException ex) { // Unwrap for HandlerExceptionResolvers ... Throwable targetException = ex.getTargetException(); if (targetException instanceof RuntimeException) { throw (RuntimeException) targetException; } else if (targetException instanceof Error) { throw (Error) targetException; } else if (targetException instanceof Exception) { throw (Exception) targetException; } else { throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException); } } }
SpringMVC九大组件
SpringMVC在工作的时候,关键位置都是由组件完成的;
这九大组件的共同点就是:全都是接口;接口就是规范,提供了非常强大的扩展性
/** 文件上传解析器 */ @Nullable private MultipartResolver multipartResolver; /** 区域信息解析器:和国际化有关 */ @Nullable private LocaleResolver localeResolver; /** 主题解析器;支持主题效果更换 */ @Nullable private ThemeResolver themeResolver; /** Handler的映射信息:HandlerMapping */ @Nullable private List<HandlerMapping> handlerMappings; /** Handler适配器 */ @Nullable private List<HandlerAdapter> handlerAdapters; /** SpringMVC强大的异常解析功能:异常解析器 */ @Nullable private List<HandlerExceptionResolver> handlerExceptionResolvers; /** RequestToViewNameTranslator used by this servlet. */ @Nullable private RequestToViewNameTranslator viewNameTranslator; /** SpringMVC中运行重定向携带数据的功能 */ @Nullable private FlashMapManager flashMapManager; /** 视图解析器 */ @Nullable private List<ViewResolver> viewResolvers;
九大组件初始化:DispatcherServlet.java中的
protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); }
总结:
1、所有请求,前端控制器(DispatchServlet)收到请求,调用doDispatch进行处理
2、根据HandlerMapping中保存的请求映射信息找到,处理当前请求的,处理器执行链(包含拦截器)
3、根据当前处理器找到它的HandlerAdapter(适配器)
4、拦截器的preHandle先执行
5、适配器执行目标方法,并返回ModelAndView
1)、ModleAttribute注解标注的方法提前运行
2)、执行目标方法的时候(确定目标方法用的参数)
a、有注解
b、无注解
a)、看是否是Model、Map或其他的
b)、如果是自定义类型
1、看隐含模型中有没有,如果有就从隐含模型中拿
2、如果没有,再看是否SessionAttributes标注的属性,如果是从从session中拿。如果拿不到,抛异常
3、都不是,就利用反射创建对象
6、拦截器postHandle执行
7、处理结果(页面渲染流程)
1)、如果有异常使用异常解析器处理异常;处理完后返回ModelAndView
2)、调用render进行渲染
a、视图解析器根据视图名得到视图对象
b、视图对象调用render方法
8、执行拦截器的afterCompletion