[转] SpringMVC 执行流程及源码解析

在 SpringMVC 中主要是围绕着 DispatcherServlet 来设计,可以把它当做指挥中心。这里先说明一下 SpringMVC 文档给出的执行流程,然后是我们稍微具体的执行流程,最后是流程大致的源码跟踪。关于很很很详细的源码解析,这里暂先不做。

官方文档中的流程

首先看下 SpringMVC 文档上给的流程图:
官方流程图
这张图片给了我们大概的执行流程:

  1. 用户请求首先发送到前端控制器 DispatcherServlet,DispatcherServlet 根据请求的信息来决定使用哪个页面控制器 Controller(也就是我们通常编写的 Controller)来处理该请求。找到控制器之后,DispatcherServlet 将请求委托给控制器去处理。
  2. 接下来页面控制器开始处理用户请求,页面控制器会根据请求信息进行处理,调用业务层等等,处理完成之后,会把结果封装成一个 ModelAndView 返回给 DispatcherServlet。
  3. 前端控制器 DispatcherServlet 接到页面控制器的返回结果后,根据返回的视图名选择相应的试图模板,并根据返回的数据进行渲染。
  4. 最后前端控制器 DispatcherServlet 将结果返回给用户。

更具体的流程

上面只是总体流程,接下来我们稍微深入一点,看下更具体的流程,这里没有图,只有步骤解析:

  1. 用户请求发送到前端控制器 DispatcherServlet。
  2. 前端控制器 DispatcherServlet 接收到请求后,DispatcherServlet 会使用 HandlerMapping 来处理,HandlerMapping 会查找到具体进行处理请求的 Handler 对象。
  3. HandlerMapping 找到对应的 Handler 之后,并不是返回一个 Handler 原始对象,而是一个 Handler 执行链,在这个执行链中包括了拦截器和处理请求的 Handler。HandlerMapping 返回一个执行链给 DispatcherServlet。
  4. DispatcherServlet 接收到执行链之后,会调用 Handler 适配器去执行 Handler。
  5. Handler 适配器执行完成 Handler(也就是我们写的 Controller)之后会得到一个 ModelAndView,并返回给 DispatcherServlet。
  6. DispatcherServlet 接收到 Handler 适配器返回的 ModelAndView 之后,会根据其中的视图名调用视图解析器。
  7. 视图解析器根据逻辑视图名解析成一个真正的 View 视图,并返回给 DispatcherServlet。
  8. DispatcherServlet 接收到视图之后,会根据上面的 ModelAndView 中的 model 来进行视图中数据的填充,也就是所谓的视图渲染。
  9. 渲染完成之后,DispatcherServlet 就可以将结果返回给用户了。

源码

DispatcherServlet 是一个 Servlet,我们知道在 Servlet 在处理一个请求的时候会交给 service 方法进行处理,这里也不例外,DispatcherServlet 继承了 FrameworkServlet,首先进入 FrameworkServlet 的 service 方法:

protected void service (HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    // 请求方法
    String method = request.getMethod ();
    //PATCH 方法单独处理
    if (method.equalsIgnoreCase (RequestMethod.PATCH.name ())) {
        processRequest (request, response);
    }
    else {// 其他的请求类型的方法经由父类,也就是 HttpServlet 处理
        super.service (request, response);
    }
}

HttpServlet 中会根据请求类型的不同分别调用 doGet 或者 doPost 等方法,FrameworkServlet 中已经重写了这些方法,在这些方法中会调用 processRequest 进行处理,在 processRequest 中会调用 doService 方法,这个 doService 方法就是在 DispatcherServlet 中实现的。下面就看下 DispatcherServlet 中的 doService 方法的实现。

请求到达 DispatcherServlet

doService 方法:

