MVC模式
顾名思义,SpringMVC框架是基于MVC设置模式设计的,即Model(模型)-View(视图)-Controller(控制)模式。
这个模式认为,应用程序不论简单或复杂,从结构上看,都可以分成三层。
- 最上面的一层,是直接面向最终用户的”视图层”(View)。它是提供给用户的操作界面,是程序的外壳。
- 最底下的一层,是核心的”数据层”(Model),也就是程序需要操作的数据或信息。
- 中间的一层,就是”控制层”(Controller),它负责根据用户从”视图层”输入的指令,选取”数据层”中的数据,然后对其进行相应的操作,产生最终结果。
这三层是紧密联系在一起的,但又是互相独立的,每一层内部的变化不影响其他层。每一层都对外提供接口(Interface),供上面一层调用。这样一来,软件就可以实现模块化,修改外观或者变更数据都不用修改其他层,大大方便了维护和升级。
SpringMVC的执行流程
SpringMVC的执行流程可以概括为下图:
本篇论述的比较简单,网上这篇文章写的比较详细可以作为参考:Spring MVC 源码分析 - 一个请求的旅行过程
下面结合源代码和上图来说明:
1. 请求被发送到DispatcherServlet
(中央控制器)。
DispatcherServlet
是整个控制流程的核心,一般我们在 SpringMVC 项目的 web.xml 文件中都要配置这个 Servlet,并且拦截所有的请求都进入到这个 Servlet ,并且最终由它的 doDispatch(HttpServletRequest request, HttpServletResponse response)
方法来处理这些请求。
web.xml文件中的配置:1
2
3
4
5
6
7
8<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
DispatcherServlet
的doDispatch
方法概览: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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102/**
* Process the actual dispatching to the handler.
* <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
* The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
* to find the first that supports the handler class.
* <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
* themselves to decide which methods are acceptable.
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception in case of any kind of processing failure
*/
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
//获取异步管理器
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
//检测请求是否为上传请求,如果是则通过 multipartResolver 将其封装成 MultipartHttpServletRequest 对象
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 获得请求对应的 HandlerExecutionChain 对象(HandlerMethod 和 HandlerInterceptor 拦截器们)
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) { //如果获取不到,则根据配置抛出异常或返回 404 错误
noHandlerFound(processedRequest, response);
return;
}
// 获得当前 handler 对应的 HandlerAdapter 对象
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 处理有Last-Modified请求头的场景
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//执行拦截器们的 preHandler 方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 真正的调用 handler 方法,也就是执行对应的方法,并返回视图
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//如果是异步,立即返回
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//无视图的情况下设置默认视图名称
applyDefaultViewName(processedRequest, mv);
//执行拦截器们的 postHandler 方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
//处理正常和异常的请求调用结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
//processDispatchResult处理异常,则执行拦截器的 afterCompletion 方法。
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
//processDispatchResult处理异常,则执行拦截器的 afterCompletion 方法。
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// 如果是上传请求则清理资源
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
2.通过HandlerMapping
得到HandlerExecutionChain
(处理器执行链)
DispatcherServlet
找到请求所对应的HandlerMapping
实例,再由HandlerMapping
获取处理该请求的处理器(handler)、拦截器们(intercepter)列表,并且包装在HandlerExecutionChain
对象中。
1 | /** |
3.获取处理器对应的HandlerAdapter
得到HandlerExecutionChain
了后,还不能直接调用处理器,需要进行对处理器进行适配,找到处理器对应的HandlerAdapter
。
1 | /** |
4.HandlerAdapter
调用处理器并返回一个ModelAndView
对象
HandlerAdapter
通过反射方法调用处理器,处理完成之后返回一个ModelAndView
对象,ModelAndView
对象中包装了模型数据和视图名称。
5.ViewResolver
根据ModelAndView
对象的 viewName 解析视图,若能解析成功,返回相应的View
视图对象。
ViewResolver会根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象。
1 |
|
6.最后View
视图对象根据ModelAndView
对象的 model 渲染视图,并将渲染结果返回给用户。
渲染视图就是将模型数据填充至视图中。springmvc框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等,我们最常用的视图就是jsp。