zoukankan      html  css  js  c++  java
  • SpringtMVC运行流程:@RequestMapping 方法中的 Map、HttpServletRequest等参数信息是如何封装和传递的(源码理解)

    在平时开发SpringtMVC程序时,在Controller的方法上,通常会传入如Map、HttpServletRequest类型的参数,并且可以方便地向里面添加数据。同时,在Jsp中还可以直接使用request等对象方便地获取出来。

    如下面2图所示:

     

    可问题是:@RequestMapping 方法中的 Map、HttpServletRequest等参数信息是如何封装和传递的?

    带着这个问题,写了个简单的Demo,来进行源码调试。

    Demo代码地址:

    https://github.com/cyhbyw/springMVC_atguigu_TongGang

    工程名称:

    springMVC_DebugSourceCode

     

    ===========以下是源码调试==================

    ==============>>>>
    PS:图片可能不是很清晰,可以右击图片、选择在新标签页中查看
    或者,可以右击图片,选择“图片另存为”保存在本地并编好号(建议直接以01、02、03……来编号)
    或者,可以右击图片,选择“复制图片”,再保存到本地并编好号(建议直接以01、02、03……来编号)
    以上三种办法,任意选择喜欢的一种,以获得并查看更清晰的图片~~
    <<<<==============

    01.首先,浏览器发出的请求到DispatcherServlet;然后,找到合适的HandlerAdapter(此处是RequestMappingHandlerAdapter);然后调用RequestMappingHandlerAdapter的handle()方法。此时,方法堆栈从Line959开始。

     

      

    02.还是在DispatcherServlet的Line959的doDispatch()方法内,又调用了几个方法,到达invokeForRequest()方法;顾名思义,此方法会真正的调用Request方法(即Controller中的方法);不过,先会在Line128解析参数。

     

     

     03.解析参数的方法又会走到Line161.

     

     

     04.再经过两个方法的调用,可以看到上述的参数解析方法是直接返回了 mavContainer.getModle()

    而由06步可以看到,Model实际上是个map对象,那么,此处直接返回map对象就相当于返回了其引用,外部任何地方的修改都将影响此map中的值!!!

    这个引用会给第08步中的 Object[] args 以及第09、10步中的 map,所以第10步中向 map 中添加数据,其实也就等价于向此 Model 中添加了数据!!!(背景知识:Java对象引用)

     

      

    05.而getModel() 方法返回 defaulutModel 的成员变量。

     

      

    06. defaulutModel 其实就是一个 BindingAwareModelMap

     

     

     07.回到刚才的Line161,可以看到 args[i] 指向了刚才得到的BindingAwareModelMap@4821。

     

      

    08.再返回一层,此处的 Object[] args 还是BindingAwareModelMap@4821;并且到目前为止,其中的元素仍然为空;此处Line136的 doInvoke(args) 方法就是通过反射调用真实的Controller中的方法。

     

      

    09.调用真实方法(由08步中的Line136反射调用);可以看到,真实Controller方法中的入参 map 还是BindingAwareModelMap@4821(说明是同一个对象——非常重要!!)

     

     

    10.将值写入map中

     

     

    11.真实Controller方法调用返回后,可以看到 mavContainer 对象中的 defaultModel 属性已经被赋值,且这个值就是BindingAwareModelMap@4821,与args是同一个对象(非常重要,而且从前面的分析中也可以看到)!!!!

    (备注:SpringMVC是如何为mavContainer 对象中的 defaultModel 属性赋值的,最开始调试了很久也没有发现,心想着,它既然是个Map,那应该是调用setXXX(), put(), putAll()这样的方法赋值进去的,但调试了很久始终没发现这样的方法被调用;同时,也可以确定它是在Line136行调用后就被赋值的;最后猜测,是同一个对象引用;现在,证明确实如此)

    再啰嗦一句,其实就是:Line128的 Object[] args 变量指向了 mavContainer 对象的 defaultModel 属性!所以在将 args 通过Line136反射调用真实的Controller方法并填充数据后,defaultModel中也就有了相应数据!

    注意结合第04步中的文字进行理解!

     

     12.真实Controller方法调用完成后,开始处理返回值

     

     13.设置视图名称

     

     

     14.准备创建ModelAndView对象

     

      

    15.从 mavContainer 中取出Model数据,并通过构造函数传入ModelAndView

     

      

    16.已经获得ModelAndView对象,进行后续操作(如渲染);注意,此时DispatcherServlet中的方法堆栈从Line971开始。

     

      

    17.准备渲染

     

      

    18.得到View对象

     

      

    19.遍历 viewResolvers 找到一个合适的就返回给18步中的View对象

     

      

    20.准备渲染

     

      

    21.将Model数据暴露为RequestAttribute

     

      

    22.暴露的本质其实是:request.setAttribute(modelName, modelValue)

    重要:在这里是 request.setAttribute 所以在 Jsp 中才可以 request.getAttribute,先有 set 才有 get 嘛。

     

      

    23.最后是一个转发操作

     

     

  • 相关阅读:
    java按照指定格式输出系统时间使用SimpleDateFormat方法
    java按照指定格式输出系统时间
    java打印系统时间
    java字符串截取指定下标位置的字符串
    java根据输入的字符串和字节数来截取,输出对应字节数的字符串
    java字符串根据正则表达式让单词首字母大写
    java根据#号截取字符串,使用Pattern的方法
    java数组冒泡排序
    Prometheus+Grafana监控平台搭建
    JMeter-setUp线程组实现用户先登录(跨线程中beanshell设置全局变量)
  • 原文地址:https://www.cnblogs.com/cyhbyw/p/8618747.html
Copyright © 2011-2022 走看看