protected void doService (HttpServletRequest request, HttpServletResponse response) throws Exception {

    // 给 request 中的属性做一份快照
    Map<String, Object> attributesSnapshot = null;
    if (WebUtils.isIncludeRequest (request)) {
        logger.debug ("Taking snapshot of request attributes before include");
        attributesSnapshot = new HashMap<String, Object>();
        Enumeration<?> attrNames = request.getAttributeNames ();
        while (attrNames.hasMoreElements ()) {
            String attrName = (String) attrNames.nextElement ();
            if (this.cleanupAfterInclude || attrName.startsWith ("org.springframework.web.servlet")) {
                attributesSnapshot.put (attrName, request.getAttribute (attrName));
            }
        }
    }

    // 如果我们没有配置类似本地化或者主题的处理器之类的
    //SpringMVC 会使用默认的值
    // 默认配置文件是 DispatcherServlet.properties
    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);
    }
    finally {
        if (WebAsyncUtils.getAsyncManager (request).isConcurrentHandlingStarted ()) {
            return;
        }
        // Restore the original attribute snapshot, in case of an include.
        if (attributesSnapshot != null) {
            restoreAttributesAfterInclude (request, attributesSnapshot);
        }
    }
}

DispatcherServlet 开始真正的处理,doDispatch 方法:

protected void doDispatch (HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;
    //SpringMVC 中异步请求的相关知识,暂先不解释
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager (request);

    try {
        ModelAndView mv = null;
        Exception dispatchException = null;

        try {
            // 先检查是不是 Multipart 类型的,比如上传等
            // 如果是 Multipart 类型的,则转换为 MultipartHttpServletRequest 类型
            processedRequest = checkMultipart (request);
            multipartRequestParsed = processedRequest != request;

            // 获取当前请求的 Handler
            mappedHandler = getHandler (processedRequest, false);
            if (mappedHandler == null || mappedHandler.getHandler () == null) {
                noHandlerFound (processedRequest, response);
                return;
            }

            // 获取当前请求的 Handler 适配器
            HandlerAdapter ha = getHandlerAdapter (mappedHandler.getHandler ());

            // 对于 header 中 last-modified 的处理
            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;
                }
            }
            // 拦截器的 preHandle 方法进行处理
            if (!mappedHandler.applyPreHandle (processedRequest, response)) {
                return;
            }

            try {
                // 真正调用 Handler 的地方
                mv = ha.handle (processedRequest, response, mappedHandler.getHandler ());
            }
            finally {
                if (asyncManager.isConcurrentHandlingStarted ()) {
                    return;
                }
            }
            // 处理成默认视图名,就是添加前缀和后缀等
            applyDefaultViewName (request, mv);
            // 拦截器 postHandle 方法进行处理
            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
            mappedHandler.applyAfterConcurrentHandlingStarted (processedRequest, response);
            return;
        }
        // Clean up any resources used by a multipart request.
        if (multipartRequestParsed) {
            cleanupMultipart (processedRequest);
        }
    }
}

可以看到大概的步骤还是按照我们上面分析的走的。

查找请求对应的 Handler 对象

对应着这句代码 mappedHandler = getHandler (processedRequest, false);,看下具体的 getHandler 方法:

protected HandlerExecutionChain getHandler (HttpServletRequest request, boolean cache) throws Exception {
    return getHandler (request);
}

继续往下看 getHandler:

protected HandlerExecutionChain getHandler (HttpServletRequest request) throws Exception {
    // 遍历所有的 handlerMappings 进行处理
    //handlerMappings 是在启动的时候预先注册好的
    for (HandlerMapping hm : this.handlerMappings) {
        HandlerExecutionChain handler = hm.getHandler (request);
        if (handler != null) {
            return handler;
        }
    }
    return null;
}

继续往下看 getHandler,在 AbstractHandlerMapping 类中:

public final HandlerExecutionChain getHandler (HttpServletRequest request) throws Exception {
    // 根据 request 获取 handler
    Object handler = getHandlerInternal (request);
    if (handler == null) {
        // 如果没有找到就使用默认的 handler
        handler = getDefaultHandler ();
    }
    if (handler == null) {
        return null;
    }
    // 如果 Handler 是 String,表明是一个 bean 名称
    // 需要超照对应 bean
    if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = getApplicationContext ().getBean (handlerName);
    }
    // 封装 Handler 执行链
    return getHandlerExecutionChain (handler, request);
}

