源码深度解析SpringMvc请求运行机制(转)

源码深度解析SpringMvc请求运行机制

本文依赖的是springmvc4.0.5.RELEASE,通过源码深度解析了解springMvc的请求运行机制。通过源码我们可以知道从客户端发送一个URL请求给springMvc开始,到返回数据给客户端期间是怎么运转的。

1、用户请求处理过程:

1、用户发送请求时会先从DispathcherServler的doService方法开始,在该方法中会将ApplicationContext、localeResolver、themeResolver等对象添加到request中,紧接着就是调用doDispatch方法:

源码:

[java] view plaincopyprint?

  1. protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
  2. if (logger.isDebugEnabled()) {
  3. String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
  4. logger.debug("DispatcherServlet with name ‘" + getServletName() + "‘" + resumed +
  5. " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
  6. }
  7. // Keep a snapshot of the request attributes in case of an include,
  8. // to be able to restore the original attributes after the include.
  9. Map<String, Object> attributesSnapshot = null;
  10. if (WebUtils.isIncludeRequest(request)) {
  11. attributesSnapshot = new HashMap<String, Object>();
  12. Enumeration<?> attrNames = request.getAttributeNames();
  13. while (attrNames.hasMoreElements()) {
  14. String attrName = (String) attrNames.nextElement();
  15. if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
  16. attributesSnapshot.put(attrName, request.getAttribute(attrName));
  17. }
  18. }
  19. }
  20. // Make framework objects available to handlers and view objects.
  21. <strong>request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
  22. request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
  23. request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
  24. request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());</strong>
  25. FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
  26. if (inputFlashMap != null) {
  27. request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
  28. }
  29. request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
  30. request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
  31. try {
  32. <strong>doDispatch(request, response);</strong>
  33. }
  34. finally {
  35. if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
  36. return;
  37. }
  38. // Restore the original attribute snapshot, in case of an include.
  39. if (attributesSnapshot != null) {
  40. restoreAttributesAfterInclude(request, attributesSnapshot);
  41. }
  42. }
  43. }

doDispatch方法就是处理用户请求的方法。

2、进入该方法后首先会检查该请求是否是文件上传的请求(校验的规则是是否是post并且contenttType是否为multipart/为前缀)即调用的是checkMultipart方法;如果是的将request包装成MultipartHttpServletRequest。见源码:

doDispatch:

[java] view plaincopyprint?

  1. processedRequest = checkMultipart(request);

checkMultipart:

[java] view plaincopyprint?

  1. protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
  2. if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
  3. if (request instanceof MultipartHttpServletRequest) {
  4. logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " +
  5. "this typically results from an additional MultipartFilter in web.xml");
  6. }
  7. else if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) instanceof MultipartException) {
  8. logger.debug("Multipart resolution failed for current request before - " +
  9. "skipping re-resolution for undisturbed error rendering");
  10. }
  11. else {
  12. return this.multipartResolver.resolveMultipart(request);
  13. }
  14. }
  15. // If not returned before: return original request.
  16. return request;
  17. }

3、然后调用getHandler方法来匹配每个HandlerMapping对象,如果匹配成功会返回这个Handle的处理链HandlerExecutionChain对象,在获取该对象的内部其实也获取我们自定定义的拦截器,并执行了其中的方法

见源码:

doDispatch:

[java] view plaincopyprint?

  1. HandlerExecutionChain mappedHandler = null;
  2. mappedHandler = getHandler(processedRequest);

getHandler方法:

[java] view plaincopyprint?

  1. protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  2. for (HandlerMapping hm : this.handlerMappings) {
  3. if (logger.isTraceEnabled()) {
  4. logger.trace(
  5. "Testing handler map [" + hm + "] in DispatcherServlet with name ‘" + getServletName() + "‘");
  6. }
  7. HandlerExecutionChain handler = hm.getHandler(request);
  8. if (handler != null) {
  9. return handler;
  10. }
  11. }
  12. return null;
  13. }

[java] view plaincopyprint?

  1. hm.getHandler方法:

[java] view plaincopyprint?

  1. public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  2. Object handler = getHandlerInternal(request);
  3. if (handler == null) {
  4. handler = getDefaultHandler();
  5. }
  6. if (handler == null) {
  7. return null;
  8. }
  9. // Bean name or resolved handler?
  10. if (handler instanceof String) {
  11. String handlerName = (String) handler;
  12. handler = getApplicationContext().getBean(handlerName);
  13. }
  14. return getHandlerExecutionChain(handler, request);
  15. }

getHandlerExecutionChain:

[java] view plaincopyprint?

  1. protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
  2. HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
  3. (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
  4. chain.addInterceptors(getAdaptedInterceptors());
  5. String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
  6. for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) {
  7. if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
  8. chain.addInterceptor(mappedInterceptor.getInterceptor());
  9. }
  10. }
  11. return chain;
  12. }

4、执行拦截器的preHandle方法,如果返回false执行afterCompletion方法并理解返回

5、通过上述获取到了HandlerExecutionChain对象,通过该对象的getHandler()方法获得一个object通过HandlerAdapter进行封装得到HandlerAdapter对象

6、该对象调用handle方法来执行Controller中的方法,该对象如果返回一个ModelAndView给DispatcherServlet

