springmvc执行流程原理分析(三)

一、DispatcherServlet执行流程及相关源码分析

1、springmvc时序图

在这里插入图片描述
1、用户请求发送至DispatcherServlet类进行处理。
2、DispatcherServlet类遍历所有配置的HandlerMapping类请求查找Handler
3、HandlerMapping类根据request请求的URL等信息查找能够进行处理的Handler,以及相关拦截器interceptor并构造HandlerExecutionChain
4、HandlerMapping类将构造的HandlerExecutionChain类的对象返回给前端控制器DispatcherServlet类。
5、前端控制器拿着上一步的Handler遍历所有配置的HandlerAdapter类请求执行Handler
6、HandlerAdapter类执行相关Handler并获取ModelAndView类的对象。
7、HandlerAdapter类将上一步Handler执行结果的ModelAndView 类的对象返回给前端控制器。
8、DispatcherServlet类遍历所有配置的ViewResolver类请求进行视图解析。
9、ViewResolver类进行视图解析并获取View对象。
10、ViewResolver类向前端控制器返回上一步骤的View对象。
11、DispatcherServlet类进行视图View的渲染,填充Model。
12、DispatcherServlet类向用户返回响应。

Spring MVC的四大组件:DispatcherServletHandlerMappingHandlerAdapter以及ViewResolver

2、打开DispatcherServlet.class的源码

  • DispatcherServlet入口doService()方法
@Override
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {

/*
        将当前Servlet的子IoC容器放入request请求中
        由此,我们可以访问到当前IoC子容器以及根IoC容器中的Bean
        */
        request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
        request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

        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 {
            //真正进行用户请求的处理
            doDispatch(request, response);
        }

doService() 方法主要进行一些参数的设置,并将部分参数放入request请求中,真正执行用户请求并作出响应的方法则为doDispatch()方法

  • 分析主要业务处理的方法doDispatch
       protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //用户的request请求
        HttpServletRequest processedRequest = request;
        //HandlerExecutionChain局部变量
        HandlerExecutionChain mappedHandler = null;
        //判断是否解析了文件类型的数据,如果有最终需要清理
        boolean multipartRequestParsed = false;

        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
            //ModelAndView局部变量
            ModelAndView mv = null;
            //处理异常局部变量
            Exception dispatchException = null;

            try {
                //检查是否包含文件等类型的数据
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);

                // Determine handler for the current request.
                //向HandlerMapping请求查找HandlerExecutionChain
                mappedHandler = getHandler(processedRequest);
                //如果HandlerExecutionChain为null,则没有能够进行处理的Handler,抛出异常
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // Determine handler adapter for the current request.
                //根据查找到的Handler请求查找能够进行处理的HandlerAdapter
                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;
                    }
                }
                
                /*
                按顺序依次执行HandlerInterceptor的preHandle方法
                如果任一HandlerInterceptor的preHandle方法没有通过则不继续进行处理
                */
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }

                // Actually invoke the handler.
                //通过HandlerAdapter执行查找到的handler
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

                applyDefaultViewName(processedRequest, mv);
                //逆序执行HandlerInterceptor的postHandle方法
                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);
            }
            //渲染视图填充Model,如果有异常渲染异常页面
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            //如果有异常按倒序执行所有HandlerInterceptor的afterCompletion方法
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Throwable err) {
            //如果有异常按倒序执行所有HandlerInterceptor的afterCompletion方法
            triggerAfterCompletion(processedRequest, response, mappedHandler,
                    new NestedServletException("Handler processing failed", err));
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                // Instead of postHandle and afterCompletion
                if (mappedHandler != null) {
                    //倒序执行所有HandlerInterceptor的afterCompletion方法
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            }
            else {
                // Clean up any resources used by a multipart request.
                //如果请求包含文件类型的数据则进行相关清理工作
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }
    }

doDispatch()方法通过调用getHandler()方法并传入reuqest通过HandlerMapping查找HandlerExecutionChain

  • getHandler()源码如下
  protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        for (HandlerMapping hm : this.handlerMappings) {
            if (logger.isTraceEnabled()) {
                logger.trace(
                        "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
            }
            HandlerExecutionChain handler = hm.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
        return null;
    }

1)getHandler()方法遍历了开发者配置的所有HandlerMapping类,springmvc拥有多个HandlerMapping类;springmvc默认包含SimpleUrlHandlerMappingBeanNameUrlHandlerMapping两种处理器映射器类;

2)处理用户请求时逐一查找用户配置的所有HandlerMapping类,找到后立即返回跳出for (HandlerMapping hm : this.handlerMappings)循环,故最后只会返回第一个能够处理的HandlerMapping类构造用户请求的HandlerExecutionChain

