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

  

  

posted @ 2020-05-13 19:44  遨游java  阅读(202)  评论(0编辑  收藏  举报