SpringMVC处理请求的流程

一、SpringMVC中的常用组件

  • DispatcherServlet:前端控制器,不需要工程师开发,由框架提供
    作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求

  • HandlerMapping:处理器映射器,不需要工程师开发,由框架提供

    作用:根据请求的url、method等信息查找Handler,即控制器方法

  • Handler:处理器,需要工程师开发
    作用:在DispatcherServlet的控制下Handler对具体的用户请求进行处理

  • HandlerAdapter:处理器适配器,不需要工程师开发,由框架提供
    作用:通过HandlerAdapter对处理器(控制器方法)进行执行

  • ViewResolver:视图解析器,不需要工程师开发,由框架提供
    作用:进行视图解析,得到相应的视图,例如:ThymeleafView、InternalResourceView、 RedirectView

  • View:视图
    作用:将模型数据通过页面展示给用户。

二、 DispatcherServlet

DispatcherServlet也是一个servlet,那么就有service方法,接下了我们看一下这两个方法是如何从Servlet一步步继承过来的。

1.DispatcherServlet的继承关系

在这里插入图片描述

2.service方法

GenericServlet中:

public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

在该类中并没有实现service方法,交给了子类去实现。

HttpServlet中:

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        long lastModified;
        if (method.equals("GET")) {
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                this.doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader("If-Modified-Since");
                if (ifModifiedSince < lastModified) {
                    this.maybeSetLastModified(resp, lastModified);
                    this.doGet(req, resp);
                } else {
                    resp.setStatus(304);
                }
            }
        } else if (method.equals("HEAD")) {
            lastModified = this.getLastModified(req);
            this.maybeSetLastModified(resp, lastModified);
            this.doHead(req, resp);
        } else if (method.equals("POST")) {
            this.doPost(req, resp);
        } else if (method.equals("PUT")) {
            this.doPut(req, resp);
        } else if (method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if (method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if (method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(501, errMsg);
        }

    }

HttpServlet中已经将service方法实现,并且它调用的doPost、doGet等一系列方法都被实现。

HttpServletBean中:在该类中并没有重写父类的service方法,所以它的service方法与HttpServlet相同。

FrameworkServlet中

protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
        if (httpMethod != HttpMethod.PATCH && httpMethod != null) {
            super.service(request, response);
        } else {
            this.processRequest(request, response);
        }

    }

从该方法可以看出,如果请求方式等于PATCH并且不等于null,那么就会调用processRequest方法,否则就会执行父类的service方法。我们知道父类的service方法根据请求方式调用的是doPost、doGet等一系列方法,在该类中这些方法都被重写,如下:

 protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.processRequest(request, response);
    }

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

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

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

    protected void doOptions(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        if (this.dispatchOptionsRequest || CorsUtils.isPreFlightRequest(request)) {
            this.processRequest(request, response);
            if (response.containsHeader("Allow")) {
                return;
            }
        }

        super.doOptions(request, new HttpServletResponseWrapper(response) {
            public void setHeader(String name, String value) {
                if ("Allow".equals(name)) {
                    value = (StringUtils.hasLength(value) ? value + ", " : "") + HttpMethod.PATCH.name();
                }

                super.setHeader(name, value);
            }
        });
    }

    protected void doTrace(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        if (this.dispatchTraceRequest) {
            this.processRequest(request, response);
            if ("message/http".equals(response.getContentType())) {
                return;
            }
        }

        super.doTrace(request, response);
    }

我们可以看出,无论哪种请求方式,最中都会调用processRequest方法,下面我们来看一下该方法。

我们只看该方法的核心部分,如下:

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

            this.logResult(request, response, (Throwable)failureCause, asyncManager);
            this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
        }

该方法又调用了doServic方法,该方法如下:

protected abstract void doService(HttpServletRequest var1, HttpServletResponse var2) throws Exception;

该方法并没有在该类中实现,我们需要去它的子类中看这个方法。

DispatcherServlet中:

在该类中并没有重写service、processRequest方法,但是它实现了父类的doService方法,下面是该方法的核心:

        try {
            this.doDispatch(request, response);
        } finally {
            if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
                this.restoreAttributesAfterInclude(request, attributesSnapshot);
            }

            if (requestPath != null) {
                ServletRequestPathUtils.clearParsedRequestPath(request);
            }
        }

在这个方法中又调用了doDispatch,该方法在该类中实现。

我们一步步分析,最终找出doDispatch方法是SpringMVC处理请求的核心方法,该方法的调用关系如下:
在这里插入图片描述

三、SpringMVC的执行流程

在这里插入图片描述

  1. 用户发送的请求被DispatcherServlet拦截。
  2. DispatcherServlet通过HandleMapping获取handler:HandlerMapping根据请求信息(URL),找到具体的handler,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet。
  3. DispatcherServlet根据handler获取HandlerAdapter(处理器适配器),执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作
  4. DispatcherServlet调用HandlerAdapter的handle()方法,来执行控制器方法。
  5. HandlerAdapter调用handler的handleRequest()方法获取ModelAndView对象,并将该对象返回给DispatcherServlet。
  6. DispatcherServlet将ModelAndView交给ViewResover进行视图解析。
  7. ViewResover将解析完的视图View返回给DispatcherServlet。
  8. DispatcherServlet对view进行视图渲染(即将模型数据model填充至视图中)。
  9. 将view响应给客户端。

下面我们从源代码(部分代码)的角度来分析这一过程。

  1. DispatcherServlet通过HandleMapping获取handler:HandlerMapping根据请求信息(URL),找到具体的handler,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet。
    在这里插入图片描述
    我们看一下HandlerExecutionChain里面有什么:
    在这里插入图片描述

  2. DispatcherServlet根据handler获取HandlerAdapter(处理器适配器)。
    在这里插入图片描述

  3. DispatcherServlet调用HandlerAdapter的handle()方法,来执行控制器方法。 HandlerAdapter调用handler的handleRequest()方法获取ModelAndView对象,并将该对象返回给DispatcherServlet。在这里插入图片描述

  4. 视图渲染
    在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值