HandlerInterceptor

处理器拦截器接口

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
// HandlerInterceptor.java

public interface HandlerInterceptor {

/**
* 拦截处理器,在 {@link HandlerAdapter#handle(HttpServletRequest, HttpServletResponse, Object)} 执行之前
*/
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}

/**
* 拦截处理器,在 {@link HandlerAdapter#handle(HttpServletRequest, HttpServletResponse, Object)} 执行成功之后
*/
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
}

/**
* 拦截处理器,在 {@link HandlerAdapter} 执行完之后,无论成功还是失败
*
* 并且,只有 {@link #preHandle(HttpServletRequest, HttpServletResponse, Object)} 执行成功之后,才会被执行
*/
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
}

}

HandlerExecutionChain

处理器执行链。

构造方法

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
// HandlerExecutionChain.java

/**
* 处理器
*/
private final Object handler;
/**
* 拦截器数组
*/
@Nullable
private HandlerInterceptor[] interceptors;
/**
* 拦截器数组。
*
* 在实际使用时,会调用 {@link #getInterceptors()} 方法,初始化到 {@link #interceptors} 中
*/
@Nullable
private List<HandlerInterceptor> interceptorList;

/**
* 已执行 {@link HandlerInterceptor#preHandle(HttpServletRequest, HttpServletResponse, Object)} 的位置
*
* 主要用于实现 {@link #applyPostHandle(HttpServletRequest, HttpServletResponse, ModelAndView)} 的逻辑
*/
private int interceptorIndex = -1;

/**
* Create a new HandlerExecutionChain.
* @param handler the handler object to execute
*/
public HandlerExecutionChain(Object handler) {
this(handler, (HandlerInterceptor[]) null);
}

/**
* Create a new HandlerExecutionChain.
* @param handler the handler object to execute
* @param interceptors the array of interceptors to apply
* (in the given order) before the handler itself executes
*/
public HandlerExecutionChain(Object handler, @Nullable HandlerInterceptor... interceptors) {
if (handler instanceof HandlerExecutionChain) {
HandlerExecutionChain originalChain = (HandlerExecutionChain) handler;
this.handler = originalChain.getHandler();
// 初始化到 interceptorList 中
this.interceptorList = new ArrayList<>();
CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList); // 逻辑比较简单,就是将前者添加到后者中,即添加到 interceptorList 中
CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList); // 逻辑比较简单,就是将前者添加到后者中,即添加到 interceptorList 中
} else {
this.handler = handler;
this.interceptors = interceptors;
}
}

addInterceptor

添加拦截器到 interceptorList 中

1
2
3
4
5
// HandlerExecutionChain.java

public void addInterceptor(HandlerInterceptor interceptor) {
initInterceptorList().add(interceptor);
}

首先,会调用 #initInterceptorList() 方法,保证 interceptorList 已初始化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// HandlerExecutionChain.java

private List<HandlerInterceptor> initInterceptorList() {
// 如果 interceptorList 为空,则初始化为 ArrayList
if (this.interceptorList == null) {
this.interceptorList = new ArrayList<>();
// 如果 interceptors 非空,则添加到 interceptorList 中
if (this.interceptors != null) {
// An interceptor array specified through the constructor
CollectionUtils.mergeArrayIntoCollection(this.interceptors, this.interceptorList);
}
}
// 置空 interceptors
this.interceptors = null;
// 返回 interceptorList
return this.interceptorList;
}

虽然代码有点长,但是逻辑很简单。实际上,我们将 interceptorList 是 interceptors 的配置。

addInterceptor(HandlerInterceptor interceptor) 方法,添加拦截器们到 interceptorList 中

1
2
3
4
5
6
7
// HandlerExecutionChain.java

public void addInterceptors(HandlerInterceptor... interceptors) {
if (!ObjectUtils.isEmpty(interceptors)) {
CollectionUtils.mergeArrayIntoCollection(interceptors, initInterceptorList());
}
}

getInterceptors

获得 interceptors 数组

1
2
3
4
5
6
7
8
9
10
11
// HandlerExecutionChain.java

@Nullable
public HandlerInterceptor[] getInterceptors() {
// 将 interceptorList 初始化到 interceptors 中
if (this.interceptors == null && this.interceptorList != null) {
this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[0]);
}
// 返回 interceptors 数组
return this.interceptors;
}

applyPreHandle

应用拦截器的前置处理。

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
// HandlerExecutionChain.java

/**
* 应用拦截器的前置处理
*
* Apply preHandle methods of registered interceptors.
* @return {@code true} if the execution chain should proceed with the
* next interceptor or the handler itself. Else, DispatcherServlet assumes
* that this interceptor has already dealt with the response itself.
*/
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
// <1> 获得拦截器数组
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
// <2> 遍历拦截器数组
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
// <3> 前置处理
if (!interceptor.preHandle(request, response, this.handler)) {
// <3.1> 触发已完成处理
triggerAfterCompletion(request, response, null);
// 返回 false ,前置处理失败
return false;
}
// <3.2> 标记 interceptorIndex 位置
this.interceptorIndex = i;
}
}
// <4> 返回 true ,前置处理成功
return true;
}
  • 3处,执行拦截器的前置处理。如果成功,则返回 true ,否则返回 false
  • 3.1处,执行失败,则调用 #triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) 方法,触发已完成处理。注意,此处不是触发当前拦截器的已完成逻辑,而是触发 [0, interceptorIndex) 这几个拦截器已完成的逻辑( 不包括当前这个拦截器 ),并且是按照倒序执行的。返回 false ,因为有拦截器执行失败
  • 3.2处,标记 interceptorIndex 位置

triggerAfterCompletion

触发拦截器的已完成处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// HandlerExecutionChain.java

/**
* Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
* Will just invoke afterCompletion for all interceptors whose preHandle invocation
* has successfully completed and returned true.
*/
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
throws Exception {
// 获得拦截器数组
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
// 遍历拦截器数组
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);
}
}
}
}

applyPostHandle

应用拦截器的后置处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// HandlerExecutionChain.java

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

HandlerInterceptor实现类

MappedInterceptor

实现 HandlerInterceptor 接口,支持地址匹配的 HandlerInterceptor 实现类。

1
2
3
4
5
6
7
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/interceptor/**" />
<mvc:exclude-mapping path="/interceptor/b/*" />
<bean class="com.elim.learn.spring.mvc.interceptor.MyInterceptor" />
</mvc:interceptor>
</mvc:interceptors>

每一个 <mvc:interceptor /> 标签,将被解析成一个 MappedInterceptor Bean 对象。

构造方法

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
// MappedInterceptor.java

/**
* 匹配的路径
*/
@Nullable
private final String[] includePatterns;
/**
* 不匹配的路径
*/
@Nullable
private final String[] excludePatterns;
/**
* 路径匹配器
*/
@Nullable
private PathMatcher pathMatcher;

/**
* HandlerInterceptor 拦截器对象
*/
private final HandlerInterceptor interceptor;

public MappedInterceptor(@Nullable String[] includePatterns, HandlerInterceptor interceptor) {
this(includePatterns, null, interceptor);
}

public MappedInterceptor(@Nullable String[] includePatterns, @Nullable String[] excludePatterns,
HandlerInterceptor interceptor) {
this.includePatterns = includePatterns;
this.excludePatterns = excludePatterns;
this.interceptor = interceptor;
}

public MappedInterceptor(@Nullable String[] includePatterns, WebRequestInterceptor interceptor) {
this(includePatterns, null, interceptor);
}

public MappedInterceptor(@Nullable String[] includePatterns, @Nullable String[] excludePatterns,
WebRequestInterceptor interceptor) {

this(includePatterns, excludePatterns, new WebRequestHandlerInterceptorAdapter(interceptor));
}
  • includePatterns + excludePatterns + pathMatcher 属性,匹配路径。
  • interceptor 拦截器

matches

判断路径是否匹配

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
// MappedInterceptor.java

/**
* Determine a match for the given lookup path.
* @param lookupPath the current request path
* @param pathMatcher a path matcher for path pattern matching
* @return {@code true} if the interceptor applies to the given request path
*/
public boolean matches(String lookupPath, PathMatcher pathMatcher) {
PathMatcher pathMatcherToUse = (this.pathMatcher != null ? this.pathMatcher : pathMatcher);
// 先排重
if (!ObjectUtils.isEmpty(this.excludePatterns)) {
for (String pattern : this.excludePatterns) {
if (pathMatcherToUse.match(pattern, lookupPath)) { // 匹配
return false;
}
}
}
// 特殊,如果包含为空,则默认就是包含
if (ObjectUtils.isEmpty(this.includePatterns)) {
return true;
}
// 后包含
for (String pattern : this.includePatterns) {
if (pathMatcherToUse.match(pattern, lookupPath)) { // 匹配
return true;
}
}
return false;
}

拦截方法实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// MappedInterceptor.java

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return this.interceptor.preHandle(request, response, handler);
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
this.interceptor.postHandle(request, response, handler, modelAndView);
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
this.interceptor.afterCompletion(request, response, handler, ex);
}

拦截器配置

在 Spring MVC 中,有多种方式,配置拦截器

<mvc:interceptors /> 标签

  • 每一个 <mvc:interceptor /> 标签会被解析成  MappedInterceptor 对象,注册到 Spring IOC 容器中。
  • 在 AbstractHandlerMapping 的 #detectMappedInterceptors(List mappedInterceptors) 方法中,会扫描 MappedInterceptor Bean 。
1
2
3
4
5
6
7
8
9
// AbstractHandlerMapping.java

protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
// 扫描已注册的 MappedInterceptor 的 Bean 们,添加到 mappedInterceptors 中
// MappedInterceptor 会根据请求路径做匹配,是否进行拦截。
mappedInterceptors.addAll(
BeanFactoryUtils.beansOfTypeIncludingAncestors(
obtainApplicationContext(), MappedInterceptor.class, true, false).values());
}