根据 requrst 获取 handler

首先看下根据 requrst 获取 handler 步骤 getHandlerInternal 方法,在 AbstractHandlerMethodMapping 中:

protected HandlerMethod getHandlerInternal (HttpServletRequest request) throws Exception {
    // 获取 request 中的 url,用来匹配 handler
    String lookupPath = getUrlPathHelper ().getLookupPathForRequest (request);
    // 根据路径寻找 Handler
    HandlerMethod handlerMethod = lookupHandlerMethod (lookupPath, request);
    // 根据 handlerMethod 中的 bean 来实例化 Handler 并添加进 HandlerMethod
    return (handlerMethod != null) ? handlerMethod.createWithResolvedBean () : null;
}

看下根据路径寻找 handler 的方法 lookupHandlerMethod:

protected HandlerMethod lookupHandlerMethod (String lookupPath, HttpServletRequest request) throws Exception {
    List<Match> matches = new ArrayList<Match>();
    // 直接匹配
    List<T> directPathMatches = this.urlMap.get (lookupPath);
    // 如果有匹配的,就添加进匹配列表中
    if (directPathMatches != null) {
        addMatchingMappings (directPathMatches, matches, request);
    }
    // 还没有匹配的,就遍历所有的处理方法查找
    if (matches.isEmpty ()) {
        // No choice but to go through all mappings
        addMatchingMappings (this.handlerMethods.keySet (), matches, request);
    }
    // 找到了匹配的
    if (!matches.isEmpty ()) {
        Comparator<Match> comparator = new MatchComparator (getMappingComparator (request));
        Collections.sort (matches, comparator);
        // 排序之后,获取第一个
        Match bestMatch = matches.get (0);
        // 如果有多个匹配的,会找到第二个最合适的进行比较一下
        if (matches.size () > 1) {
            Match secondBestMatch = matches.get (1);
            if (comparator.compare (bestMatch, secondBestMatch) == 0) {
                Method m1 = bestMatch.handlerMethod.getMethod ();
                Method m2 = secondBestMatch.handlerMethod.getMethod ();
                throw new IllegalStateException (
                        "Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL () + "': {" +
                        m1 + "," + m2 + "}");
            }
        }
        // 设置 request 参数
        handleMatch (bestMatch.mapping, lookupPath, request);
        // 返回匹配的 url 的处理的方法
        return bestMatch.handlerMethod;
    }
    else {// 最后还没有找到,返回 null
        return handleNoMatch (handlerMethods.keySet (), lookupPath, request);
    }
}

获取默认 Handler

如果上面没有获取到 Handler,就会获取默认的 Handler。如果还获取不到就返回 null。

处理 String 类型的 Handler

如果上面处理完的 Handler 是 String 类型的,就会根据这个 handlerName 获取 bean。

封装 Handler 执行链

上面获取完 Handler,就开始封装执行链了,就是将我们配置的拦截器加入到执行链中去,getHandlerExecutionChain:

protected HandlerExecutionChain getHandlerExecutionChain (Object handler, HttpServletRequest request) {
    // 如果当前 Handler 不是执行链类型,就使用一个新的执行链实例封装起来
    HandlerExecutionChain chain =
        (handler instanceof HandlerExecutionChain) ?
            (HandlerExecutionChain) handler : new HandlerExecutionChain (handler);
    // 先获取适配类型的拦截器添加进去拦截器链
    chain.addInterceptors (getAdaptedInterceptors ());
    // 当前的 url
    String lookupPath = urlPathHelper.getLookupPathForRequest (request);
    // 遍历拦截器,找到跟当前 url 对应的,添加进执行链中去
    for (MappedInterceptor mappedInterceptor : mappedInterceptors) {
        if (mappedInterceptor.matches (lookupPath, pathMatcher)) {
            chain.addInterceptor (mappedInterceptor.getInterceptor ());
        }
    }

    return chain;
}

获取对应请求的 Handler 适配器

getHandlerAdapter:

