源码浅析SpringMVC请求的流转过程

简介: Spring MVC框架使用了其”模型-视图-控制器”( Model-View-Controller )架构方式,用于开发灵活且松散耦合的 Web 应用程序。我们都使用过SpringMVC来处理信息,并渲染视图到Browser。但需要注意的是,在现在的架构中,大都采用了前后端分离的情况,而我们在使用SpringMVC的时候,只需要关注M(Model),C(Controller)这两个部分,而视图渲染的部分则交给了前端。

前言

Spring MVC框架使用了其”模型-视图-控制器”( Model-View-Controller )架构方式,用于开发灵活且松散耦合的 Web 应用程序。我们都使用过SpringMVC来处理信息,并渲染视图到Browser。但需要注意的是,在现在的架构中,大都采用了前后端分离的情况,而我们在使用SpringMVC的时候,只需要关注M(Model),C(Controller)这两个部分,而视图渲染的部分则交给了前端。

流程图

image.png

源码解析

(1):用户向服务发送HTTP请求,DispatcherServlet捕获请求。
(2):DispatcherServlet根据URL,调用 HandlerMapping 获得该 Handler 对象以及所对应的拦截器,其返回的是HandlerExecutionChain对象,这个对象中就包含了Handler对象以及这个Handler所对应的拦截器。
image.png
(3):DispatcherServlet根据获得的 Handler,选择一个合适的HandlerAdapter 。(附注:如果成功获得 HandlerAdapter 后,此时将开始执行拦截器的 preHandler 方法),然后获取Request请求数据,填充Handler,执行Handler。
(4):上一步获取到HandlerAdapter后,会执行Handler,并返回ModelAndView
image.png
(5):根据返回的 ModelAndView ,选择一个适合的 ViewResolver(必须是已经注册到 Spring 容器中的 ViewResolver),解析出View对象,然后返回给 DispatcherServlet。
image.png
(6):ViewResolver通过render()方法结合 Model 和 View,来渲染视图。
image.png
(7):ViewResolver通过render()方法写回给Browser。
image.png

流程详解

看完以上没有看过源码的童靴可能会一脸懵逼,此上也是围绕流程图进行了部分截取,方便大家理解,下面我们来搭建一个测试Demo来进一步了解。

(1):测试Controller(模拟用户真实情况)
image.png
(2):在解析DispatcherServlet之前,我们先来看一下DispatcherServlet的父类FrameworkServlet。
image.png
(3):通过上图我们不难看到一些敏感内容,如doGet(...)、doPost(…)、doPut(…)、doDelete(…)等等,我们通过这些方法可以看到,这些方法都指向了同一个方法,processRequest(…)
image.png
(4):我们来看一下FrameworkServlet的service(…)方法。

protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String method = request.getMethod();//获取请求方法
    if (method.equalsIgnoreCase(RequestMethod.PATCH.name())) {//判断请求方法
        this.processRequest(request, response);
    } else {
        super.service(request, response);//调用父类的service(…)方法
    }
}

(5):我们来看一下父类HttpServlet所包含的方法。
image.png
(6):通过service(…)我们可以看出,此方法是根据方法类型,分发请求的。
image.png
(7):我们继续跟进方法,就不难发现这些请求处理的方法就回到了(3)中所示。
image.png
(8):我们重点关注一下,processRequest(…)方法,(代码已作删减)

protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    try {
        //线程绑定
        /**
         *封装Locale对象、属性到LocaleContextHolder
         *封装Locale对象、属性到RequestContextHolder
         */
         …
        this.doService(request, response);//请求处理
    } catch (ServletException var17) {
        failureCause = var17;
        throw var17;
    } catch (IOException var18) {
        failureCause = var18;
        throw var18;
    } catch (Throwable var19) {
        failureCause = var19;
        throw new NestedServletException("Request processing failed", var19);
    } finally {
        //解除绑定
        //……
        this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
    }
}

(9):通过上述代码,请求处理doService(…)方法。我们可以看到父类中是一个抽象方法,Spring中很多地方运用了这种方法,由父类抽象流程,交由子类在实现具体的方法,看到这里也就明白了,这个地方就是DispatcherServlet的入口方法,
image.png
(10):DispatcherServlet中doService(…)方法

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    //DEBUG日志输出
    //封装属性
    //…
    try {
        this.doDispatch(request, response);//请求处理分发
    } finally {
        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
            this.restoreAttributesAfterInclude(request, attributesSnapshot);
        }
    }
}

(11):请求处理,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 {
        try {
            ModelAndView mv = null;
            Exception dispatchException = null;
            try {
                //校验是否是文件上传请求
                processedRequest = this.checkMultipart(request);
                multipartRequestParsed = processedRequest != request;
                //获取处理器、拦截器数组对象。
                mappedHandler = this.getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    //获取不到,异常处理。
                    this.noHandlerFound(processedRequest, response);
                    return;
                }
                //获取当前处理器所对应的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;
                    }
                }
                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 var19) {
                dispatchException = var19;
            }
            //处理结果(包括异常),渲染视图等等,
            this.processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        } catch (Exception var20) {
            this.triggerAfterCompletion(processedRequest, response, mappedHandler, var20);
        } catch (Error var21) {
            this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, var21);
        }
    } finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        } else if (multipartRequestParsed) {
            this.cleanupMultipart(processedRequest);
        }
    }
}
目录
相关文章
|
4天前
|
Java 应用服务中间件 Spring
Spring5源码(50)-SpringMVC源码阅读环境搭建
Spring5源码(50)-SpringMVC源码阅读环境搭建
44 0
|
4天前
|
Java 应用服务中间件 数据库连接
Spring5源码(51)-Servlet知识点回顾以及SpringMVC分析入口
Spring5源码(51)-Servlet知识点回顾以及SpringMVC分析入口
38 0
|
10月前
|
存储 前端开发 搜索推荐
(八)Spring源码解析:Spring MVC
(八)Spring源码解析:Spring MVC
56 1
|
4天前
|
设计模式 前端开发 Java
[Spring ~源码] Spring的run方法以及SpringMVC执行流程
[Spring ~源码] Spring的run方法以及SpringMVC执行流程
|
4天前
|
SQL JSON 前端开发
【源码免费下载】SpringBoot整合Spring+SpringMVC+MyBatisPlus案例:图书管理系统
【源码免费下载】SpringBoot整合Spring+SpringMVC+MyBatisPlus案例:图书管理系统
67 0
|
JSON 缓存 Java
享读SpringMVC源码5-异常处理HandlerExceptionResolver(下)
享读SpringMVC源码5-异常处理HandlerExceptionResolver(下)
|
Java Spring 容器
享读SpringMVC源码5-异常处理HandlerExceptionResolver(上)
享读SpringMVC源码5-异常处理HandlerExceptionResolver(上)
享读SpringMVC源码5-异常处理HandlerExceptionResolver(上)
|
Java Spring
享读SpringMVC源码4-感谢RequestMappingHandlerAdapter(下)
享读SpringMVC源码4-感谢RequestMappingHandlerAdapter(下)
享读SpringMVC源码4-感谢RequestMappingHandlerAdapter(下)
|
数据采集 缓存 Java
享读SpringMVC源码4-感谢RequestMappingHandlerAdapter(上)
享读SpringMVC源码4-感谢RequestMappingHandlerAdapter(上)
|
设计模式 缓存
享读SpringMVC源码3-既有HandlerMapping 何生HandlerAdapter
享读SpringMVC源码3-既有HandlerMapping 何生HandlerAdapter