原理 - Spring:(二)DispatcherServlet.doDispatch方法流程

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/lidelin10/article/details/100033302

该文章主要介绍了DispatcherServlet的主要逻辑实现 – doDispatch方法,包括拦截器各个方法调用时机、Handler的查找和调用等主要逻辑

DispatcherServlet主要在doDispatch中分发请求以及拦截器的调用,
(源代码下方有流程图)

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;
    ...
      // 检查是否为multipart/*类型
    processedRequest = checkMultipart(request);
    multipartRequestParsed = (processedRequest != request);

    
    if (mappedHandler == null) {
        noHandlerFound(processedRequest, response);
        return;
    }

    // 确认支持当前请求Handler的Adapter,用于调用Handler的handle方法
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

    // 处理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;
    }

    // HandlerAdapter代理执行Handler的handle方法
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

    ...

    //进行视图的渲染
    applyDefaultViewName(processedRequest, mv);
    
    //调用拦截器链的postHandle方法
    mappedHandler.applyPostHandle(processedRequest, response, mv);
    ...
}

转换成流程图如下:
在这里插入图片描述
当一个请求到来时:
1、根据request的uri和其他信息(比如HttpMethod、Header等信息)确定Handler,选择支持该类型Hanlder的HandlerAdapter(HandlerAdapter主要用于对Handler的handle方法调用:处理函数参数的注入、返回值的处理等);

    //确认处理当前请求的Handler
    mappedHandler = getHandler(processedRequest);

    ...

    // 确认支持当前请求Handler的Adapter,用于调用Handler的handle方法
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

2、如果是Get或者Head请求,判断文件修改时间;如果未修改直接返回;RequestMappingAdapter的修改时间默认返回-1,即判断文件修改时间总是返回false;

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

3、从步骤1中确定的Hanlder是一条包含拦截器集合和Hanlder的调用链,DispatcherServlet调用所有拦截器的preHandle方法;

    // 对拦截器链preHandle的调用
    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
        return;
    }

4、handler通过adapter进行调用,主要进行参数值的匹配和注入

    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

5、渲染视图

    //进行视图的渲染
    applyDefaultViewName(processedRequest, mv);

6、调用拦截器postHandle方法(逆序调用)

    //调用拦截器链的postHandle方法
    mappedHandler.applyPostHandle(processedRequest, response, mv);

7、对正常完成的部分拦截器调用afterCompletion;例如

拦截器1 --> 拦截器2 --> 拦截器3 …
拦截器3抛出异常
afterCompletion的调用过程
拦截器2 --> 拦截器1 …

这里拦截器调用有三种情况:
1、对于拦截器返回false的情况,直接返回,不调用postHandle和afterCompletion方法;
2、对于中间拦截器抛出异常,对于成功执行的拦截器,反序调用其afterCompletion方法;
3、如果拦截器成功执行,所有拦截器的afterCompletion反序调用
即按照成功执行preHandle方法后的拦截器逆序调用。

猜你喜欢

转载自blog.csdn.net/lidelin10/article/details/100033302
今日推荐