Spring framework MVC源码阅读笔记(一)
2016-09-14 16:45
525 查看
org.springframework.web.servlet.DispatcherServlet
下图来自Spring官方文档,MVC对请求的处理流程
![](https://static.oschina.net/uploads/space/2016/0914/163949_Q3uZ_866681.jpg)
上图中Front controller由DispatcherServlet充当,负责拦截和响应请求。实际请求的处理和响应的生成由Controller完成,这里的Controller具体就是平时用@Controller注解配置的类,这些类中由@RequestMapping配置的方法对应Handler,Spring MVC提供了HandlerMapping接口用于保存请求与Handler之间的对应的关系,请求最终会交给最匹配的Handler来处理。(View template部分暂缺,还说不清)
下图为DispatcherServlet继承结构
![](https://static.oschina.net/uploads/space/2016/0914/160447_QBuM_866681.jpg)
该类根据配置拦截请求,从图片和类名可知该类就是是一个Servlet,那么普通的Servlet所用有的特性该类自然也有。
下图为Servlet配置信息,该信息来自Servlet规范(该文档非常值得一看)
![](https://static.oschina.net/uploads/space/2016/0914/161631_noZs_866681.jpg)
先看DispatcherServlet的一般配置
该类由容器负责实例化,load-on-startup为1应该是在容器启动是就加载该类。Servlet配置信息比较关注init-param节点,该节点可以为Servlet提供一些参数,通过复写init方法可以获得,DispatcherServlet的属性也是通过这个方式配置的,其具体实现在祖先类HttpServletBean中找到,不过之前平时使用时从来没配过。
自定义的Servlet通常会继承javax.servlet.http.HttpServlet然后根据需要复写不同的方法,DispatcherServlet只复写了doService方法,其他的都交由祖先类处理。
以下是doService的具体实现
DispatcherServlet中维护了一个(或不止一个Map)用于保存处理者和请求之间的对于关系,从中获取最匹配的Handler来处理请求,如果找不到大概就会返回404的错误。以下为挑选Handler及实际处理请求实现:
未完,待续……
下图来自Spring官方文档,MVC对请求的处理流程
![](https://static.oschina.net/uploads/space/2016/0914/163949_Q3uZ_866681.jpg)
上图中Front controller由DispatcherServlet充当,负责拦截和响应请求。实际请求的处理和响应的生成由Controller完成,这里的Controller具体就是平时用@Controller注解配置的类,这些类中由@RequestMapping配置的方法对应Handler,Spring MVC提供了HandlerMapping接口用于保存请求与Handler之间的对应的关系,请求最终会交给最匹配的Handler来处理。(View template部分暂缺,还说不清)
下图为DispatcherServlet继承结构
![](https://static.oschina.net/uploads/space/2016/0914/160447_QBuM_866681.jpg)
该类根据配置拦截请求,从图片和类名可知该类就是是一个Servlet,那么普通的Servlet所用有的特性该类自然也有。
下图为Servlet配置信息,该信息来自Servlet规范(该文档非常值得一看)
![](https://static.oschina.net/uploads/space/2016/0914/161631_noZs_866681.jpg)
先看DispatcherServlet的一般配置
<web-app> <servlet> <servlet-name>example</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>example</servlet-name> <url-pattern>/example/*</url-pattern> </servlet-mapping> </web-app>
该类由容器负责实例化,load-on-startup为1应该是在容器启动是就加载该类。Servlet配置信息比较关注init-param节点,该节点可以为Servlet提供一些参数,通过复写init方法可以获得,DispatcherServlet的属性也是通过这个方式配置的,其具体实现在祖先类HttpServletBean中找到,不过之前平时使用时从来没配过。
自定义的Servlet通常会继承javax.servlet.http.HttpServlet然后根据需要复写不同的方法,DispatcherServlet只复写了doService方法,其他的都交由祖先类处理。
以下是doService的具体实现
@Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { if (logger.isDebugEnabled()) { String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : ""; logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed + " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]"); } // Keep a snapshot of the request attributes in case of an include, // to be able to restore the original attributes after the include. //总而言之先保存下request携带的属性,从代码可以看出只保留了MVC相关的属性 Map<String, Object> attributesSnapshot = null; if (WebUtils.isIncludeRequest(request)) { attributesSnapshot = new HashMap<>(); Enumeration<?> attrNames = request.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = (String) attrNames.nextElement(); if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) { attributesSnapshot.put(attrName, request.getAttribute(attrName)); } } } // Make framework objects available to handlers and view objects. //为request添加一些属性,在真正负责处理请求的代码使用(?) request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); //Flash相关,暂时不管 FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); } request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); try { //实际转发请求的代码 doDispatch(request, response); } finally { if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Restore the original attribute snapshot, in case of an include. if (attributesSnapshot != null) { restoreAttributesAfterInclude(request, attributesSnapshot); } } } }
DispatcherServlet中维护了一个(或不止一个Map)用于保存处理者和请求之间的对于关系,从中获取最匹配的Handler来处理请求,如果找不到大概就会返回404的错误。以下为挑选Handler及实际处理请求实现:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; //看字面意思,为处理异步请求做准备,到目前为止没怎么用过异步Servlet WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { //是否为上传文件的请求,是的话先处理下 processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // Determine handler for the current request. //选择具体的Handler mappedHandler = getHandler(processedRequest); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. //关于HTTP协议中缓存的部分,对于动态生成的内容使用缓存不熟 String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isDebugEnabled()) { logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { // As of 4.3, we're processing Errors thrown from handler methods as well, // making them available for @ExceptionHandler methods and other scenarios. dispatchException = new NestedServletException("Handler dispatch failed", err); } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err)); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }
//逻辑不复杂,就是从Map中获取Handler,至于该Map是如何维护的还要再看 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; }
未完,待续……
相关文章推荐
- spring-mvc源码阅读(二)<mvc:annotation-driven/>做了什么
- [java,spring] spring 源码阅读笔记1
- spring-mvc源码阅读(三)RequestMappingHandlerMapping
- SpringMVC+Spring阅读笔记——SpringMVC概览
- Spring-Framework 源码阅读之AnnotationBeanUtils
- Spring-Framework 源码阅读之@Autowired和AutowiredAnnotationBeanPostProcessor
- Spring 源码阅读笔记(一)
- spring mvc 源代码笔记1--org.springframework.web.servlet.mvc.method
- spring-framework-4.1.x源码阅读环境搭建(导入Eclipse)
- Spring源码阅读笔记
- spring-framework-reference阅读笔记(一)
- spring-framework-4.1.x源码阅读环境搭建(导入Eclipse)
- spring源码阅读笔记(二)——自定义标签
- Spring事务源码阅读笔记
- spring-framework-4.1.x源码阅读环境搭建(导入Eclipse)
- spring源码阅读笔记
- Spring源码阅读笔记(待补充)
- spring-mvc源码阅读(一)servlet
- spring源码阅读笔记(一)
- Spring源码阅读笔记