SpringMVC大致过程

MVC

MVC是一种框架模式,将M和V的实现代码分离。

  1. M(Model):模型,业务规则。处理请求、返回数据,数据可以被多个视图使用。
  2. V(View):视图,就是你能看到并能交互的界面。
  3. C(Controller):控制器,负责接收用户的请求去调用哪个M去处理,然后再返回确定哪个V显示数据。


Servlet

为什么在这里讲一下Servlet?其实SpringMVC就是一个Servlet,所以弄清楚Servlet的过程,SpringMVC的就类似了。

我们现来看一下Servlet的类图关系。



SpringMVC

SpringMVC和Servlet的关系


大致过程

  1. 初始化的时候用了一个Map保存URL和Controller类的对应关系
  2. 根据请求的URL找到对应的Controller,然后从Controller中找到处理请求的方法
  3. 将请求参数绑定到方法的形参上,执行方法处理请求,并返回结果视图


九大组件

在DispathcherServlet类中,我们可以找到SpringMVC的九大组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/**
* 九大组件之一
* 用于处理上传请求。将普通请求封装
*/
@Nullable
private MultipartResolver multipartResolver;

/**
* 九大组件之一:本地语言解析器
* 从请求中解析出Local。主要用于i18n。
*/
@Nullable
private LocaleResolver localeResolver;

/**
* 九大组件之一:模板解析器
* 负责从请求中解析出主题名,主题就是样式、图片以及它们所形成的显示效果的集合。相关类:
* ThemeSource:根据主题名查找具体的主题
*/
@Nullable
private ThemeResolver themeResolver;


/**
* 九大组件之一
* 用来查找Handler。可以是类也可以是方法。
* 比如标注了@RequestMapping的每个方法都可以看成一个Handler
*/
@Nullable
private List<HandlerMapping> handlerMappings;

/**
* 九大组件之一:适配器
* 因为Servlet的方法结构都是doService(HttpServletRequest req,
* HttpServletResponse resp)形式的,
* 将SpringMVC中的Handler转为这种格式。
*/
@Nullable
private List<HandlerAdapter> handlerAdapters;

/**
* 九大组件之一:异常处理器
* 处理Handler产生的异常情况的组件
*/
@Nullable
private List<HandlerExceptionResolver> handlerExceptionResolvers;

/**
* 九大组件之一
* 从请求中获取ViewName
*/
@Nullable
private RequestToViewNameTranslator viewNameTranslator;

/**
* 九大组件之一
* 用于管理FlashMap。FlashMap用于重定向时的参数传递
*/
@Nullable
private FlashMapManager flashMapManager;

/**
* 九大组件之一:视图解析器
* 将String类型的视图名和Locale解析为View类型的视图,只有一个resolveViewName()方法。
*/
@Nullable
private List<ViewResolver> viewResolvers;


源码解析

SpringMVC初始化

首先我们从Servlet的初始化init()开始,在DispatcherServlet类中,我们并没有发现Servlet的初始化方法,所以我们去父类中去找找。在HttpServletBean中我们终于发现了init()方法。


我们可以看见这里只是对一些初始的属性参数进行了设置,具体通过子类调用initServletBean()这个方法来调用。我们点进去看看


我们可以看到子类FrameworkServlet的initServletBean()方法中添加了一些日志相关的信息,以及一个重要的方法**initWebApplicationContext()**,这个方法最终会调用我们IoC容器的refresh()方法。剩下的initFrameworkServlet()这个方法是个空方法,可以留给我们进行扩展。我们继续跟进initWebApplicationContext()方法。


我们进入createWebApplicationContext()方法中


configureAndRefreshWebApplicationContext()方法,终于我们看见了refresh()方法


其实就是IoC容器的初始化。

我们接着看SpringMVC九大组件的初始化

在DispatcherServlet中,onRefresh()方法和initStrategies()方法

到此,SpringMVC初始化差不多就完成了,下面去看看SpringMVC是如何处理请求的。



SpringMVC处理请求

在doService()方法中。其中最核心的方法是doDispatch()方法。


我们进入doDispatch()。

这里面的处理大致流程是:

  1. 先判断一下是不是文件上传
  2. 通过getHandler()方法找到请求对应的处理handler的Bean实例以及添加一些拦截器,封装成一个HandlerExecutionChain请求处理链对象
  3. 获取一个支持的处理适配器HandlerAdapter。getHandlerAdapter()
  4. 调用给定的handler处理请求,执行并返回结果视图。handle()
  5. 处理一下处理的结果,可以是ModelAndView或者是一个异常。processDispatchResult()


我们先去看看getHandler()方法。


继续点进去,在AbstractHandlerMapping的getHandler()方法中。


是不是看见了一个我们很熟悉的方法?getBean()。这时候我们就获取到了对应handler的实例了,然后就是调用getHandlerExecutionChain()方法,将一些拦截器与之封装为一个HandlerExecutionChain。


这时候一个HandlerExecutionChain就完成了。

然后我们去看看getHandlerAdapter()方法。


接下来是handle()方法,我们点进去看看,他会调用AbstractHandlerMethodAdapter类的handle方法,我们会发现它最后会调用handleInternal()这个方法,交给子类去实现。


进入handleInternal()方法


我们可以看见都会调用invokeHandlerMethod()这个方法,跟进去。都是些什么addXXX、setXXX、registerXXX方法。最重要的是invokeAndHandle()方法,它完成了将请求中的参数和方法中的参数进行绑定,通过@RequestParam注解或者是ASM框架。


invokeAndHandle()方法


然后就是返回相应的ModelAndView了。

接下来对ModelAndView进行处理,在processDispatchResult()方法中。可以看见对异常的处理和对正常视图的处理。


其中调用了render()方法对视图进行渲染。

到此,一个请求的处理差不多就完成了。SpringMVC的工作也差不多结束了。其中还有些细节的地方,比如在将请求中的参数和方法的参数绑定时ASM框架的使用,感兴趣可以去看看。



关于调用了refresh()方法,九大组件什么时候初始化。

前面我们知道看初始化的时候,如果进行了refresh(),下面的onRefresh()方法好像就不能调用了啊,那九大组件到底是什么时候初始化的呢?

这其实用到了事件监听器。我们都知道IoC容器的refresh()方法中有事件传播器的注册(initApplicationEventMulticaster()方法)、事件的发布(finishRefresh())方法。其实就是在事件发布的时候,调用了SpringMVC九大组件的初始化。我们后续再讲。

作者

zhaommmmomo

发布于

2021-04-26

更新于

2023-06-27

许可协议