springMVC处理一个请求的过程-源码详解


贴上我们用来测试的代码:
在这里插入图片描述
很简单,就是一个注解的controller,只要从浏览器输入对应的路径,这个方法就会拦截这个请求,进而开始具体的处理

1.springMVC如何寻找对应的controller?

我们先列出大概的流程,之后会进行详解

在这里插入图片描述
springmvc中最重要的就是前端处理器,也就是DispatcherServlet了,它会拦截浏览器的请求进行转发,交给对应的controller进行处理,首先它是一个继承自httpServlet的Servlet,而httpServlet中有三个重要的方法doGet,doPost,Service,可以看一下这篇文章:Servlet详解
找到DispatcherServletdoGetdoPost方法,这两个方法都调用了
在这里插入图片描述
这个方法,为了节省篇幅,我们直接找到里面的doService方法,这个方法又调用了doDispatch方法,doDispatch是我们研究的重点,我们所谓的视图解析,数据封装,方法处理基本都在这个方法中进行,在具体探讨之前,我们先列出一个springmvc处理的大概流程

  • 首先扫描整个项目,也就是我们定义的包扫描的范围,拿到所有加了@Controller注解的类,并且定义一个map集合
  • 将加了@Controller注解的类中的方法进行遍历
  • 判断这些类中的方法是否被加了@RequestMapping注解
  • 如果有注解,就将其注解的value作为key加入map,它的value就是该方法对象
  • 根据用户发送的请求,拿到URI
  • 根据这个URI作为key去map中匹配,看是否有返回值,如果有就匹配与之对应的适配器,然后再进行处理…

下面我们就根据源代码来看看是否是这个过程,需要注意的是,我们看源码并不需要一行行的看懂,我个人认为看源码的目的是看里面的设计模式,设计思想和如何完成功能,所以文章剩下部分的代码可能有的地方不会着重介绍

2.将method封装到map中

在这里插入图片描述
mappedHandler顾名思义就是处理器映射器,它是一个HandlerExecutionChain对象,这个对象是来做什么的呢?首先这个对象是由HandlerMapping创建的HandlerMapping是获取所有请求与处理器(为了大家好理解,我们将处理器理解为Handler也就是常说的控制器Controller)的关系,而HandlerExecutionChain代表具体某一个处理器与请求的关系,其中可能包括拦截器,我们进入这个方法:
在这里插入图片描述
注意这里的private List<HandlerMapping> handlerMappings;它有多种HandlerMapping:
在这里插入图片描述
为什么会有这两种HandlerMapping来创建我们的mappedHandler呢?原因是因为我们创建controller的方式不同,现在绝大部分创建的方式就是加上Controller注解,但是还有其他方式:
在这里插入图片描述
在这里插入图片描述
即通过接口的方式创建,所以要根据不同创建方式来创建不同的HandlerExecutionChain对象,我们接着getHandler方法往下走,发现了HandlerExecutionChain handler = hm.getHandler(request);这行代码,我们进入这个getHandler方法:
在这里插入图片描述
再次进入标记的方法:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码到这里我们可以发现,这个逻辑确实是根据URI路径去map匹配我们对应的方法!

2.适配器处理

程序执行到这里,已经拿到了我们所需要的方法了:
在这里插入图片描述
接下来就是根据传进去的method方法去匹配对应的适配器了,为什么需要不同的适配器,是因为执行的方法不同,如果是注解方式,对应controller通过反射来调用方法,如果是实现接口的处理器,则调用接口的实现类来调用方法,我们进入这个方法:
在这里插入图片描述
我们可以看看都有哪些适配器:
在这里插入图片描述
进入这个supports判断逻辑,我们这里是通过注解注册的Controller,因此是这种:
在这里插入图片描述

3.处理Handler的参数

获取到适配器之后就可以处理这个方法了,返回一个ModelAndView mv对象:
在这里插入图片描述
我们进入这个方法
在这里插入图片描述
在这里插入图片描述
进入invokeHandlerMethod方法,找到这一行:
在这里插入图片描述
然后进入这个方法:
在这里插入图片描述
这就是重点代码了:
在这里插入图片描述
我们的请求参数中经常会携带一些参数,适配器对参数的处理可谓是重中之重,第一个标红的代码表示获取传入方法的参数,springmvc会自动的将传入的参数封装成相应的对象,前提是方法参数中是对象,根据路径传进来的参数来解析封装对象,要是我们,该怎么处理这些参数呢?通过注解的Controller会通过反射创建方法对象进行参数的处理,我们写一段伪代码来看看:
在这里插入图片描述
这就是处理参数的一个大概过程,下面我们通过源代码来验证

4.参数处理细节

在这里插入图片描述
进入第一个方框的代码:
在这里插入图片描述
和我们的伪代码类似,它会先判断参数的类型,去请求中获取对应参数类型的值,不过和我们普通的if判断不同,这里是通过参数处理器来进行判断的,也就是argumentResolvers

private HandlerMethodArgumentResolverComposite argumentResolvers = new HandlerMethodArgumentResolverComposite();

其中:HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver,故HandlerMethodArgumentResolver就是我们说的参数处理器
我们可以看一下有多少种参数处理器:
在这里插入图片描述
有27种不同的参数处理器,如果通过我们简单的if elsel判断,那么代码就会变得非常冗余,进入下面给args数组赋值的代码中:

args[i] = this.argumentResolvers.resolveArgument(
							parameter, mavContainer, request, this.dataBinderFactory);
							

在这里插入图片描述
它先获取了参数处理器,进入这个方法:
在这里插入图片描述
我们通过浏览器访问首先不会进入缓存,不进入缓存,就会进入到
if (methodArgumentResolver.supportsParameter(parameter))这个判断种,也就是根据参数选择合适的参数处理器,并将这个参数处理器放进缓存中,下次就直接从缓存种得到参数处理器去给参数赋值,给参数赋值过后就可以真正处理参数了:

return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);

处理过程就是我们自己写的逻辑代码

总结:

这里仅仅是简单介绍了springmvc是如何通过请求去匹配到对应的controller来处理请求,并且处理请求参数,至于如何解析视图,由于篇幅原因,请看另一篇文章:
spring MVC如何解析视图,View视图源码解析
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章