今天阅读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中的内容