SpringMVC的一次调用

前言

SpringMVC其实我觉得可讲的还不是很多,但是曾经面试最喜欢的问的就是SpringMVC的一次调用过程,不知道现在是什么情况。

SpringMVC的作用

首先我们要知道SpringMVC是以Servlet为基础的一个框架,属于web层的MVC框架,用来替代Servlet来做http请求的响应和处理。通过它我们可以通过几个简单的注解就可以高效的处理请求和返回数据。

前面容器已经讲过Servlet,在看SpringMVC就比较简单了。我们知道Servlet主要用来对请求的初始化,处理已经返回数据。假如我们没有Servlet那么我们对每个请求都要不厌其烦的去配置对每个请求的拦截,然后对每个请求做自己业务处理。SpringMVC就将其做了简化动作以便我们高效开发。

SpringMVC的调用过程

直接抛出一个网上随处可找的图,然后直接说明结果,最后简单讲解一下其大致思路

SpringMVC的一次调用

上图算是找到的一张比较完整的图。实际我也不会记得这么详细,大致的过程为

  1. 客户端发起请求,进入DispatcherServlet
  2. DispatcherServlet通过传入的url找到对应的Handle(即Controller)
  3. 最后调用其逻辑
  4. 获取到返回值后,经过视图解析器,返回Html(如果是ajax就直接返回数据)

这里的逻辑我写的比较简单,不想弄得太复杂

DispatcherServlet

DispatcherServlet是SpringMVC的核心功能,本质是一个Servlet。这个Servlet逻辑处理比较多。但是也好理解。直接看代码了。不做配置说明了

看代码之前先要了解一下其的类的关系图

dispatcherServlet-class

可以明显的看到他还是集成了Servlet,而且是HttpServlet只不过他又加了几层封装(每次看Spring的代码,其实都可以猜到了,它的风格就这样),那么如果肯定去找doService方法咯

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
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
//---忽略代码--
try {
doDispatch(request, response);
}
finally {
// ---忽略代码---
}
}

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 {
// 对文件的处理
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 获取handler,通过RequestMappingHandlerMaping获取
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}

// 获取Handler适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// 对浏览器请求的特殊处理
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;
}
}

if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}

// 实际调用Handle的方法,返回封装个后的ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

if (asyncManager.isConcurrentHandlingStarted()) {
return;
}

applyDefaultViewName(processedRequest, mv);
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) {
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);
}
}
}
}

基本源码也就这里了。

这里讲的不很仔细,后面再补充!