SpringMVC请求处理过程浅析

这里写图片描述

上图完整描绘了SpringMVC的请求处理过程,可以看到,此过程都是以DispatcherServlet为中轴线进行的,而具体的处理逻辑在DispatcherServlet的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 {
            ModelAndView mv = null;
            Exception dispatchException = null;

            try {
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);

                mappedHandler = getHandler(processedRequest);

                ……

                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                ……

                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }

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

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

                applyDefaultViewName(processedRequest, mv);
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            ……
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        ……
    }

1,调用getHandler方法,根据请求request信息寻找对应的Handler,调用链如下:

    DispatcherServlet.getHandler()
        -->AbstractHandlerMapping.getHandler()
            -->AbstractUrlHandlerMapping.getHandlerInternal()
                -->AbstractUrlHandlerMapping.getHandlerExecutionChain()

以SimpleUrlHandlerMapping为例分析,顾名思义,此步骤的步骤就是根据请求URL找到匹配的Controller,并通过getgetHandlerExecutionChain方法对返回的Handler进行封装,以保证满足返回类型的匹配。先看一下getHandlerInternal方法,

protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        //根据请求路径寻找handler
        Object handler = lookupHandler(lookupPath, request);
        if (handler == null) {
            Object rawHandler = null;
            if ("/".equals(lookupPath)) {
                rawHandler = getRootHandler();
            }
            if (rawHandler == null) {
                rawHandler = getDefaultHandler();
            }
            if (rawHandler != null) {
                // Bean name or resolved handler?
                if (rawHandler instanceof String) {
                    String handlerName = (String) rawHandler;
                    rawHandler = obtainApplicationContext().getBean(handlerName);
                }
                validateHandler(rawHandler, request);
                //将Handler封装成HandlerExecutionChain类型
                handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
            }
        }
        ……
        return handler;
    }

lookupHandler整个过程虽然比较复杂,但不难理解,考虑了直接匹配与通配符两种情况,再看一下将Handler封装成HandlerExecutionChain的过程。

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

        String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
        for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
            if (interceptor instanceof MappedInterceptor) {
                MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
                if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                    chain.addInterceptor(mappedInterceptor.getInterceptor());
                }
            }
            else {
                chain.addInterceptor(interceptor);
            }
        }
        return chain;
    }

通过将Handler以参数形式传入,并构建HandlerExecutionChain类型实例,并加入事先配置的拦截器。

2,根据当前Handler寻找对应的HandlerAdapter

笔者曾经很疑惑,既然handler都有了,直接调用处理方法不就可以了,为什么又多出来一个HandrAdapter。其实这正是适配器模式的体现,通过URL匹配的Handler类型千变万化,通过加入适配器,将不同类型Handler的调用过程统一化,体现了面向对象编程中的开闭原则——对扩展开发、对修改关闭。
默认情况下,SpringMVC支持HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、AnnotationMethodHandlerAdapter三种适配器。

    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        if (this.handlerAdapters != null) {
            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");
    }

3,HandlerInterceptor处理

SpringMVC允许通过处理拦截Web请求,进行前置处理和后置处理,需要注意的是,一般情情况下,两者的处理顺序相反。

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

    /**
     * Apply postHandle methods of registered interceptors.
     */
    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable 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);
            }
        }
    }

4,逻辑处理

逻辑处理其实是通过适配器中转调用Handler并返回视图,对应代码:

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

5,后处理

对于上述逻辑处理结果的处理,也许有异常,也许有正常ModelAndView对象返回,都在processDispatchResult方法中,其中包含了两个步骤:1,异常视图的处理;2,解析视图并跳转页面。

    private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
            @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
            @Nullable Exception exception) throws Exception {

        boolean errorView = false;

        if (exception != null) {
            if (exception instanceof ModelAndViewDefiningException) {
                logger.debug("ModelAndViewDefiningException encountered", exception);
                mv = ((ModelAndViewDefiningException) exception).getModelAndView();
            }
            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?
        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;
        }

        if (mappedHandler != null) {
            mappedHandler.triggerAfterCompletion(request, response, null);
        }
    }

以上是SpringMVC处理请求的大致过程,笔者忽略了一些异常处理场景,重点关注核心流程,希望对读者有所帮助。

猜你喜欢

转载自blog.csdn.net/tjreal/article/details/79706544
今日推荐