Fork me on GitHub

SpringMVC

注意:所有文章除特别说明外,转载请注明出处.

SpringMVC 解析

1.什么是拦截器:

SpringMVC提供了拦截器机制:

HandlerInterceptor:SpringMVC

​ 允许在目标方法之前进行一些拦截工作,或者在目标方法之后进行一些其他的处理。

perHandle:在目标方法执行之前,返回boolean,return true(放行);return false 不放行;

postHandle:在目标方法执行之后调用,目标方法调用之后;

aftercompletion:在整个请求完成之后,来到目标页面之后;资源响应之后;

2.拦截器怎么使用:

1.实现HandlerInterceptor 接口 实现三个方法!

2.配置这个拦截器需要拦截那些请求

  1. 拦截器是一个接口!
  2. 实现HandleInterceptor接口:
  3. 配置拦截器

3.拦截器的运行流程

3.1.正常运行流程:

​ 拦截器的preHandle———目标方法———拦截器的postHandle———页面———拦截器的afterCompletion

3.2.其他流程:
1. 只要preHandle 不放行,其他流程均完蛋。
2. 放行之后,目标方法炸了,preHandle 放行,postHandle没有执行,**但是afterCompletion执行了。**
3.3.多个拦截器的流程:

正常流程:

异常流程:

​ 1)、First只要不放行,后面全都没有

​ 2)、First 放行,但是Second 不放行。但是First 的afterCompletion还要执行。

​ 总结:==已放行的拦截器的 afterCompletion 都要执行==

==拦截器的 preHandle 是顺序执行的,但是 postHandle 和 afterCompletion 是逆序执行的。==

3.拦截器的源码流程

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
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);

// Determine handler for the current request.
//先获取到处理器,并拿到执行链
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}

// Determine handler adapter for the current request.
//在获取适配器
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;
}
}
//执行所有拦截器的preHandle (返回false 就是 true 就直接返回了)
//如果有一个拦截器返回false 那么目标方法之后都不会执行了。
//直接跳到 afterCompletion 执行
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}

// Actually invoke the handler.
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);
}

//页面渲染(如果渲染失败出现了异常,catch中也会执行afterCompletion)
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);
}
}
}
}
PreHandle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];

//preHandle - true -false
if (!interceptor.preHandle(request, response, this.handler)) {
//先去执行 afterCompletion
triggerAfterCompletion(request, response, null);
//返回false
return false;
}
//记录了索引
this.interceptorIndex = i;
}
}
return true;
}
PostHandle
1
2
3
4
5
6
7
8
9
10
11
12
13
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {

HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {

//逆序执行
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
processDispatchResult
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
        @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
        @Nullable Exception exception) throws Exception {

    boolean errorView = false;

    if (exception != null) {
        if (exception instanceof ModelAndViewDefiningException) {
            logger.debug("ModelAndViewDefiningException encountered", exception);
            mv = ((ModelAndViewDefiningException) exception).getModelAndView();
        }
        else {
            Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
            mv = processHandlerException(request, response, handler, exception);
            errorView = (mv != null);
        }
    }

    // Did the handler return a view to render?
    if (mv != null && !mv.wasCleared()) {

        //页面渲染
        render(mv, request, response);
        if (errorView) {
            WebUtils.clearErrorRequestAttributes(request);
        }
    }
    else {
        if (logger.isDebugEnabled()) {
            logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
                    "': assuming HandlerAdapter completed request handling");
        }
    }

    if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
        // Concurrent handling started during a forward
        return;
    }
    if (mappedHandler != null) {

        //页面正常,执行afterCompletion,即使没有走到这里afterCompletion 也会执行
        mappedHandler.triggerAfterCompletion(request, response, null);
    }
}
triggerAfterCompletion
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
        throws Exception {

    HandlerInterceptor[] interceptors = getInterceptors();
    if (!ObjectUtils.isEmpty(interceptors)) {

        //逆序执行(通过之前记录的索引),把之前所有放行的拦截器的AfterCompletion全部执行
        for (int i = this.interceptorIndex; i >= 0; i--) {
            HandlerInterceptor interceptor = interceptors[i];
            try {
                interceptor.afterCompletion(request, response, this.handler, ex);
            }
            catch (Throwable ex2) {
                logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
            }
        }
    }
}

流程总结:

就一句话:==所有已经放行的拦截器的afterCompletion 一定会执行==

SpringMVC的流程总结:

1、所有的请求,==前端控制器(DispatcherServlet),调用doDispatch==进行处理;

2、根据==HandleMapping中保存的映射信息==找到,处理当前请求的==,处理器执行链==(包含了拦截器)。

3、==根据当前处理器找到他的适配器==;

4、==拦截器的preHandle 先执行==

5、==适配器执行目标方法==

​ 1)、ModelAttribute注解标注的方法提前执行

​ 2)、执行目标方法的时候(确定目标方法的参数)

​ 1)有注解:

​ 2)没注解:

​ 1)、看看是否是Model 、Map 或者其他的

​ 2)、如果是自定义类型

​ 1)先从隐含模型中看有没有,如果有就从隐含模型中拿

​ 2)如果没有,看看是否是SessionAttributes标注的属性,如果是从session中拿,拿不到抛出异常

​ 3)如果都不是,利用反射创建对象。

6、==拦截器的 postHandle 执行==

7、处理结果(==页面渲染流程==)

1)、如果有异常使用==异常解析器==处理异常,返回ModelAndView

2)、调用 ==render== 进行页面渲染

​ 1)视图解析器通过视图名得到视图对象

​ 2)、视图对象调用 render 方法;

3)、==执行拦截器的afterCompletion==

SpringMVC流程图:

本文标题:SpringMVC

文章作者:Bangjin-Hu

发布时间:2019年10月15日 - 09:22:26

最后更新:2020年03月30日 - 07:59:03

原始链接:http://bangjinhu.github.io/undefined/SpringMVC/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

Bangjin-Hu wechat
欢迎扫码关注微信公众号,订阅我的微信公众号.
坚持原创技术分享,您的支持是我创作的动力.