3)注意:在配置HandlerMapping类时需要注意不要对同一请求多次进行处理,即只配置一种HandlerMapping类即可。

  • 没有获取到HandlerExecutionChain 对象,会执行noHandlerFound()方法
 protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (pageNotFoundLogger.isWarnEnabled()) {
            pageNotFoundLogger.warn("No mapping found for HTTP request with URI [" + getRequestUri(request) +
                    "] in DispatcherServlet with name '" + getServletName() + "'");
        }
        if (this.throwExceptionIfNoHandlerFound) {
            throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request),
                    new ServletServerHttpRequest(request).getHeaders());
        }
        else {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
        }
    }

若没有找到对应的HandlerExecutionChain 则会抛出异常NoHandlerFoundException

  • 获取到HandlerExecutionChain 后DispatcherServlet会调用getHandlerAdapter()方法来查找能够对Handler进行处理的HandlerAdapter
    DispatcherServlet.classgetHandlerAdapter()方法源码:
 // Determine handler adapter for the current request.
                //根据查找到的Handler请求查找能够进行处理的HandlerAdapter
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        for (HandlerAdapter ha : this.handlerAdapters) {
            if (logger.isTraceEnabled()) {
                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");
    }

1)遍历所有的HandlerAdapter类,springmvc默认有以下几种适配器:HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、RequestMappingHandlerAdapter
2)HandlerAdapter类是一个接口包含一个supports()方法,该方法用来判断当前遍历得到的HandlerAdapter类是否有处理当前处理器类请求的资格来得到方法的返回值,如果具备此资格,则返回当前的HandlerAdapter类,不行则继续遍历;
3)注意:HttpRequestHandlerAdapter只能 处理 实现了org.springframework.web.HttpRequestHandler接口的处理器类               SimpleControllerHandlerAdapter只能 处理 实现了org.springframework.web.servlet.mvc.Controller接口的处理器类

  /*
                按顺序依次执行HandlerInterceptor的preHandle方法
                如果任一HandlerInterceptor的preHandle方法没有通过则不继续进行处理
                */
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }

HandlerInteceptor的preHandle()方法源码

 void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
        HandlerInterceptor[] interceptors = getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            for (int i = interceptors.length - 1; i >= 0; i--) {
                HandlerInterceptor interceptor = interceptors[i];
                interceptor.postHandle(request, response, this.handler, mv);
            }
        }
    }

判断获取的HandlerExecutionChain 处理器执行链对象是否符合任一HandlerInterceptor的preHandle方法顺利通过这一条件,如果通过了则就绪向下执行。

  • HandlerExecutionChain 没有问题以及获取了HandlerAdapter对象后,继续调用processDispatchResult()方法
 // Actually invoke the handler.
                //通过HandlerAdapter执行查找到的handler
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

                applyDefaultViewName(processedRequest, mv);
                //逆序执行HandlerInterceptor的postHandle方法
                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);
            }
            //渲染视图填充Model,如果有异常渲染异常页面
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
  • processDispatchResult()源码,此步骤是在通过控制器执行逻辑顺利执行后获取到了ModelAndView视图后执行,主要作用是渲染视图并填充model:
 private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
            HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {

        boolean errorView = false;
        //判断HandlerMapping、HandlerAdapter处理时的异常是否为空
        if (exception != null) {
            //上述两个组件处理时的异常不为空
            //如果为ModelAndViewDefiningException异常,则获取一个异常视图
            if (exception instanceof ModelAndViewDefiningException) {
                logger.debug("ModelAndViewDefiningException encountered", exception);
                mv = ((ModelAndViewDefiningException) exception).getModelAndView();
            }
            //如果不为ModelAndViewDefiningException异常,进行异常视图的获取
            else {
                Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
                mv = processHandlerException(request, response, handler, exception);
                errorView = (mv != null);
            }
        }

        // Did the handler return a view to render?
        //判断mv是否为空,不管是正常的ModelAndView还是异常的ModelAndView,只要存在mv就进行视图渲染
        if (mv != null && !mv.wasCleared()) {
            render(mv, request, response);
            if (errorView) {
                WebUtils.clearErrorRequestAttributes(request);
            }
        }
        //否则记录无视图
        else {
            if (logger.isDebugEnabled()) {
                logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
                        "': assuming HandlerAdapter completed request handling");
            }
        }

        if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            // Concurrent handling started during a forward
            return;
        }
        //执行相关HandlerInterceptor的afterCompletion()方法
        if (mappedHandler != null) {
            mappedHandler.triggerAfterCompletion(request, response, null);
        }
    }

processDispatchResult()方法主要用于针对产生的异常来构造异常视图,接着不管视图是正常视图还是异常视图均调用render()方法来渲染。

二、总结

通过分析springmvc的执行流程的源码,我们发现springmvc的主要执行逻辑均在DispatcherServlet类中的doDispatch方法中,通过源码分析+时序图我们可以更好的理解springmvc的执行流程以及它的底层处理机制;最后奉上本文参考博客:https://www.jianshu.com/p/0f981efdfbbd

  • 查找到了对应的HandlerAdapter类后就会调用HandlerExecutionChainapplyPreHandle()方法来执行配置所有HandlerInteceptor的preHandle()方法
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值