7、DispatcherServlet借助ViewResolver完成逻辑试图名到真实视图对象的解析,得到View后DispatcherServlet使用这个View对ModelAndView中的模型数据进行视图渲染

本文转自:http://blog.csdn.net/liyantianmin/article/details/46948963

时间: 2024-10-14 02:40:42

源码深度解析SpringMvc请求运行机制(转)的相关文章

源码深度解析SpringMvc请求运行机制

本文依赖的是springmvc4.0.5.RELEASE,通过源码深度解析了解springMvc的请求运行机制.通过源码我们可以知道从客户端发送一个URL请求给springMvc开始,到返回数据给客户端期间是怎么运转的. 1.用户请求处理过程: 1.用户发送请求时会先从DispathcherServler的doService方法开始,在该方法中会将ApplicationContext.localeResolver.themeResolver等对象添加到request中,紧接着就是调用doDisp

JAVA框架底层源码剖析系列Spring,Mybatis,Springboot,Netty源码深度解析

<Spring源码深度解析>从核心实现和企业应用两个方面,由浅入深.由易到难地对Spring源码展开了系统的讲解,包括Spring的设计理念和整体架构.容器的基本实现.默认标签的解析.自定义标签的解析.bean的加载.容器的功能扩展.AOP.数据库连接JDBC.整合MyBatis.事务.SpringMVC.远程服务.Spring消息服务等内容. <Spring源码深度解析>不仅介绍了使用Spring框架开发项目必须掌握的核心概念,还指导读者如何使用Spring框架编写企业级应用,并

Spring源码深度解析pdf

下载地址:网盘下载 <Spring源码深度解析>从核心实现和企业应用两个方面,由浅入深.由易到难地对Spring源码展开了系统的讲解,包括Spring的设计理念和整体架构.容器的基本实现.默认标签的解析.自定义标签的解析.bean的加载.容器的功能扩展.AOP.数据库连接JDBC.整合MyBatis.事务.SpringMVC.远程服务.Spring消息服务等内容. <Spring源码深度解析>不仅介绍了使用Spring框架开发项目必须掌握的核心概念,还指导读者如何使用Spring框

spring源码深度解析— IOC 之 开启 bean 的加载

概述 前面我们已经分析了spring对于xml配置文件的解析,将分析的信息组装成 BeanDefinition,并将其保存注册到相应的 BeanDefinitionRegistry 中.至此,Spring IOC 的初始化工作完成.接下来我们将对bean的加载进行探索. 之前系列文章: spring源码深度解析— IOC 之 容器的基本实现 spring源码深度解析— IOC 之 默认标签解析(上) spring源码深度解析— IOC 之 默认标签解析(下) spring源码深度解析— IOC

spring5 源码深度解析----- 被面试官给虐懵了,竟然是因为我不懂@Configuration配置类及@Bean的原理

@Configuration注解提供了全新的bean创建方式.最初spring通过xml配置文件初始化bean并完成依赖注入工作.从spring3.0开始,在spring framework模块中提供了这个注解,搭配@Bean等注解,可以完全不依赖xml配置,在运行时完成bean的创建和初始化工作.例如: public interface IBean { } public class AppBean implements IBean{ } //@Configuration申明了AppConfig

Spring源码深度解析第一天

其实第一天已经过去了,今天是第二天.iteye刚注册的小号就被封了.不论是它的失误还是他的失误总之我跟iteye是没有缘分了. 昨天基本没有进展.所以从今天开始说了.下面流水账开始了. <Spring源码深度解析>这本书没有pdf完整版是让我很失望的.如果有完整版即使看完了我也会选择买一本实体如果有用的话. 书中说从github下载源码.发现github没有想象中的简单易懂.还需要记忆很多命令才能玩得转.从github上获得了Spring源码后需要使用Gradle来编译成eclipse项目.g

SPRING技术内幕,Spring源码深度解析

 SPRING技术内幕,Spring源码深度解析 SPRING技术内幕:深入解析SPRING架构与设计原理(第2版)[带书签].pdf: http://www.t00y.com/file/78131650 Spring源码深度解析 [郝佳编著] sample.pdf: http://www.t00y.com/file/78131634 [jingshuishenliu.400gb.com]Spring Data.pdf: http://www.t00y.com/file/78256084 [

iOS开发之Masonry框架源码深度解析

Masonry是iOS在控件布局中经常使用的一个轻量级框架,Masonry让NSLayoutConstraint使用起来更为简洁.Masonry简化了NSLayoutConstraint的使用方式,让我们可以以链式的方式为我们的控件指定约束.本篇博客的主题不是教你如何去使用Masonry框架的,而是对Masonry框架的源码进行解析,让你明白Masonry是如何对NSLayoutConstraint进行封装的,以及Masonry框架中的各个部分所扮演的角色是什么样的.在Masonry框架中,仔细

JVM CPU Profiler技术原理及源码深度解析

研发人员在遇到线上报警或需要优化系统性能时,常常需要分析程序运行行为和性能瓶颈.Profiling技术是一种在应用运行时收集程序相关信息的动态分析手段,常用的JVM Profiler可以从多个方面对程序进行动态分析,如CPU.Memory.Thread.Classes.GC等,其中CPU Profiling的应用最为广泛.CPU Profiling经常被用于分析代码的执行热点,如“哪个方法占用CPU的执行时间最长”.“每个方法占用CPU的比例是多少”等等,通过CPU Profiling得到上述相