SpringMVC框架源码解析
这篇blog是学完itheima视频后进一步学习的内容,所以也是紧接着上一篇blog:
https://blog.****.net/qq_43175022/article/details/108933556
源码分析
雷丰阳大神讲解https://www.bilibili.com/video/BV1d4411g7tv?p=156
组件解析 的前四步及九大组件
- p156 流程分析
- p157 -160 doDispatch()方法源码分析SpringMVC加载过程,对应上文组件解析前7个步骤的内容
- 157 源码分析,找到有用方法加注解
- 158 文字概述上述过程:
解析getHandler()方法,引出:getHandler()方法如何根据当前请求找到对应类来处理,即如何返回目标处理类的执行链(同组件解析的第③步)
解决:通过调用HandlerMapping(处理器映射器)保存每一个处理器对应处理的请求映射信息
-
159 解析getHandlerAdapter()方法,解析如何找到适配器Adapter,对应④⑤步
三种返回值类型的获取方法:
HTTPRequestHandlerAdapter()、
SimpleControllerHandlerAdapter()、
AnnotationMethodHandlerAdapter()注解适配器,重点
-
160 后续Debug走完组件解析的后续两步
- p161 SpringMVC九大组件:
(没有翻译的那个不重要),九大组件作用及共同点:
- p162 九大组件初始化细节:
细节:
例如HandlerMapping组件:
总结:
组件解析中的关键点Handler处理 P163-167
- p163 聚焦组件解析中⑤⑥步中Handler的目标方法执行:
引出真正执行的方法:
- p164 invokeHandlerMethod()方法解析,真正执行目标方法的两个注解(34点)的解析:
-
首先查找34点中的是否有@SessionAttributes存储Session,没有直接执行下一步:
-
进入@ModelAttribute注解解析细节:
-
进入resolveHandlerArguments()方法,获得agrs[]:
- 该方法使用一个双层for()循环确定:
- 然后进行分支判断找到的注解个数(由于上述注解冲突只能标一个,出现多个就抛出异常):
- 分析没有找到注解的分支:
-
进入resolveCommonArgument()方法解析普通参数(原生API):
确定当前参数是否为Servlet原生API,解析成功就将方法返回的Object赋予上文声明的args[]
-
不为普通参数时:
本例中为map参数,所以传入隐含模型
-
获得args[] (该args只获得ModelAttribute注解这一个参数)后,寻找ModelAttribute注解属性Value的值,赋予attrName
-
反射Method类型的attributeMethodToInvoke(由for循环迭代遍历获得的attributeMethod解析而来),使其可访问
-
运行ModelAttribute提前运行的方法(详情可见34点)赋予一个Object类型
-
判断上述attrName是否为空
-
不为空上述方法已经赋值
-
为空执行下列语句:
赋予ModelAttribute方法的返回值类型首字母小写(由attributeMethodToInvoke获得)
-
-
判断隐含模型是否包含attrName,没有就执行:
作用:
-
再次调用resolveHandlerArguments()方法,获得agrs[]:
不同的是第一个形参换成了 invokeHandlerMethod()方法的第一个形参handleMethod解析获得的handlerMethodToInvoke
-
return语句:
真真正正的执行方法:handlerMethodToInvoke.invoke
总结:ModelAttribute标注的方法提前运行并且把执行后的返回值放在隐含模型中
- p165 166 上文有提及,40点只是获取了34点的两个提前注解的参数信息,所以需要再次调用resolveHandlerArguments()方法,获取其他参数的值
-
165 @RequestParam的普通类型、普通类型、map类型的三个参数获得流程:
-
166 POJO类型(自定义类型)参数:
-
有注解:
-
没注解:
总结:
步骤:
-
该方法的内循环的一个分支语句,确定上述值:
-
进入resolveModelAttribute()方法获取WebDataBinder实例对象:
-
标红部分讲解,确定POJO的值:
-
-
上述166 167Handler处理获得参数过程总结(排除两个提前注解过程):
组件解析的视图解析部分(最后三步)源码分析
- p172 视图解析流程:
结合代码重点摘要:
上述图片流程解析:
完成了上文Handler处理获得ModelAndView对象后,继续向下执行调用了上述第2点processDispatchResult()方法,该方法方法体中调用了第3点的render()方法渲染页面,该方法中声明View(页面)对象,View调用前端控制器定义的resolveNameView()方法,获得一个View对象,提出下面第5点问题:
-
组件解析中的⑧⑨步的视图解析器调用源码流程解析:
-
在前端控制器的resolveNameView()方法中,迭代遍历九大组件之一的ViewResolver对象
过程中还查看当前viewResolver对象的获得方法和默认值
-
迭代出的当前页面的视图解析器调用本身接口自带的内部resolveNameView()方法,获得一个View对象:
进入该resolveViewName()方法(在一个抽象类中):
-
首先查看缓存,有就直接获取
-
为空时调用createView()方法创建View对象:
View对象:
进入createView()方法:
-
三个不同类型的分支结构判断创建获得其中一种View对象:
-
调用父类执行创建,父类再调用loadView()方法一顿解析,期间又会返回createView()方法所在类进行解析(略)
-
-
获得一个View对象
本案例中获得了一个InternalResourceView对象
还有一个常用的View对象:RedirectView对象
-
存入缓存
-
-
上述流程总结:
-
-
组件解析中的⑩步的视图解析器调用源码流程解析:
上述得到View对象后返回第三点的render()方法(前端控制器定义的)
-
view对象调用接口自带的内部render()方法(抽象类中)(上文接口图示可见该方法):
-
进入renderMergedOutputModel()方法:
其中的关键方法exposeModelAsRequestAttribute():
-
进入exposeModelAsRequestAttribute()方法:
-
回到renderMergedOutputModel()方法:
取得映射地址并获得转发器:
转发器转发:
如果获得的View对象是RedirectView对象,就是获得重定向器,重定向到映射地址。
-
-
总结:
拦截器和异常处理源码 P211 212和P221 226 4P
略。