先大致分析一下启动过程,然后详细分析请求的处理过程。

因为在web.xml文件中给Spring MVC的Servlet配置了load-on-startup,所以程序启动时会初始化Spring MVC,在HttpServletBean中将配置的contextConfigLocation属性设置到Servlet中,然后在FrameworkServlet中创建了WebApplicationContext,DispatcherServlet根据contextConfigLocation配置的classpath下的appContext.xml文件初始化了Spring MVC中的组件。这就是Spring MVC容器创建的过程。

下面来分析具体处理请求的过程。

1)请求发送到服务器后,服务器程序就会分配一个Socket线程来跟它连接,接着创建出request和response,然后交给对应的Servlet处理,这样请求就从Servlet容器传递到了Servlet(Servlet容器)。

2)在Servlet中请求首先会被HttpServlet处理,在HttpServlet的service方法中将ServletRequest和ServletResponse转换为HttpServletRequest和HttpServletResponse,并调用转换为后Request和Response的servlce方法(Java的HttpServlet)。

3)接下来请求就到了Spring MVC,在Spring MVC中首先由FrameworkServlet的service方法进行处理,这里service方法又会将请求交给HttpServlet的service方法处理。(FrameworkServlet)

4)在HttpServlet的service方法中会根据请求类型将请求传递到对应的方法如doGet方法(Java的HttpServlet)。

5)doGet方法在Spring MVC的FrameworkServlet中,它又将传递到了processRequest方法,然后在processRequest方法中将当前请求的LocaleContext和RequestAttributes设置到LocaleContextHolder和RequestContextHolder后将请求传递到了doService方法,doService方法在DispatcherServlet里实现(FrameworkServlet)。

6)DispatcherServlet的doService方法将webApplicationContext. localeResolver. themeResolver. themeSource. outputFlashMap和flashMapManager设置到了request的属性中,然后将请求传递到了doDispatch方法中(DispatcherServlet)。

7)DispatcherServlet的doDispatch中首先调用checkMultipart方法检查是不是上传请求,然后调用getHandler方法获取到Handler( DispatcherServlet)。

8)getHandler方法获取Handler的过程会遍历容器中所有的HandlerMapping,<mvc:annotation-driven/>标签配置的HandlerMapping是RequestMappingHandlerMapping和BeanNameUrIHandlerMapping,在用RequestMappingHandlerMapping匹配时我们的请求会和其初始化时读取到定义的@RequestMapping(value= “hello”))所注释的内容相匹配,然后根据这个条件找到定义的处理器方法hello方法(RequestMappingHandlerMapping)。

9)找到处理器后调用RequestMappingInfoHandlerMapping里的handleMatch方法会将匹配到的Pattern( hello)设置到了request的属性中( RequestMappinglnfoHandlerMapping)。

10)找到Handler后返回DispatcherServlet的doDispatch方法中,然后调用getHandlerAdapter方法根据Handler查找HandlerAdapter.也就是根据工具找使用工具的人。查找的方式也是遍历配置的所有HandlerAdapter,然后分别调用它们的supports方法进行检查,检查的方法通常是看Handler的类型是否支持,RequestMappingHandlerAdapter. HttpRequestHandlerAdapter和SimpleControllerHandlerAdapter,最后找到RequestMappingHandlerAdapter( DispatcherServlet)。

11)DispatcherServlet的doDispatch方法中检查到是Get请求,然后检查是否可以使用缓存,因为RequestMappingHandlerAdapter的getLastModified方法直接返回-l,所以不会使用缓存,接着调用了Handlerlnterceptor的preHandle方法,这里没有配置Handlerlnterceptor,这一步就不管了,接下来用RequestMappingHandlerAdapter便用Handler处理请求(DispatcherServlet)。

12)RequestMappingHandlerAdapter首先在其父类的handle方法中直接将请求传递到了它的handlelnternal方法,handlelnternal方法首先调用getSessionAttributesHandler初始化了本处理器对应的SessionAttributesHandler,并判断出注释有@SessionAttributes,进而调用checkAndPrepare方法禁止了Response的缓存,然后将请求传递到了invokeHandleMethod方法( RequestMappingHandlerAdapter).

13)RequestMappingHandlerAdapter的invokeHandleMethod方法中首先创建了WebDataBinderFactory,ModeIFactory和ServletlnvocableHandlerMethod, ModeIFactory创建过程中会找到定义的注释了@ModeIAttribute的replaceSensitiveWords万法(RequestMappingHandlerAdapter)。

14)接着创建ModelAndViewContainer,并调用ModeIFactory的initModel方法给Model设置参数,这里会调用了定义的replaceSensitiveWords方法,调用前会使用RequestParamMethodArgumentResolver解析出"xxx"参数的值并设置给replaceSensitiveWords方法,方法处理完(去除敏感词)后,ModeIFactory将其使用@ModelAttribute注释中的"xxx"作为name,去除敏感词后的内容作为value设置到Model中(ModeIFactory)。

