springMVC(2) 攔截器的實(shí)現(xiàn)原理二

今天閱讀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)容
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 在使用SpringMVC攔截器的時(shí)候,我們接觸的最多的便是HandlerInterceptor接口,因?yàn)槲覀兯械?..
    谷和阿秋閱讀 8,655評(píng)論 0 3
  • 你要知道的SpringMVC DispatcherServlet執(zhí)行流程及源碼分析都在這里 轉(zhuǎn)載請(qǐng)注明出處 htt...
    WWWWDotPNG閱讀 10,448評(píng)論 2 25
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,660評(píng)論 19 139
  • 海的味道是天空味的 不信你看遠(yuǎn)方 海天一色 退潮的沙灘上 你留下一串腳印 梅花狀的
    雀替閱讀 547評(píng)論 0 0
  • 2013年至2014年,我第一次考研。那時(shí)候,由于心態(tài)不好,或許根本原因是因?yàn)樽约旱幕A(chǔ)知識(shí)掌握的不夠牢固,從而導(dǎo)...
    歸塵2017閱讀 304評(píng)論 7 2

友情鏈接更多精彩內(nèi)容