SpringMVC执行流程源码分析

SpringMVC源码分析

前言

由于学习SpringBoot发现对springMVC的执行流程不是特别熟悉,所以对SpringMVC的源码进行简要的分析从而来了解SpringMVC的执行原理。

一、执行流程总结

在之前做的springMVC的总结中我们可以了解到SpringMVC的简要执行流程:

在这里插入图片描述

1、 用户发送请求至前端控制器DispatcherServlet

2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。

3、 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

4、 DispatcherServlet通过HandlerAdapter处理器适配器调用处理器

5、 执行处理器(Controller,也叫后端控制器)。

6、 Controller执行完成返回ModelAndView

7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet

8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器

9、 ViewReslover解析后返回具体View

10、DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。

11、DispatcherServlet响应用户

那就以此为参照来对其源码进行简要的剖析。

二、SpringMVC源码简单剖析

根据上边的图我们可以看到前端控制器在springMVC的系统中拥有了非常大的作用,那么我们就以此来入手。

在这里插入图片描述

  • 首先在它的关系图中我们可以看出,DispatcherServlet类继承FrameworkServlet类,而FrameworkServlet继承了HttpServletBean类,再往上就是HttpServlet类与Servlet类了。
  • 那么我们就可以得出DispatchServlet是一个servlet类,既然是一个Servlet那么久有一个核心方法:service方法,我们在DispatchServlet中找,发现没有,那我们继续去它的父类中找,于是发现了如下方法:
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
    if (HttpMethod.PATCH != httpMethod && httpMethod != null) {
        super.service(request, response);
    } else {
        this.processRequest(request, response);
    }
}
  • 它首先判断是不是PATCH请求,如果不是的话执行父类的service()方法,如果是则执行 processRequest(),那我们继续追踪:
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) {
                // servlet doesn't support if-modified-since, no reason
                // to go through further expensive logic
                doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < lastModified) {
                    // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
                    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 {
            //
            // Note that this means NO servlet supports whatever
            // method was requested, anywhere on this server.
            //

            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);
        }
    }

发现走到父类的super.service(request, response)方法之后,在service方法中调用了doGetdoHeaddoPost…等方法,而HTTP的基本请求(GET、POST、PUT、DELETE)方法都在DispatcherServerlet的父类FrameworkServlet中进行了重写,在重写的方法中调用了processRequest方法:

	@Override
	protected final void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}
	@Override
	protected final void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}
	@Override
	protected final void doPut(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}
	@Override
	protected final void doDelete(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

(注:从此至上述service方法开始,均为评论区(@thalictrum)指出错误后修改,由于当时学习的版本已经不明确,此块代码参考的MVC版本为:4.0.2.RELEASE)
于是让我们继续追踪:

protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        long startTime = System.currentTimeMillis();
        Throwable failureCause = null;
        LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
        LocaleContext localeContext = this.buildLocaleContext(request);
        RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor(null));
        this.initContextHolders(request, localeContext, requestAttributes);
        try {
            this.doService(request, response);
        } catch (IOException | ServletException var16) {
            failureCause = var16;
            throw var16;
        } catch (Throwable var17) {
            failureCause = var17;
            throw new NestedServletException("Request processing failed", var17);
        } finally {
            this.resetContextHolders(request, previousLocaleContext, previousAttributes);
            if (requestAttributes != null) {
                requestAttributes.requestCompleted();
            }

            if (this.logger.isDebugEnabled()) {
                if (failureCause != null) {
                    this.logger.debug("Could not complete request", (Throwable)failureCause);
                } else if (asyncManager.isConcurrentHandlingStarted()) {
                    this.logger.debug("Leaving response open for concurrent processing");
                } else {
                    this.logger.debug("Successfully completed request");
                }
            }

            this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
        }
    }
  • 这里边的代码主要是执行一些控制器等等,可以不用了解太多,我们主要是了解其执行流程。在其中我们可以看到 this.doService(request, response);方法,来执行一些事务,那么我们继续追踪:
