这篇blog是学完itheima视频后进一步学习的内容,所以也是紧接着上一篇blog: https://blog.csdn.net/qq_43175022/article/details/108933556
雷丰阳大神讲解https://www.bilibili.com/video/BV1d4411g7tv?p=156
解析getHandler()方法,引出:getHandler()方法如何根据当前请求找到对应类来处理,即如何返回目标处理类的执行链(同组件解析的第③步)
解决:通过调用HandlerMapping(处理器映射器)保存每一个处理器对应处理的请求映射信息
159 解析getHandlerAdapter()方法,解析如何找到适配器Adapter,对应④⑤步
三种返回值类型的获取方法:
HTTPRequestHandlerAdapter()、
SimpleControllerHandlerAdapter()、
AnnotationMethodHandlerAdapter()注解适配器,重点
160 后续Debug走完组件解析的后续两步
p161 SpringMVC九大组件:
(没有翻译的那个不重要),九大组件作用及共同点:
p162 九大组件初始化细节:细节:
例如HandlerMapping组件:
总结:
引出真正执行的方法:
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处理获得参数过程总结(排除两个提前注解过程):
结合代码重点摘要:
上述图片流程解析:
完成了上文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对象,就是获得重定向器,重定向到映射地址。
总结:
略。