携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第7天,点击查看活动详情
浅看SpringMVC源码
先看dispatcherServlet的init方法做切入, 该方法是servlet的生命周期的init方法, 第一次访问serlvet映射的url时会执行该方法, 在serlvet生命周期中只会执行一次.
在idea里ctrl+n-->找到dispatcherServlet的源码, ctrl+f12-->搜索init, 在父类中找到代码, 最后找到this.initServletBean(); 这里的this是指dispatcherServlet实例(当前对象).
继续在dispatcherServlet中找到initServletBean方法, 找到其中的this.webApplicationContext = this.initWebApplicationContext(), 给其中的成员变量--WebApplicationContext做赋值.
在这里会加载web.xml配置文件里的东西
再看dispatcherServlet中的doDispatch方法,是通过dispatcherServlet的doGet/doPost方法, 找到doDispatch方法的.
doGet/doPost方法都调用processRequest方法, 里面有一行this.doService方法, 传入req, resp, 该方法里面是一个抽象方法, 去父类中找到doService方法, 找try-catch里的一行, doDispatch方法, 继续传递入req, resp.
接下来重点看doDispatch方法.
mapperdHandler = this.getHandler(processedRequest)
这行是为了获得handler是谁, 就是handlerMethod, 而mappedHandler是一个HandlerExecutionChain类型, 里面封装了object类型的Handler, 是一个1v1关系,
是HandlerMapping映射器帮助我们建立handler和HandlerExecutionChain的映射关系, 源码在getHandler方法中, 里面有一行 this.handlerMapping != null, 这个 handlerMapping 是一个数组, 在dispatcherServlet的生命周期过程中进行初始化.
// getHandler
事实上handlerMapping是一个接口, 里面有实现类,形式上是一个list里由两个元素
- BeanNameUrlHandlerMapping
- RequestMappingHandlerMapping
第一个现在已经不用, 第二个handlerMapping根据request获得请求url, 根据请求url找到controller组件里的handler方法.
又根据handler方法上的注解value属性, 确定是那个handler方法是要找的方法.
在doDispatch方法中获得handlerAdapter, 用this.getHandlerAdapter(mapperHandler.getHanlder()), 根据handler的类型找对应的适配器, 这里的hanlder是handlerMethod, 要根据RequestMappingHandlerMapping找到对应的适配器--RequestMappingHandlerAdapter.
而BeanNameURLHandlerMapping对应的HandlerAdapter是SimpleControllerHandlerAdapter, 但现在并不会使用这种HandlerAdapter.
适配器主要做的事情是将业务方法的形参正确的接收, 对形参类型进行适配.
获得合适的HandlerAdapter后, 要执行handler方法.
源码为doDispatch方法里的mv = ha.handle(processedRequest, response, mapperHandler.getHandler()), 在其中就会做handler方法形参的适配以及执行controller组件中的业务方法login(), 就是执行了handler方法.
这里的method.invoke(instance, args)用源码实现就是ha.handle()方法.
执行ha.handler()方法是Controller组件中的方法(@RequestMappingHandlerMapping对应的方法)的返回值mv的类型是ModelAndView, 我们当前响应结果为json, 在Handlermethod上有注解@ResponseBody会将该方法返回值转化为json字符串响应出去, 所以这里返回的mv其实是null,
this.processDispatchResult()会处理handlermethod返回的结果, 如果返回的mv为null, 会帮我们响应一个json, 会使用到jackson.
总结: doDispatch中的handlerMapping处理方法, handlerAdapter处理参数, 方法返回结果为mv如果是null, 就将对象转换成json字符串返回响应. 总共做哪些事情:
- 请求url映射
- 请求方法对应
- 请求结果封装
思考: 如果现在做web应用开发, 使用springmvc框架, 现在主要做的事情就是handlerMethod的开发,
- 要通过@RequestMapping建立映射关系,
- 在handlerMethod的形参中接收到我们需要的参数,
- 在controller组件中定义service成员变量, 注入对应的service组件,
- 在handler方法中写具体的业务, 即使用service里的方法执行对应的业务,
- 最后把执行完业务的方法返回值返回出去, 返回的一般是json字符串的形式.