SpringMVC源码流程分析

DispatcherServlet源码分析

SpringMVC核心的就是DispatcherServlet,所有的请求都会转发到DispatcherServlet,让后在通过DispatcherServlet执行具体的控制层(Handler) 返回modelAndView给客户端视图展示。

DispatcherServlet与Servlet关系

关系:DispatcherServlet继承FrameworkServlet继承HttpServlet

流程执行关系:

HttpServlet service方法 判断请求方法的类型

FrameworkServlet doService

DispatcherServlet doService

DispatcherServlet源码流程分析

  • 1.执行doDispatch
  • 2.调用getHandler方法获取请求目标的方法  也就是  请求url映射路径对应的控制层具体的方法
  • handlerMappings的作用查找控制器位置,比如xml和注解方式。
  • 3.调用getHandlerAdapter获取控制层适配器 RequestMappingHandlerAdapter
  • 4.执行拦截器前置方法 preHandle() 如果返回为true的话
  • 5.执行实际请求目标方法 返回modeAndView对象
  • 6.执行拦截器PostHandle()方法
  • 7.设置渲染视图层内容
  • 8.执行拦截器afterCompletion方法

 

 

现在先从最开始的web.xml文件进行分析,我们首先配置了contextConfigLocation如下所示:

继承关系如下图所示: 

上图中的ServletContextListener该类位于servlet-api.jar包中(再tomcat的自带lib中可以找到) 
ContextLoaderListener实现了ServletContextListener接口,该接口保证了在能够为客户端提供服务之前向ServletContext中添加任何对象。每个Web应用都有一个ServletContext与之相关联,启动时被创建,关闭时被销毁,并且ServletContext在全局范围内有效。ServletContextListener的核心逻辑就是初始化WebApplicationContext实例并放入ServletContext中。 
我们之所以使用了ContextLoaderListener是为了避免下面这种硬编码配置:
ApplicationContext ac = new ClassPathXmlApplecation("applicationContext.xml")

 再来说说ContextLoaderListener的实际步骤是: 

  1. webApplication存在性验证(配置中只能有一个ServletContextListener接口,验证的方法就是检查该属性是否存在) 
  2. 创建webApplication实例 
  3. 将属性注入(例如contextConfigLocation)webApplication 
  4. 将实例记录到servletContext中 
  5. 映射当前的类加载器与创建的实例到全局变量currentContextPerThread中 
     

讲完了ContextLoaderListener再来讲讲web.xml中另一个重要配置DispatcherServlet,对于DispatcherServlet的配置如下所示:

接下来我们先给出DispatcherServlet的类层次结构,如下图所示: 

注册url与HandlerMethod映射关系链

Spring容器启动时, 在org.springframework.web.servlet.handler.AbstractHandlerMethodMapping类

遍历IOC容器中所有bean 

判断是否有@Controller和@RequestMapping注解 

 

  

DispatcherServlet的初始化过程

调用链关系如下图:

  1. HttpServletBean  init ()方法
  2. FrameworkServlet initServletBean方法→  initWebApplicationContext();
  3. DispatcherServlet onRefresh方法→  initStrategies()方法

容器启动时, 在HttpServletBean类里面的init方法里面进行初始化

最终执行DispatcherServlet的initStrategies方法进行组件的初始化 

初始化上传文件解析器(或者是多部分请求解析器)

初始化本地化解析器 

初始化主题解析器 

 初始化处理器映射器

初始化处理器适配器 

初始化处理器异常解析器

初始化请求到视图名翻译器 

初始化视图解析器

初始化重定向数据管理器 

DispatcherServlet的处理逻辑

虽然HTTP1.1报文头一共有八种,常用的:GET、POST、PUT、DELETE,不太常用的:HEAD、TRACE、CONNECT、OPTIONS,但是实际上FrameworkServlet并没有实现CONNECT和HEAD。他们分别对应着doXXX()方法。 
对于不同的方法,Spring统一的将他们引入到processRequest方法中,该方法完成了以下操作: 

  1. 提取当前线程的LocaleContext和RequestAttribute以便在当前请求后还能够恢复 
  2. 根据当前request创建LocaleContext和RequestAttribute,并绑定到当前线程 
  3. 委托doService方法执行doDispatch(request, response)方法

仍然是准备工作,将webApplicationContext,localeResolver等属性注入request中,然后继续由doDispatch方法进行处理,

doDispatch方法的处理逻辑为: 
第一步:将MultipartContent类的request转化为MultipartHttpServletRequest类型的request 
第二步:首先获取到HandlerExecutionChain,HandlerExecutionChain结构很简单,包括一个我们具体处理请求的Controller层方法的对象handler,以及拦截器interceptors、interceptorList。如果没有获取到相应的HandlerExecutionChain,则会返回404。


第三步:若如果没有找到对应的Handler则通过response向用户报错 


第四步:根据当前的Handler寻找对应的HandlerAdapter(遍历寻找) 


第五步:缓存处理,根据Last-Modified缓存机制(第一次成功请求后如果在第二次请求之间内容没有改变,那么返回304状态码),Controller需要实现LastModified接口 


第六步:顺序调用拦截器的preHandle()方法,如果不符合拦截器的拦截规则则会同时调用afterCompletion()方法


第七步:逻辑处理,通过适配器中转调用Handler(处理用户定义的逻辑)并返回视图 


第八步:调用拦截器的postHandle()

 
第九步:调用processDispatchResult()对请求结果进行处理。如果业务处理过程中有异常抛出,调用processHandlerException()对异常进行处理,这里会调用我们自定义的HandlerExceptionResolvers进行处理,然后返回一个异常处理结果的ModelAndView对象。

第十步:执行拦截器afterCompletion方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值