Spring MVC源码解析(一)——概况

一、Spring MVC

Spring MVC 基于模型-视图-控制器(Model-View-Controller, MVC)模式实现,并且很好的实现了软件设计中的开闭原则(即对扩展开放,对修改关闭),当因为业务需要对Spring MVC做些定制化处理时,就会发现Spring MVC对功能扩展是极其友好的、在后续的源码解析系列文章中我们会陆续看到Spring MVC在处理请求的各个步骤中都可以定制所需要的功能。

二、Spring MVC 整体框架

image

整个系列的文章都会围绕这张图进行,会对每一个步骤进行详细讲解。
首先我们先来看一下 DispatcherServlet diagram

可以看到蓝色的继承关系到 Servlet 相信大家在学习MVC框架之前对 HttpServlet
非常的熟悉,目前还有一些老项目在使用原生的 java servlet进行项目开发。我们看一下 servlet接口最重要的方法签名:

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
复制代码 /**
* Called by the servlet container to allow the servlet to respond to
* a request.
*
* <p>This method is only called after the servlet's <code>init()</code>
* method has completed successfully.
*
* <p> The status code of the response always should be set for a servlet
* that throws or sends an error.
*
*
* <p>Servlets typically run inside multithreaded servlet containers
* that can handle multiple requests concurrently. Developers must
* be aware to synchronize access to any shared resources such as files,
* network connections, and as well as the servlet's class and instance
* variables.
* More information on multithreaded programming in Java is available in
* <a href="http://java.sun.com/Series/Tutorial/java/threads/multithreaded.html">
* the Java tutorial on multi-threaded programming</a>.
*
*
* @param req the <code>ServletRequest</code> object that contains
* the client's request
*
* @param res the <code>ServletResponse</code> object that contains
* the servlet's response
*
* @exception ServletException if an exception occurs that interferes
* with the servlet's normal operation
*
* @exception IOException if an input or output exception occurs
*
*/

public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;

这个方法是servlet处理web请求的入口。Spring MVCDispatchSerlvet还分装了一层FrameWorkServlet用于统一处理所有不同方法类型(GETPOST等)的请求

三、各组件的基本介绍。

我们从一个Http请求的角度,来大致了解Spring MVC是处理请求的大致流程(例如,到controller方法加@ResponseBody时就不会有视图解析这一步)。

1、web container 接收到一个请求,容器调用已经注册好的DispatcherServlet,后者通过Request对象到RequestMapping
获取对应的 handler(即controller层实际调用的方法)。

2、执行interceptorpreHandler()方法。

3、执行第一步获取的Controller方法,并返回ModelAndView

4、执行interceptorpostHandler()方法。

5、视图渲染,执行ViewResolve.resolveViewName()方法回去视图文件。

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
复制代码/**
* 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 {
//判断请求是否是 multipart post (常见的有 post 表单提交的数据)
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);

// Determine handler for the current request.
//通过request获取handler,包括 intercepter 信息
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}

// Determine handler adapter for the current request.
//获取 handler 适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//调用 intercepter.perHandler()方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}

// Actually invoke the handler.
//调用controller方法发挥 ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//当 ModelAndView 中不包含视图时获取默认视图
applyDefaultViewName(processedRequest, mv);
//调用 intercepter.perHandler()方法
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);
}
//视图渲染并将渲染后的视图文件(html)或者 json 等写入Response body 返回给浏览器
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}

总结

本文主要介绍了Spring MVC的一些概念以及请求执行的大致过程。后续的文章将继续分析Spring MVC的各个组件,以及如何根据自己的项目定制相应的功能。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%