protected HandlerAdapter getHandlerAdapter (Object handler) throws ServletException {
    // 遍历所有的 HandlerAdapter,找到和当前 Handler 匹配的就返回
    // 我们这里会匹配到 RequestMappingHandlerAdapter
    for (HandlerAdapter ha : this.handlerAdapters) {
        if (ha.supports (handler)) {
            return ha;
        }
    }
}

缓存的处理

也就是对 last-modified 的处理

执行拦截器的 preHandle 方法

就是遍历所有的我们定义的 interceptor,执行 preHandle 方法

使用 Handler 适配器执行当前的 Handler

ha.handle 执行当前 Handler,我们这里使用的是 RequestMappingHandlerAdapter,首先会进入 AbstractHandlerMethodAdapter 的 handle 方法:

public final ModelAndView handle (HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception {
    return handleInternal (request, response, (HandlerMethod) handler);
}

handleInternal 方法,在 RequestMappingHandlerAdapter 中:

protected final ModelAndView handleInternal (HttpServletRequest request,
        HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

    if (getSessionAttributesHandler (handlerMethod).hasSessionAttributes ()) {
        // Always prevent caching in case of session attribute management.
        checkAndPrepare (request, response, this.cacheSecondsForSessionAttributeHandlers, true);
    }
    else {
        // Uses configured default cacheSeconds setting.
        checkAndPrepare (request, response, true);
    }

    // Execute invokeHandlerMethod in synchronized block if required.
    if (this.synchronizeOnSession) {
        HttpSession session = request.getSession (false);
        if (session != null) {
            Object mutex = WebUtils.getSessionMutex (session);
            synchronized (mutex) {
                return invokeHandleMethod (request, response, handlerMethod);
            }
        }
    }
    // 执行方法,封装 ModelAndView
    return invokeHandleMethod (request, response, handlerMethod);
}

组装默认视图名称

前缀和后缀名都加上

执行拦截器的 postHandle 方法

遍历 intercepter 的 postHandle 方法。

处理最后的结果,渲染之类的

processDispatchResult 方法:

private void processDispatchResult (HttpServletRequest request, HttpServletResponse response,
        HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {

    boolean errorView = false;

    if (exception != null) {
        if (exception instanceof ModelAndViewDefiningException) {
            mv = ((ModelAndViewDefiningException) exception).getModelAndView ();
        }
        else {
            Object handler = (mappedHandler != null ? mappedHandler.getHandler () : null);
            mv = processHandlerException (request, response, handler, exception);
            errorView = (mv != null);
        }
    }

    // Did the handler return a view to render?
    if (mv != null && !mv.wasCleared ()) {
        // 渲染
        render (mv, request, response);
        if (errorView) {
            WebUtils.clearErrorRequestAttributes (request);
        }
    }
    else {
    }

    if (WebAsyncUtils.getAsyncManager (request).isConcurrentHandlingStarted ()) {
        // Concurrent handling started during a forward
        return;
    }

    if (mappedHandler != null) {
        mappedHandler.triggerAfterCompletion (request, response, null);
    }
}

重点看下 render 方法,进行渲染:

protected void render (ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 设置本地化
    Locale locale = this.localeResolver.resolveLocale (request);
    response.setLocale (locale);

    View view;
    if (mv.isReference ()) {
        // 解析视图名,得到视图
        view = resolveViewName (mv.getViewName (), mv.getModelInternal (), locale, request);
    }
    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 () + "'");
        }
    }

    // 委托给视图进行渲染
    view.render (mv.getModelInternal (), request, response);
}

view.render 就是进行视图的渲染,然后跳转页面等处理。

到这里大概的流程就走完了。其中涉及到的东西还有很多,暂先不做详细处理。

原文:[SpringMVC 执行流程及源码解析](http://cxis.me/2017/04/06/SpringMVC% E6%89% A7% E8% A1%8C% E6% B5%81% E7% A8%8B% E5%8F%8A% E6% BA%90% E7% A0%81% E8% A7% A3% E6%9E%90/)


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 jaytp@qq.com

×

喜欢就点赞,疼爱就打赏