今天閱讀springMVC HandlerMapping的源碼時(shí)發(fā)現(xiàn)自己還漏掉了一些攔截器的部分。
這次我們直接從配置文件的解析部分入手。
InterceptorsBeanDefinitionParser類
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;
}
}
這個(gè)類的作用很容易理解,就是將配置轉(zhuǎn)化為對(duì)應(yīng)的攔截器類。但是如果注意一下,我們會(huì)發(fā)現(xiàn)該解析類是將其轉(zhuǎn)化為MappedInterceptor類。那么接下來(lái)我們就去閱讀一下MappedInterceptor類部分。
MappedInterceptor類
該類中包含如下幾個(gè)屬性
@Nullable
private final String[] includePatterns;
@Nullable
private final String[] excludePatterns;
private final HandlerInterceptor interceptor;
@Nullable
private PathMatcher pathMatcher;
不難看出其中比接口HandlerInterceptor多了includePattern、excludePattern和pathMatcher。這三個(gè)屬性的意思我們不難猜出來(lái)。其中我們需要關(guān)注的是includePattern和excludePattern。接下來(lái)看該類中的這樣一個(gè)方法。
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;
}
}
仔細(xì)閱讀該段代碼,我們不難讀出MappedInterceptor的匹配規(guī)則:(我們不妨就當(dāng)返回true為攔截,返回false為不攔截)
如果路徑在excludePatterns中,則不攔截。如果不在,那么若includePatterns為空,則攔截,否則在includePatterns中才攔截。
比較關(guān)鍵的兩個(gè)地方是:
- 優(yōu)先判excludePatterns
- 若includePatterns列表為空且請(qǐng)求不在excludePatterns的情況下全部攔截,否則只攔截includePatterns中的內(nèi)容