SpringMVC doDispatch方法的基本思路梳理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010412719/article/details/79068994

SpringMVC doDispatch方法的基本思路梳理

在分析之前,先介绍一个类

1、HandlerExecutionChain

    public class HandlerExecutionChain {
        private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
        private final Object handler;
        private HandlerInterceptor[] interceptors;
        private List<HandlerInterceptor> interceptorList;
        private int interceptorIndex;

该类中主要包括了一个用于处理request的handler,以及和request相关的一系列拦截器interceptors.

进入正题,doDispatch方法的代码如下:

    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;
                    /*
                    分析1,其目的是:得到包含了用于处理request的HandlerMethod、Interceptors。
                    */
                    mappedHandler = this.getHandler(processedRequest, false);
                    //如果没有,则说明没有处理器能够处理该request,因此返回404错误。
                    if(mappedHandler == null || mappedHandler.getHandler() == null) {
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }
                        /*
                        分析2,其目的是:得到与Handler匹配的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;
                        }
                    }
                        /*
                        分析3:执行所有注册拦截器的preHandler方法
                        */
                    if(!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }

                    try {
                    //前面的第一步就是找到用于处理request的handler,到这里才真正意思上的执行用于处理request的handler方法。具体后面进行分析
                        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    } finally {
                        if(asyncManager.isConcurrentHandlingStarted()) {
                            return;
                        }

                    }

                    this.applyDefaultViewName(request, mv);
                    /*
                    分析4:执行所有注册拦截器的postHandler方法
                    */
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var27) {
                    dispatchException = var27;
                }

                this.processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
            } catch (Exception var28) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var28);
            } catch (Error var29) {
                this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, var29);
            }

        } finally {
            if(asyncManager.isConcurrentHandlingStarted()) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                return;
            } else {
                if(multipartRequestParsed) {
                    this.cleanupMultipart(processedRequest);
                }

            }
        }
    }

doDispatch方法主要逻辑如下:

1)找到用于处理request的handler和interceptors,构造成一个HandlerExecutionChain.

2) 找到与用于处理request的handler相匹配的HandlerAdapter,目的是:后续将使用此HandlerAdapter来执行handler。

3)执行所有注册拦截器的preHandler方法

4)真正意思上的执行用于request的handler方法,得到ModelAndView

5)倒序执行所有注册拦截器的postHandler方法。

6)解析并返回ModelAndView

主要是理清思路,本篇博文将依次分析除第4点之外的几点。

分析1:找到用于处理request的handler和interceptors,构造成一个HandlerExecutionChain.

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

该函数的功能为:遍历DispatcherServlet中的private List handlerMappings; 看哪个HandlerMapping能够处理该request,则返回由

AbstractHandlerMapping.java

    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        Object handler = getHandlerInternal(request);//第一步
        if (handler == null) {
            handler = getDefaultHandler();
        }
        if (handler == null) {
            return null;
        }
        // Bean name or resolved handler?
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = getApplicationContext().getBean(handlerName);
        }
        //第二步
        return getHandlerExecutionChain(handler, request);
    }

此方法的主要逻辑如下:

第一步:根据request中的url得到相应的handler,此handler为HandlerMethod的实例。

第二步:将第一步得到的HandlerMethod作为参数实例化一个HandlerExecutionChain对象。在实例化过程中,还需要得到与request相关的Interceptors。

下面将逐一的分析这两步所涉及到具体实现。

先看第一步:根据request中的url得到相应的handler,此handler为HandlerMethod的实例

getHandlerInternal方法的代码如下:

    AbstractHandlerMethodMapping.java   

    @Override
    protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        if (logger.isDebugEnabled()) {
            logger.debug("Looking up handler method for path " + lookupPath);
        }
        //得到与request相关的handlerMethod,如何得到的,就是在Map中来寻找
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        if (logger.isDebugEnabled()) {
            if (handlerMethod != null) {
                logger.debug("Returning handler method [" + handlerMethod + "]");
            }
            else {
                logger.debug("Did not find handler method for [" + lookupPath + "]");
            }
        }
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }   

getHandlerInternal函数的功能:就是在Map中寻找HandlerMethod方法。Map中保存的是<url,HandlerMethod>,Map中的内容如何来的呢:是在容器初始化时会建立所有url和controller的对应关系,保存到Map

    protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
        HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
                (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
        chain.addInterceptors(getAdaptedInterceptors());

        String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
        for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) {
            if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        }

        return chain;
    }

其中,private final List<MappedInterceptor> mappedInterceptors =
new ArrayList<MappedInterceptor>();
中保存的是我们项目配置文件配置的拦截器。

分析2:找到与用于处理request的handler相匹配的HandlerAdapter

DispatcherServlet.java

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

