springMVC 执行流程

来源:互联网 发布:web数据挖掘第二版pdf 编辑:程序博客网 时间:2024/06/06 01:41

这里写图片描述

分析:
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的那些事

原创粉丝点击