protected abstract void doService(HttpServletRequest var1, HttpServletResponse var2) throws Exception;
  • 我们发现它是调用了子类:DispatcherServlet类中的方法,继续追踪:
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    if (this.logger.isDebugEnabled()) {
        String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
        this.logger.debug("DispatcherServlet with name '" + this.getServletName() + "'" + resumed + " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
    }
    Map<String, Object> attributesSnapshot = null;
    if (WebUtils.isIncludeRequest(request)) {
        attributesSnapshot = new HashMap();
        Enumeration attrNames = request.getAttributeNames();

        label112:
        while(true) {
            String attrName;
            do {
                if (!attrNames.hasMoreElements()) {
                    break label112;
                }
                attrName = (String)attrNames.nextElement();
            } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));

            attributesSnapshot.put(attrName, request.getAttribute(attrName));
        }
    }
    request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
    request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
    request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
    request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.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.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
    }
    try {
        this.doDispatch(request, response);
    } finally {
        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
            this.restoreAttributesAfterInclude(request, attributesSnapshot);
        }

    }
}
  • 我们看到它首先设置了一些request属性,然后执行了一个this.doDispatch(request, response)方法,至此我们算是找到了它的核心执行代码:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    try {
        try {
            ModelAndView mv = null;
            Object dispatchException = null;
            try {
                processedRequest = this.checkMultipart(request);
                multipartRequestParsed = processedRequest != request;
                mappedHandler = this.getHandler(processedRequest);
                if (mappedHandler == null) {
                    this.noHandlerFound(processedRequest, response);
                    return;
                }
                HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (this.logger.isDebugEnabled()) {
                        this.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;
                }
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
                this.applyDefaultViewName(processedRequest, mv);
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            } catch (Exception var20) {
                dispatchException = var20;
            } catch (Throwable var21) {
                dispatchException = new NestedServletException("Handler dispatch failed", var21);
            }
            this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
        } catch (Exception var22) {
            this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
        } catch (Throwable var23) {
            this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
        }

    } finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        } else if (multipartRequestParsed) {
            this.cleanupMultipart(processedRequest);
        }

    }
}
  • 这段代码可以分成四个部分:

    • 查找Handler对应的HandlerMapping部分:
    try {
        processedRequest = this.checkMultipart(request);
        multipartRequestParsed = processedRequest != request;
        mappedHandler = this.getHandler(processedRequest);
        if (mappedHandler == null) {
            this.noHandlerFound(processedRequest, response);
            return;
        }
    

    它首先判断request请求是不是二进制请求,然后执行this.getHandler(processedRequest);方法。那么我们来了解一下这个方法:

    @Nullable
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        if (this.handlerMappings != null) {
            Iterator var2 = this.handlerMappings.iterator();
            while(var2.hasNext()) {
                HandlerMapping hm = (HandlerMapping)var2.next();
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + this.getServletName() + "'");
                }
                HandlerExecutionChain handler = hm.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
        }
        return null;
    }
    

    首先:我们发现它获取了一个HandlerMapping的迭代器,然后查找每一个HandlerMapping。那么它为什么要先去查找HandlerMapping呢?那是因为我们在配置Controller的时候有两种方式:xml和注解的方式,所以它先去找到HandlerMapping,然后根据HandlerMapping去找Handler,就是hm.getHandler(request);这个方法来查找Handler。

在这里插入图片描述

执行后发现,它返回了一个HandlerExcutionChain类型的Handler,它里面包含了我们自己创建的Handler。

在这里插入图片描述

因此我们也就拿到了Handler对应的HandlerMapping。

  • 查找HandlerAdapter部分:
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
    if (this.logger.isDebugEnabled()) {
        this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
    }
    if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
        return;
    }
}

在拿到HandlerMapping之后,开始查找HandlerAdapter,就是ha.getLastModified(request, mappedHandler.getHandler());来查找。

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        if (this.handlerAdapters != null) {
            Iterator var2 = this.handlerAdapters.iterator();
            while(var2.hasNext()) {
                HandlerAdapter ha = (HandlerAdapter)var2.next();
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("Testing handler adapter [" + ha + "]");
                }
                if (ha.supports(handler)) {
                    return ha;
                }
            }
        }
        throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }

它的查找方式与之前查找HandlerMapping类似。

  • 拦截器执行部分:
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    return;
}
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HandlerInterceptor[] interceptors = this.getInterceptors();
    if (!ObjectUtils.isEmpty(interceptors)) {
        for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
            HandlerInterceptor interceptor = interceptors[i];
            if (!interceptor.preHandle(request, response, this.handler)) {
                this.triggerAfterCompletion(request, response, (Exception)null);
                return false;
            }
        }
    }
    return true;
}

它就是获取拦截器然后执行。

  • 再接下来就是Hanler执行部分:
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
    return;
}
this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
    dispatchException = var20;
} catch (Throwable var21) {
    dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);

它首先在 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); 执行了handler并返回了一个视图;然后通过 this.applyDefaultViewName(processedRequest, mv); 在我们没有设置视图名称的时候返回默认视图名;然后通过 this.applyDefaultViewName(processedRequest, mv); 获取到项目的拦截器,然后判断拦截器是否存在,存在则对该请求进行测试(postHandler),如果有一个拦截器不成功,则请求失败。最后来到视图解析和渲染的执行方法: this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {
    boolean errorView = false;
    if (exception != null) {
        if (exception instanceof ModelAndViewDefiningException) {
            this.logger.debug("ModelAndViewDefiningException encountered", exception);
            mv = ((ModelAndViewDefiningException)exception).getModelAndView();
        } else {
            Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
            mv = this.processHandlerException(request, response, handler, exception);
            errorView = mv != null;
        }
    }
    if (mv != null && !mv.wasCleared()) {
        this.render(mv, request, response);
        if (errorView) {
            WebUtils.clearErrorRequestAttributes(request);
        }
    } else if (this.logger.isDebugEnabled()) {
        this.logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + this.getServletName() + "': assuming HandlerAdapter completed request handling");
    }
    if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
        if (mappedHandler != null) {
            mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
        }

    }
}

