DispatcherServlet的详细执行流程

DispatcherServlet源码分析

以下是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 {
        ModelAndView mv = null;
        Exception dispatchException = null;

        try {
            /* 检查是否为文件上传请求,如果是,就返回一个装饰对象 */
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            // Determine handler for the current request.
            //2-1. 根据当前请求地址找到 那个能处理此请求的类(加了Controller注解的类)
            mappedHandler = getHandler(processedRequest);
            //如果找不到就404
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            // Determine handler adapter for the current request.
            //2-2. 拿到能执行这个类所有方法的适配器(反射工具)。
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            // Process last-modified header, if supported by the handler.
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (logger.isDebugEnabled()) {
                    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;
            }

            // Actually invoke the handler.
            //2-3. 让适配器去执行目标方法(加了RequestMapping注解的方法),将目标方法执行后的返回值作为视图名 并保存到ModelAndView中。(无论方法的返回值怎么写,适配器最后都会把执行后的结果封装成ModelAndView)
            /* ha就是“2-2”得到的适配器 */ 
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }

            applyDefaultViewName(processedRequest, mv);
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex) {
            dispatchException = ex;
        }
        catch (Throwable err) {
            // As of 4.3, we're processing Errors thrown from handler methods as well,
            // making them available for @ExceptionHandler methods and other scenarios.
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }
        /* 转发到目标页面 */ 
        //2-4. 根据方法最终执行后封装的ModelAndView 转发到对应页面。(ModelAndView中的数据可以从请求域中获取)
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex) {
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Throwable err) {
        triggerAfterCompletion(processedRequest, response, mappedHandler,
                new NestedServletException("Handler processing failed", err));
    }
    finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            // Instead of postHandle and afterCompletion
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        }
        else {
            // Clean up any resources used by a multipart request.
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }
}

总结(执行流程,以注解为例):

  1. DispatcherServlet拦截到所有请求。

  2. DispatcherServlet调用自己的doDispatch()方法处理这个请求。处理流程:

    1. 调用自己的getHandler()方法: 根据当前的请求地址找到能处理这个请求的 目标处理器类(就是加了Controller注解的类)。

    2. 然后,调用自己的getHandlerAdapter()方法: 根据当前的处理器类,获取能执行这个 处理器方法(加了RequestMapping注解的方法)的适配器(HandlerAdapter)。

    3. 再然后,调用适配器(RequestMappingHandlerAdapter)对象ha的handle()方法: 让获取到的适配器 执行目标方法,并返回一个ModelAndView对象。

    4. 最后,根据返回ModelAndView对象的信息转发到具体页面。此ModelAndView中的模型数据可以在request中取出。
      DispatcherServlet的执行流程



getHandler()是如何找到目标类的

答案点这里

ioc容器启动时会把每个组件对象创建出来,在创建Controller对象时,spring会扫描每个处理器的配置信息(这些信息通常是在配置文件或注解上),然后spring就知道每个处理器都能处理什么请求,并把这些信息存入一个叫handlerMappings的集合中(HandlerMapping是一个接口,与Map没有关系)。

接上,为什么是集合呢?因为spring在扫描Controller的时候,会根据配置信息的来源把这些信息存入到不同的HandlerMapping中(来自配置文件的信息就存入BeanNameUrlHandlerMapping对象中,来自注解的信息就存入DefaultAnnotationHandlerMapping对象中)。
BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping都有一个名为“handlerMap”的属性。handlerMap是一个map,处理请求的方法与请求地址 的映射信息就在这个map中。
在这里插入图片描述

总结: getHandler()会遍历handlerMappings集合中的HandlerMapping实现类,然后查看每个实现类中的handleMap 是否有目标请求的映射信息。如果有就返回带有目标类信息的handler对象;如果没有就报404

发布了10 篇原创文章 · 获赞 13 · 访问量 431

猜你喜欢

转载自blog.csdn.net/hufuzhi1146231094/article/details/103074676
今日推荐