SpringMVC框架源码解析

    科技2025-01-28  5

    这篇blog是学完itheima视频后进一步学习的内容,所以也是紧接着上一篇blog: https://blog.csdn.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

    略。

    Processed: 0.009, SQL: 8