该getHandlerAdapter函数的功能为:判断private List<HandlerAdapter> handlerAdapters;中哪个Adapter能支持这个handler。或者说,这个handler应该与哪个Adapter进行搭档才能正常工作。

从Debug的情况来看,如果我们采用的是@RequestMapping注解形式,则获取到的是HandlerAdapter 是RequestMappingHandlerAdapter类的一个实例。

以下就是RequestMappingHandlerAdapter的support方法的实现,即只要此时的handler为HandlerMethod的实例,就是支持的。

    AbstractHandlerMethodAdapter.java
    public final boolean supports(Object handler) {
        return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
    }
    RequestMappingHandlerAdapter    
    protected boolean supportsInternal(HandlerMethod handlerMethod) {
        return true;
    }

分析3:执行所有注册拦截器的preHandler方法

    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HandlerInterceptor[] interceptors = getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            for (int i = 0; i < interceptors.length; i++) {
                HandlerInterceptor interceptor = interceptors[i];
                if (!interceptor.preHandle(request, response, this.handler)) {
                    triggerAfterCompletion(request, response, null);
                    return false;
                }
                this.interceptorIndex = i;//interceptorIndex标示着拦截器数组中下标小于等于interceptorIndex的拦截器已经被成功执行。
            }
        }
        return true;
    }

该函数的功能为:调用所有注册拦截器的preHandle方法,如果preHandle方法的返回结果为true,则会继续执行下面的程序。如果preHandler方法返回false,则调用triggerAfterCompletion方法。该方法的代码如下:

    void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
            throws Exception {

        HandlerInterceptor[] interceptors = getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            for (int i = this.interceptorIndex; i >= 0; i--) {
                HandlerInterceptor interceptor = interceptors[i];
                try {
                    interceptor.afterCompletion(request, response, this.handler, ex);
                }
                catch (Throwable ex2) {
                    logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
                }
            }
        }
    }

从代码中可以看到:triggerAfterCompletion方法它会调用所有已经成功执行的拦截器的afterCompletion方法,而且是反序调用的过程。

以上可以得到的结论为:

1)只有所有注册的拦截器都执行成功,即都返回true,则doDispathcer中的代码才会继续执行。

2)如果第i个拦截器返回false,则会触发triggerAfterCompletion方法来反序执行刚刚所有已经成功执行的拦截器的afterCompletion方法。并返回false从而使得doDispatcher中的代码就不会往下执行了。

看到这里,我们也就明白了拦截器的作用。

分析4:倒序执行所有注册拦截器的postHandler方法

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

该函数的功能:反序执行所有注册的拦截器的postHandler方法,比较简单哈。

小结

就这样我们稍微理清了下doDispatch这个方法的基本思路,有很多细节,博文中并没有关注,如果你有兴趣,可以仔细研究。

========================漂亮的分割线========================

博文的以上部分可以看作是SpringMVC用于处理Http请求的运行主线的源码分析。而没有分析初始化主线。在看了这篇博文之后(http://downpour.iteye.com/blog/1341459),感觉对SpringMVC的初始化主线又多了一份了解。

总结如下:

1、基于框架所编写的应用程序的构成三要素。

a)入口程序DispatcherServlet,在web.xml文件中定义。

b)核心配置文件,[servlet-name]-servlet.xml文件。里面定义了相关组件。

c)控制逻辑,Controller。

2、框架的具体实现。

有两条主线。

a)初始化主线 -- 负责对SpringMVC的运行要素进行初始化。

b)用于处理http请求的运行主线 -- 负责对SpringMVC中的组件进行逻辑调度完成对Http请求的处理。

这两条主线的划分是根据servlet中的init方法和service方法来的,这两个方法的运行时间和触发条件截然不同。其中,init方法在整个系统启动时运行,且只运行一次。因此,在init方法中我们往往会对整个应用程序进行初始化操作。而service方法在整个系统运行的过程中一直处于监听模式,侦听并处理所有的web请求。

SpringMVC的整个运行体系,是由DispatcherServlet、组件和容器这三者共同构成的。 既然是三个元素之间的关系表述,我们必须以两两关系的形式进行归纳:

DispatcherServlet - 容器 —— DispatcherServlet负责对容器进行初始化,初始化的依据是核心配置文件

容器 - 组件 —— 容器对组件进行全局管理

DispatcherServlet - 组件 —— DispatcherServlet对组件进行逻辑调用

2.1)初始化主线。

首先要明确3个观点。

a)初始化主线的驱动方法:init().

b) 初始化主线的执行次序(根据DispatcherServlet的继承结构而来):HttpServletBean–>FrameworkServlet–>DispatherServlet.

c) 初始化主线的操作对象:Spring容器(WebApplicatonContext)以及组件.

(配图)

2.2)用于处理http请求的运行主线。

(配图)

猜你喜欢

转载自blog.csdn.net/u010412719/article/details/79068994