15)接下来调用ServletInvocableHandlerMethod的invokeAndHandle方法实际执行处理,先在父类InvocableHandlerMethod的invokeForRequest方法中调用了getMethodArgumentValues方法来解析参数,@PathVariable、RedirectAttributes、Model三个参数分别使用PathVariableMethodArgumentResolver、RedirectAttributesMethodArgumentResolver和ModelMethodProcessors三个参数解析器来解析,第一个返回在HandlerMapping中(第9步)设置到request属性中的值,第二个会新建一个RedirectAttributesModeLMap然后设置到mavContainer中并返回,第三个直接返回mavContainer中的Model,这时的Model中已经保存了前面去敏感词后的xx参数(InvocableHandlerMethod).

16)接下来调用InvocableHandlerMethod的dolnvoke方法处理请求,这里实际调用了我们编写的xxx处理方法,其中将"xx"设置到RedirectAttributes中,通过FlashMap传递,将"yy"设置到Model中,因为它在@SessionAttributes中进行了设置,所以会保存到SessionAttributes中,处理完后返回"redirect:/showArticle",将请求返回到ServletInvocableHandlerMethod(自定义的FollowMeController).

17)ServletlnvocableHandlerMethod使用HandlerMethodReturn ValueHandler处理返回值,因为返回的是String,所以使用的是ViewNameMethodReturn ValueH andler,它首先将返回值"redirect:/showArticle"设置到mavContainer的wew里,然后将mavContainer中的redirect标志redirectModeIScenario设置为了true,这样ServletlnvocableHandlerMethod就处理完了,接着将请求返回RequestMappingHandlerAdapter( ServletInvocableHandlerMethod)。

18)RequestMappingHandlerAdapter调用getModeIAndView方法对返回值进一步处理,首先使用ModeIFactory的updateModel方法处理@SessionAttributes注释,将其中的"xx"参数从Model中取出并使用sessionAttributesHandler保存;然后使用mavContainer中的Model和View创建ModelAndView;最后检查到Model是RedirectAttributes类型(因为我们返回的是redirect视图,而且设置了RedirectAttributes属性,所以mavContamer中getModel会返回RedirectAttributes类型的Model),这时会将之前保存到RedirectAttributes中的"xxx"参数设置到outputFlashMap,这样RequestMappingHandlerAdapter的处理就完成了,请求返回DispatcherServlet中(RequestMappingHandlerAdapter).

19)DispatcherServlet在doDispatch方法中首先检查返回的View是否为空,如果为空使用RequestToViewNameTranslator查找默认View,然后执行Handlerlnterceptor的applyPostHandle方法,这里这两项都不需要处理。接下来将请求传递到processDispatchResult方法( DispatcherServlet)。

20)DispatcherServlet的processDispatchResult方法中首先判断是否有异常,这里没有则不需要处理,然后调用render方法进行页面的渲染。render方法中首先使用localeResolver解析出Locale;然后调用resolveViewName方法解析出View,解析过程使用到了ViewResolver,这里使用的是我们配置的InternalResourceViewResolver,具体处理方法在UrIBasedViewResolver的createView方法中,它检查到是redirect的返回值,所以创建了RedirectView类型的View;然后调用View的render方法渲染输出(DispatcherServlet)。

21)RedirectView的render方法在父类AbstractView中定义,其中调用了RedirectView的renderMergedOutputModel方法,renderMergedOutputModel方法中将request属性中保存的outputFlashMap和FlashMapManager取出,使用FlashMapManager将outputFlashMap保存到了Session中,然后调用sendRedirect方法使用response的sendRedirect方法将请求发出,然后请求返回DispatcherServlet昀processDispatchResult方法(RedirectView)。

22)DispatcherServlet的processDispatchResult方法接着调用Handler的triggerAfierComp-letion方法,进而调用拦截器的afterCompletion方法,然后将请求返回到FrameworkServlet( DispatcherServlet)。

23)在FrameworkServlet的processRequest方法中将原来的LocaleContext和RequestAttributes恢复到LocaleContextHolder和RequestContextHolder中,并发出ServletRequestHandledEvent消息,最后将请求返回给Servlet容器(FrameworkServlet)。

这样一个完整的请求就处理完了。 Redirect后的请求处理过程大致和前面的过程差不多,主要有以下不同:

  1. 在上述第6步中DispatcherServlet的doService方法会使用flashMapManager将之前保存的FlashMap取出保存到request的"INPUT_ FLASH—MAP_ ATTRIBUTE"属性中;
  2. 在上述第14步中ModeIFactory的initModel方法会将之前保存在SessionAttributes中的"xx"参数设置到Model中;
  3. 在上述第1 5步中参数解析器使用的是ModeIMethodProcessor和SessionStatusMethodArgumentResolver,它们都是直接从mavContainer中获取的;
  4. 在上述第1 8步中ModelFactory的updateModel方法会在判断mavContainer中sessionStatus的状态后将SessionAttributes清空;
  5. 在上述第20、21步中由于本次返回值不是redirect类型所以IntemaIResourceViewResolver解析出的不是RedirectView而是jsp类型的InternaIResourceView,对应的模板是/WEB-INF/views/xx.jsp.