一,一个Http请求进入SpringMVC的完整流程:
首先看下动态请求的处理:(静态资源请求的处理其实比较简单,只是以流的方式把静态资源写入response中而已)
在Servlet容器中,一个请求的完整流程是:
1.Servlet容器调用Servlet.service()
2.HttpServlet.service()分发get,post等
3.FrameworkServlet.doGet()
4.final FrameworkServlet.processRequest()
5.DispatcherServlet.doService()
6.DispatcherServlet.doDispatch()
7.根据请求的url路径找到可以匹配的HandlerMapping,调用其getHandler得到HandlerExecutionChain,HandlerExecution具体包含了实际的handler处理逻辑以及一组提供额外功能拦截器
看下doDispatch中的对getHandler的调用以及getHandler的实现:
DispatcherServlet初始化完成之后,DispatcherServlet的所有的mvc元素都已经被赋值,所以直接遍历this.handlerMappings调用getHandler,handler不为空直接返回。
getHandler的具体逻辑实现以及HandlerMapping中的对的初始化设置,先留下来下一篇继续深入探索。
8.用HandlerExecution中的拦截器对请求进行预处理,必须要所有的拦截器的preHandler都执行成功才会继续,否则直接返回,请求处理完毕。
doDispatch中的调用HandlerAdapter以及预处理请求部分
9.预处理成功之后,根据找到的HandlerExecutionChain的handler找到支持该handler的HandlerAdapter,调用HandlerAdapter.handle(request,response,handler)
10.找到一个HandlerAdapter的具体实现(以RequestMapping注解的RequestMappingHandlerAdapter为例),RequestMappingHandlerAdapter.handleInternal(request,response,method),用反射调用具体的处理方法,并且生成ModelAndView
调用handle方法直接生成ModelAndView:
RequestMappingHandlerAdapter的实现:
继续深入的话就是利用反射工具反射调用处理方法,以及ModelAndView的生成。先留着,下下篇继续深入。
11,在DispatcherServlet中的doDispatch方法获得返回的ModelAndView,最后进行模型和视图的渲染
视图的渲染也留着下下篇博客继续深入
二,订制自己的DispatcherServlet
啃书啃了半天,来找点成就感吧,准备实现一个侏儒版的DispatcherServlet,把每个部分的功能都砍一遍,自己依托已有的FrameworkServlet写个CustomDispatcherServlet。
分两步吧:
1,先用xml配置一个最简单的SpringMVC项目,并且能够在Tomcat中运行起来;
2,在已有的web.xml中把DispatcherServlet改为我们自己写的CustomDispatcherServlet,再次部署项目到Tomcat中,也依然可以运行。
1,配置一个最简单的SPRINGMVC项目,看下我的目录结构:
在web.xml中配置DispatcherServlet和必要的启动参数,还有其映射路径:
spring-test.xml中开启component-scan扫描controller相应包,还有配置一个InternalResourceViewResolver视图解析器:
resource包下写个Hello的controller类:
index.jsp 简单的一个跳转链接:
Hello.jsp 就是say hello而已:
然后配置一下Tomcat,启动项目访问,点击SayHello链接可以进行页面的跳转说明已经成功了!
2,把DISPATCHERSERVLET改为自己手写的CUSTOMDISPATCHERSERVLET
接下来就到了重量级的手写CustomDispatcherServlet了,回顾一下DispatcherServlet的主要职责:
- 自己维持mvc的HandlerMapping,HandlerAdapters等元素,对其进行初始化
- doDispatch分发各类的请求
我们主要实现这两部分就ok了,我们的CustomDispatcherServlet继承FrameworkServlet,只有必须的三个成员属性:
HandlerMapping,HanlderAdatper,ViewResolver
1,实现onRefresh方法,从FrameworkServlet已经初始化成功的web上下文或者整个应用的根上下文中寻找三个成员属性的实例,对其进行初始化:
initHandlerMappings实现:
initHandlerAdapters和initHandlerMapping的实现差不多,intViewResolver是直接获取配置的InternalResourceViewResolver:
2,重写doService方法,完成对Http请求的处理:
doService设置了必要的参数,后面的视图的渲染需要用到web上下文,所以需要把webapplicationcontext设置到请求域中,但是name不能随便命名,必须是DispatcherServlet.CONTEXT,这个留到后面再看下具体实现,以及将分发任务委托给doDispatch。
doDispatch :对请求获取其对应的Handler,然后生存ModelAndView,最后进行视图的渲染即可:
getHandlerExecution 就是简单的遍历所有的HandlerMapping,依次执行getHandler方法,若不为空就直接用:
getHandlerAdapter 也是遍历所有的HandlerAdapters,依次判断是否支持该请求对应的handler,支持的话直接返回:
最后是视图的渲染render :
写到这里,大功告成。
马上用自己的DispatcherServlet来处理请求,把web.xml中的DispatcherServlet去掉,换上自己的:
然后在Tomcat中运行,点击链接SayHello:
成功跳转!
哇,成就感满满的,手写一个SpringMVC框架指日可待了。
三,结尾
源码:https://github.com/151250010/TestWeb
三个遗留问题下篇博客或下下篇解决:
- HanlderMapping 的 键值对是怎么设置的,以及getHandler又是怎么获取到HandlerExecutionChain的
- HandlerAdapter.handle() 生成ModelAndView 到底怎么实现的
- 视图的渲染具体怎么实现的