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的那些事
- springMVC执行流程
- springmvc执行流程
- SpringMVC执行流程
- springMVC的执行流程
- SpringMVC执行流程
- SpringMvc的执行流程
- SpringMvc的执行流程
- springMVC应用程序执行流程
- SpringMVC执行的流程
- SpringMVC执行流程
- springMVC的执行流程
- springMVC执行流程详解
- SpringMVC执行流程
- SpringMVC执行流程
- SpringMVC执行流程
- springmvc执行流程
- springMVC的执行流程
- SpringMVC的执行流程
- python3 读中文txt文件提示 'gbk' codec can't decode byte 0x80 ...或 'gbk' codec can't encode character '\xX问题
- ubuntu16.04 安装jre
- 8D模拟
- Android 图形系统之gralloc
- css动画停在最后状态
- springMVC 执行流程
- HDU 6138 Fleet of the Eternal Throne AC自动机
- Idea导入项目及部署至Tomcat(从Eclipse到Idea的华丽转身)
- 关于jedis异常:Could not get a resource from the pool
- Thinkphp5 出现错误 require mongodb > 1.0
- DrawerLayout侧滑栏
- OPENGL学习笔记之三
- 关于V4L2编程中获取视频流的误区
- hdu4460-最短路&思维- Friend Chains