本篇主要讲解了Spring mvc的调用过程,通过这个过程来了解Spring的原理。


进入web.xml中配置的Spring拦截(调度)器:

 Spring MVC 原理 - DispatcherServlet调用完整过程

调用堆栈信息:

Spring MVC 原理 - DispatcherServlet调用完整过程


开始拦截,这一步主要是根据request获取handler(该handler可以配置)

Spring MVC 原理 - DispatcherServlet调用完整过程


(接上面方法)这段代码中的if(isGet…主要解决浏览器的缓存问题,如果没有过修改,则返回(浏览器可能会用缓存响应)。

Spring MVC 原理 - DispatcherServlet调用完整过程


调用方法handler

Spring MVC 原理 - DispatcherServlet调用完整过程


进入handler方法:

Spring MVC 原理 - DispatcherServlet调用完整过程


进入方法invokeHandlerMethod:

Spring MVC 原理 - DispatcherServlet调用完整过程


440行进入下一个方法invokeHandlerMethod:

Spring MVC 原理 - DispatcherServlet调用完整过程

Spring MVC 原理 - DispatcherServlet调用完整过程


进入该方法:

Spring MVC 原理 - DispatcherServlet调用完整过程


171行进入处理参数的方法:

Spring MVC 原理 - DispatcherServlet调用完整过程

Spring MVC 原理 - DispatcherServlet调用完整过程


处理参数的方法,使用参数类型进行for循环:

Spring MVC 原理 - DispatcherServlet调用完整过程

获取一个参数的注解:

Spring MVC 原理 - DispatcherServlet调用完整过程

通过下面方法返回注解数组:

Spring MVC 原理 - DispatcherServlet调用完整过程

其中parameterIndex在创建该对象时赋值,和参数类型的位置是对应的(下图中的i):

Spring MVC 原理 - DispatcherServlet调用完整过程


获取注解之后,对注解进行遍历,通过判断注解类型来获取paramNameheaderName或其他:

Spring MVC 原理 - DispatcherServlet调用完整过程

Spring MVC 原理 - DispatcherServlet调用完整过程

在每个if中的defaultValue,方法parseDefaultValueAttribute用来获取注解的默认值设置:

Spring MVC 原理 - DispatcherServlet调用完整过程

可以看到系统用了一个不常用的字符串作为默认值,用这个值和传入的value进行比较,使用这个值的目的是尽可能和用户设置的值区分开。

Spring MVC 原理 - DispatcherServlet调用完整过程

指定类型的注解(if判断里面的),只能存在一个,超过1个会报错

Spring MVC 原理 - DispatcherServlet调用完整过程

如果没有注解,则判断类型是否为常用的(request,response,session)

Spring MVC 原理 - DispatcherServlet调用完整过程

对于没有注解的参数,可能会执行下面的方法:

Spring MVC 原理 - DispatcherServlet调用完整过程

进入处理标准类型的方法:

Spring MVC 原理 - DispatcherServlet调用完整过程

Spring MVC 原理 - DispatcherServlet调用完整过程

Spring MVC 原理 - DispatcherServlet调用完整过程

通过上面的方法判断出基本的类型。


回到有注解的情况,针对不同的注解,具体处理过程如下(if顺序没有优先级,因为只有一个注解,一种情况):

Spring MVC 原理 - DispatcherServlet调用完整过程


到这一步,会根据具体的注解类型执行不同的resolve***()方法。

resolve***的方法最终返回的是类型符合要求(resolve内部有各种类型转换的方法)的参数值。


最后处理完成,返回参数列表:

Spring MVC 原理 - DispatcherServlet调用完整过程

反射调用方法:

Spring MVC 原理 - DispatcherServlet调用完整过程

进入用户写的处理方法中:

Spring MVC 原理 - DispatcherServlet调用完整过程

在用户方法执行完成后,返回:

Spring MVC 原理 - DispatcherServlet调用完整过程

返回result之后,使用result去获取ModelAndView,执行方法getModelAndView:

Spring MVC 原理 - DispatcherServlet调用完整过程


该方法主要通过result返回值来判断:

Spring MVC 原理 - DispatcherServlet调用完整过程

当前方法是带ResponseBody注解的,所以执行到这里:

Spring MVC 原理 - DispatcherServlet调用完整过程

进去方法:

Spring MVC 原理 - DispatcherServlet调用完整过程

这里是根据http类型做出相应的输出:

Spring MVC 原理 - DispatcherServlet调用完整过程

用户配置的:

Spring MVC 原理 - DispatcherServlet调用完整过程

接收的类型:

Spring MVC 原理 - DispatcherServlet调用完整过程

写的方法:

Spring MVC 原理 - DispatcherServlet调用完整过程

这里配置的json格式,所以会进入JSON方法:

Spring MVC 原理 - DispatcherServlet调用完整过程

写入ResponseBody后,返回mav:

Spring MVC 原理 - DispatcherServlet调用完整过程

最后返回之前调用handler的地方,之后会有一些不同种类的拦截器方法:

Spring MVC 原理 - DispatcherServlet调用完整过程


拦截器如:

Spring MVC 原理 - DispatcherServlet调用完整过程

Spring MVC 原理 - DispatcherServlet调用完整过程

Spring MVC 原理 - DispatcherServlet调用完整过程

还有一些处理不同异常情况的拦截器。


系统默认都会去执行一个拦截器,这个拦截器基本上都是空方法,是一个private类:

Spring MVC 原理 - DispatcherServlet调用完整过程


返回调用doDIspatch的地方:

Spring MVC 原理 - DispatcherServlet调用完整过程


返回到doService的地方:

Spring MVC 原理 - DispatcherServlet调用完整过程


最后回到httpservlet的service方法:

Spring MVC 原理 - DispatcherServlet调用完整过程



到这里就完成了一次完整的调用过程。


可以发现,整个过程的流程是比较清晰,程序启动时会根据mvc的配置和spring配置来处理配置信息和注解的类。

Servlet处理请求,通过request(主要是url)来获取handler,之后最主要的一个部分就是获取需要注入的参数,最后调用用户方法,处理返回结果。


整个过程中麻烦的地方就是在一些细节的处理上,这些细节未必一开始就有的,一开始应该是一个主要的流程,后续发现问题或者为了通用性做的改进。


相关文章: