目录
  1. InterceptorsBeanDefinitionParser类
  2. MappedInterceptor类
springMVC(2) 拦截器的实现原理二

今天阅读springMVC HandlerMapping的源码时发现自己还漏掉了一些拦截器的部分。

这次我们直接从配置文件的解析部分入手。

InterceptorsBeanDefinitionParser类

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
class InterceptorsBeanDefinitionParser implements BeanDefinitionParser {

@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext context) {
context.pushContainingComponent(
new CompositeComponentDefinition(element.getTagName(), context.extractSource(element)));

RuntimeBeanReference pathMatcherRef = null;
if (element.hasAttribute("path-matcher")) {
pathMatcherRef = new RuntimeBeanReference(element.getAttribute("path-matcher"));
}

List<Element> interceptors = DomUtils.getChildElementsByTagName(element, "bean", "ref", "interceptor");
for (Element interceptor : interceptors) {
RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
mappedInterceptorDef.setSource(context.extractSource(interceptor));
mappedInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

ManagedList<String> includePatterns = null;
ManagedList<String> excludePatterns = null;
Object interceptorBean;
if ("interceptor".equals(interceptor.getLocalName())) {
includePatterns = getIncludePatterns(interceptor, "mapping");
excludePatterns = getIncludePatterns(interceptor, "exclude-mapping");
Element beanElem = DomUtils.getChildElementsByTagName(interceptor, "bean", "ref").get(0);
interceptorBean = context.getDelegate().parsePropertySubElement(beanElem, null);
}
else {
interceptorBean = context.getDelegate().parsePropertySubElement(interceptor, null);
}
mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, includePatterns);
mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, excludePatterns);
mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(2, interceptorBean);

if (pathMatcherRef != null) {
mappedInterceptorDef.getPropertyValues().add("pathMatcher", pathMatcherRef);
}

String beanName = context.getReaderContext().registerWithGeneratedName(mappedInterceptorDef);
context.registerComponent(new BeanComponentDefinition(mappedInterceptorDef, beanName));
}

context.popAndRegisterContainingComponent();
return null;
}

private ManagedList<String> getIncludePatterns(Element interceptor, String elementName) {
List<Element> paths = DomUtils.getChildElementsByTagName(interceptor, elementName);
ManagedList<String> patterns = new ManagedList<>(paths.size());
for (Element path : paths) {
patterns.add(path.getAttribute("path"));
}
return patterns;
}

}

这个类的作用很容易理解,就是将配置转化为对应的拦截器类。但是如果注意一下,我们会发现该解析类是将其转化为MappedInterceptor类。那么接下来我们就去阅读一下MappedInterceptor类部分。

MappedInterceptor类

该类中包含如下几个属性

1
2
3
4
5
6
7
8
9
10
@Nullable
private final String[] includePatterns;

@Nullable
private final String[] excludePatterns;

private final HandlerInterceptor interceptor;

@Nullable
private PathMatcher pathMatcher;

不难看出其中比接口HandlerInterceptor多了includePattern、excludePattern和pathMatcher。这三个属性的意思我们不难猜出来。其中我们需要关注的是includePattern和excludePattern。接下来看该类中的这样一个方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public boolean matches(String lookupPath, PathMatcher pathMatcher) {
PathMatcher pathMatcherToUse = (this.pathMatcher != null) ? this.pathMatcher : pathMatcher;
if (this.excludePatterns != null) {
for (String pattern : this.excludePatterns) {
if (pathMatcherToUse.match(pattern, lookupPath)) {
return false;
}
}
}
if (ObjectUtils.isEmpty(this.includePatterns)) {
return true;
}
else {
for (String pattern : this.includePatterns) {
if (pathMatcherToUse.match(pattern, lookupPath)) {
return true;
}
}
return false;
}
}

仔细阅读该段代码,我们不难读出MappedInterceptor的匹配规则:(我们不妨就当返回true为拦截,返回false为不拦截)

如果路径在excludePatterns中,则不拦截。如果不在,那么若includePatterns为空,则拦截,否则在includePatterns中才拦截。

比较关键的两个地方是:

  • 优先判excludePatterns
  • 若includePatterns列表为空且请求不在excludePatterns的情况下全部拦截,否则只拦截includePatterns中的内容
文章作者: 谷河
文章链接: https://www.lyytaw.com/spring/springMVC(2)-%E6%8B%A6%E6%88%AA%E5%99%A8%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86%E4%BA%8C/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 谷河|BLOG