它首先判断一下是否异常,如果出现异常,判断异常是否是ModelAndViewDefiningException的实例,如果是就直接调用getModelAndView方法返回一个mv,否则调用processHanlderException方法初始化mv对象;如果没有异常出现,那么判断mv是否为空,为空抛出异常,不为空则判断mv,wasCleared()方法返回的值是否为真;判断完成以后,执行了 this.render(mv, request, response);方法。

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    Locale locale = this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale();
    response.setLocale(locale);
    String viewName = mv.getViewName();
    View view;
    if (viewName != null) {
        view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request);
        if (view == null) {
            throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + this.getServletName() + "'");
        }
    } else {
        view = mv.getView();
        if (view == null) {
            throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a View object in servlet with name '" + this.getServletName() + "'");
        }
    }
    if (this.logger.isDebugEnabled()) {
        this.logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + this.getServletName() + "'");
    }

    try {
        if (mv.getStatus() != null) {
            response.setStatus(mv.getStatus().value());
        }
        view.render(mv.getModelInternal(), request, response);
    } catch (Exception var8) {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" + this.getServletName() + "'", var8);
        }

        throw var8;
    }
}

它首先设置了视图的编码格式,然后通过 view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request);进行了视图解析:

 @Nullable
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception {
    if (this.viewResolvers != null) {
        Iterator var5 = this.viewResolvers.iterator();
        while(var5.hasNext()) {
            ViewResolver viewResolver = (ViewResolver)var5.next();
            View view = viewResolver.resolveViewName(viewName, locale);
            if (view != null) {
                return view;
            }
        }
    }
    return null;
}

它是首先寻找视图解析器对象,然后根据视图解析器执行视图解析,解析完成之后返回view对象。然后就是通过 view.render(mv.getModelInternal(), request, response); 进行视图渲染。

public void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
    if (this.logger.isTraceEnabled()) {
        this.logger.trace("Rendering view with name '" + this.beanName + "' with model " + model + " and static attributes " + this.staticAttributes);
    }
    Map<String, Object> mergedModel = this.createMergedOutputModel(model, request, response);
    this.prepareResponse(request, response);
    this.renderMergedOutputModel(mergedModel, this.getRequestToExpose(request), response);
}

它首先通过 Map<String, Object> mergedModel = this.createMergedOutputModel(model, request, response);获取了传入的model的map集合。然后通过 this.prepareResponse(request, response);设置响应头的两个参数,最后通过 this.renderMergedOutputModel(mergedModel, this.getRequestToExpose(request), response);将mergeModel合到请求里.

protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
    this.exposeModelAsRequestAttributes(model, request);
    this.exposeHelpers(request);
    String dispatcherPath = this.prepareForRendering(request, response);
    RequestDispatcher rd = this.getRequestDispatcher(request, dispatcherPath);
    if (rd == null) {
        throw new ServletException("Could not get RequestDispatcher for [" + this.getUrl() + "]: Check that the corresponding file exists within your web application archive!");
    } else {
        if (this.useInclude(request, response)) {
            response.setContentType(this.getContentType());
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Including resource [" + this.getUrl() + "] in InternalResourceView '" + this.getBeanName() + "'");
            }

            rd.include(request, response);
        } else {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Forwarding to resource [" + this.getUrl() + "] in InternalResourceView '" + this.getBeanName() + "'");
            }

            rd.forward(request, response);
        }

    }
}

它首先进行了 this.exposeModelAsRequestAttributes(model, request);操作:

protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request) throws Exception {
    model.forEach((modelName, modelValue) -> {
        if (modelValue != null) {
            request.setAttribute(modelName, modelValue);
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Added model object '" + modelName + "' of type [" + modelValue.getClass().getName() + "] to request in view with name '" + this.getBeanName() + "'");
            }
        } else {
            request.removeAttribute(modelName);
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Removed model object '" + modelName + "' from request in view with name '" + this.getBeanName() + "'");
            }
        }

    });
}

由此可见,model中的数据,最终是放在request域中的。

然后他们进行了RequestDispatcher 对象配置,就是选择它要进行的操作了,是使用include还是forward进行跳转。至此,视图的解析与渲染工作都完成了,并且也发送到了前端页面,完成了一个请求的整个流程。

三、总结

SpringMVC的总体执行流程的源码解析就为以上描述,因为是学习SpringBoot过程中对其执行原理不太清晰,所以做得总结,可能有些许纰漏,也可能有些许错误,欢迎大家指正。

参考资料:

【1】SpringMVC源码关于视图解析渲染

【2】Spring源码解析 - springMVC核心代码(一)

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值