springMVC 执行流程

这里写图片描述

分析:
dispatcherServlet配置在web.xml中,一般都是分发所有请求。发送一个请求进入到dispatcherServlet的doDispatcher函数中

// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);

进入到getHandler,

/**
     * Return the HandlerExecutionChain for this request.
     * <p>Tries all handler mappings in order.
     * @param request current HTTP request
     * @return the HandlerExecutionChain, or {@code null} if no handler could be found
     */
    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;
    }

可以看出mappedHandler 是一个HandlerExecutionChain。
什么是HandlerExecutionChain?JavaDoc解释:Handler execution chain, consisting of handler object and any handler interceptors.

这个HandlerExecutionChain是由HandlerMapping 获取到的。

什么是HandlerMapping ?解释:Interface to be implemented by objects that define a mapping between requests and handler objects

此时的handlerMapping里有什么?
这里写图片描述

getHandler()方法执行后 得到HandlerExecutionChain里的handler是你请求的控制器。

注意:如果发送的请求没有经过映射如a.html,mappedHandler 不为null.因为配置了

<mvc:default-servlet-handler />

靠的是handlerMapping里的simpleUrlHandlerMapping(认为请求的是静态资源),得到HandlerExecutionChain里的handler是DefaultServletHttpRequesthandler
如果没有这个配置 则为null.

接下来获取HandlerAdapter

// Determine handler adapter for the current request.
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

解释:Interface that must be implemented for each handler type to handle a request

然后执行

    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
        }
/**
     * Apply preHandle methods of registered interceptors.
     * @return {@code true} if the execution chain should proceed with the
     * next interceptor or the handler itself. Else, DispatcherServlet assumes
     * that this interceptor has already dealt with the response itself.
     */
    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;
    }

这个方法applyPreHandle()调用了拦截器的preHandler

接下来调用目标方法,执行HandlerAdapter对象的handle方法
HandlerAdapter作用:接过handlermapping解析请求得到的handler对象。在更精确的定位到能够执行请求的方法。而且在调用目标方法过程中发生很多事情,如表单数据类型校验,数据类型的转换 ,格式化等

// Actually invoke the handler.
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

三个参数分别为 请求(request current HTTP request),响应( response current HTTP response) ,映射的控制器(handler handler to use),返回一个ModelAndView

继承HandlerAdapter接口的有
这里写图片描述
我这里进入到AbstractHandlerMethodAdapter。里面有handleInternal方法。Use the given handler method to handle the request.

然后通过mappedHandler调用拦截器postHandle方法。

    mappedHandler.applyPostHandle(processedRequest, response, mv);
/**
     * Apply postHandle methods of registered interceptors.
     */
    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);
            }
        }
    }

处理视图:

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

进入processDispatchResult

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

看到 判断是否有异常,如果有,利用视图解析器processHandlerException里的HandlerExceptionResolver解析

之后渲染视图(仍在processDispatchResult方法里)


        // 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");
            }
        }
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
        // Determine locale for request and apply it to the response.
        Locale locale = this.localeResolver.resolveLocale(request);
        response.setLocale(locale);

        View view;
        if (mv.isReference()) {
            // We need to resolve the view name.
            view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
            if (view == null) {
                throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
                        "' in servlet with name '" + getServletName() + "'");
            }
        }
        else {
            // No need to lookup: the ModelAndView object contains the actual View object.
            view = mv.getView();
            if (view == null) {
                throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
                        "View object in servlet with name '" + getServletName() + "'");
            }
        }

        // Delegate to the View object for rendering.
        if (logger.isDebugEnabled()) {
            logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
        }
        try {
            view.render(mv.getModelInternal(), request, response);
        }
        catch (Exception ex) {
            if (logger.isDebugEnabled()) {
                logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
                        getServletName() + "'", ex);
            }
            throw ex;
        }
    }

在这里利用视图解析器ViewResolver得到view对象,将逻辑视图 变为物理视图。

最后调用拦截器的trigglerAfterCompletion(整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中preHandle返回true的拦截器的afterCompletion。)

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

以上是正常的流程。

如果发送一个请求,如a.html.如果在springMVC的配置文件里没有

<!-- 加载静态资源 -->
<mvc:default-servlet-handler />

则404. 必须有这个配置 而且view里有这个文件才可以。

如果你配置了

<mvc:default-servlet-handler />

则必须配置

<!-- 配置返回信息编码格式 -->
    <mvc:annotation-driven>
        <mvc:message-converters>
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <value>text/plain; charset=UTF-8</value>
                        <value>text/json; charset=UTF-8</value>
                        <value>text/html; charset=UTF-8</value>
                        <value>application/json; charset=UTF-8</value>
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

不然 controller无法进入。参考这个:mvc:annotation-driven以及@Controller和@RequestMapping的那些事

发布了53 篇原创文章 · 获赞 5 · 访问量 8万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章