インターセプターとSpring MVCのソースコード解析中

なぜ起源、ルールに合致する研究インターセプタは適用されません

@Configuration("admimWebConfig")
public class WebConfiguration implements WebMvcConfigurer {
 public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(getServiceAuthRestInterceptor()).
                addPathPatterns(getIncludePathPatterns());
     
    }
}

見つけることができ、インターセプタは内部登録に注入されます

public InterceptorRegistration addInterceptor(HandlerInterceptor interceptor) {
        InterceptorRegistration registration = new InterceptorRegistration(interceptor);
        this.registrations.add(registration);
        return registration;
    }

アイデアによって、あなたは、この方法だけで使用されている登録を見ることができます

protected List<Object> getInterceptors() {
        return this.registrations.stream()
                .sorted(INTERCEPTOR_ORDER_COMPARATOR)
                .map(InterceptorRegistration::getInterceptor)
                .collect(Collectors.toList());
    }

そして、この方法はWebMvcConfigurationSupportここで呼び出され
、この変数を使用することがあり、このクラスのメンテナンスインターセプタ変数が、見つかったアイデアインターセプタによってのみ、次のメソッドを返すために、

protected final Object[] getInterceptors() {
        if (this.interceptors == null) {
            InterceptorRegistry registry = new InterceptorRegistry();
            addInterceptors(registry);
            registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService()));
            registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider()));
            this.interceptors = registry.getInterceptors();
        }
        return this.interceptors.toArray();
    }

上記の方法は、このメソッドの呼び出しWebMvcConfigurationSupportです

@Bean
    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
        RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
        mapping.setOrder(0);
    // 可以看到,是RequestMappingHandlerMapping的setInterceptors的拦截
//器调用了,也就是说,RequestMappingHandlerMapping维护了所有的拦截器
// 维护在interceptors这个变量中
    mapping.setInterceptors(getInterceptors());
    ...
        return mapping;
    }

Spring MVCのソースコード解析は、それは、インターセプタを呼び出すためにアップすると以前は、doDispatchのメソッドDispatchServletに呼ばれています

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
                      ...
// 找到能处理这个请求的handlerMapping
// 这里找到的handlerMapping,已经初始化过了所有的拦截器
// 这里通过handlermapping,获取HandlerExecutionChain,这里会过滤掉不匹配的拦截器
                mappedHandler = getHandler(processedRequest);
    ...
// 这里会调用拦截器
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
                         ...            
    }

インターセプタ・メソッドの呼び出しを参照してください。
すでにインターセプタをフィルタリングされ、かつインターセプターフィルタをマッチしていないここでインターセプタ変数のHandlerExecutionを発見したデバッグを
この変数は、それの終わりにインターセプタを割り当てられていますか?そして、アイデアが開発中のデバッグプロセスは、有効な値に割り当てられない場所インタセプタはありません、最後にHandlerExecutionインターセプタの値は来る方法ですか?
それは非常に奇妙だった、となぜですか?それはそれのどこ値はありますか?
その後、ヘッド建設HandlerExecutionコードを通じて、私たちはその後、オフヨーヨーが値を変更する値ではなく、直接の割り当てを変更するメソッドを追加し、インターセプタはコレクションです、あなたがリターンしてこのコレクションに取得することができ、事を見落としが見つかります

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HandlerInterceptor[] interceptors = getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            for (int i = 0; i < interceptors.length; i++) {
                HandlerInterceptor interceptor = interceptors[i];
                if (!interceptor.preHandle(request, response, this.handler)) {
                    triggerAfterCompletion(request, response, null);
                    return false;
                }
                this.interceptorIndex = i;
            }
        }
        return true;
    }
public HandlerInterceptor[] getInterceptors() {
        if (this.interceptors == null && this.interceptorList != null) {
            this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]);
        }
        return this.interceptors;
    }

それはインターセプタを除外、コード行であります

                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        if (this.handlerMappings != null) {
            for (HandlerMapping hm : this.handlerMappings) {
                if (logger.isTraceEnabled()) {
                    logger.trace(
                            "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
                }
//这行代码
                HandlerExecutionChain handler = hm.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
        }
        return null;
    }
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        Object handler = getHandlerInternal(request);
        if (handler == null) {
            handler = getDefaultHandler();
        }
        if (handler == null) {
            return null;
        }
        // Bean name or resolved handler?
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = obtainApplicationContext().getBean(handlerName);
        }
// 这行代码
        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
        if (CorsUtils.isCorsRequest(request)) {
            CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
            CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
            CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
            executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
        }
        return executionChain;
    }

最後に、ここで除外され、ここに配置することインターセプタと一致していません

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
        HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
                (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
// 这是我们请求的路径
        String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
        for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
            if (interceptor instanceof MappedInterceptor) {
                MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
// 这里进行匹配
                if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                    chain.addInterceptor(mappedInterceptor.getInterceptor());
                }
            }
            else {
                chain.addInterceptor(interceptor);
            }
        }
        return chain;
    }

フィルタリングされたフィルタがどのように見て
、直接このインターセプタを追加しない、つまり、除外(excludeUrlで、で、excludeUrl濾過により、まず、ありますが、多くの人がそれを見つけるだろうし、excludeUrlに追加無効ましたこれはなぜでしょうか?コードの下を見て
、その後includeUrlに従ってフィルタリング、includeUrlが空である、つまり、このフィルタを追加し、そのノーカスタムincludeUrl、インターセプタすべての場合。
includeUrlが空でない場合は、インターセプトをマッチング

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

これは、特定の一致コードである:AntPathMatcherクラス、すなわちAUTパターンマッチング、詳細なマッチングAUTの方法は、多くの百度があります。
コードの最初の行で批判的な視線

protected boolean doMatch(String pattern, String path, boolean fullMatch,
            @Nullable Map<String, String> uriTemplateVariables) {
// pathSeparator路径分割符是“/”,path如果以“/”分割,而pathSeparator不以“/”分
//割,则直接返回false。也就是说,如果访问swagger-ui.html页面,这里的path
//是/swagger-ui.html,而不管配置的excludeUrl是:**swagger.html还是
//*swagger.html,都将返回false,匹配不到
        if (path.startsWith(this.pathSeparator) != pattern.startsWith(this.pathSeparator)) {
            return false;
        }
    ...
        return true;
    }

だから、AntPathMatcherパターンは、それが何であるかに一致しますか?
アリのルールに一致するように使用AntPathMatcher名前は、私たちが見て、参照してください。

文字のワイルドカードの説明

?1文字にマッチします

*試合ゼロ以上の文字(除く/ディレクトリの区切り)

*ゼロ以上のディレクトリとディレクトリにマッチします

いくつかの例を参照してください:
/swagger.htmlに一致/*swagger.html、*は0以上まあ

/ / Swagger.html /swagger.html **もゼロ以上のディレクトリまあ一致する
/
/ * ** /webjars/springfox-swagger-ui/images/favicon-32x32.png整合性多層一致するディレクトリを.pngをします複数の文字にマッチします

?COM /トンst.jsp -試合:COM /なtest.jsp、COM / tast.jsp、COM / txst.jsp
  COM / .jspファイル-マッチング:COMのすべての.jspファイルフォルダの下の
  COM /
/test.jsp -マッチング:すべての.jspファイルの下のcomフォルダとサブフォルダ、
  ORG / springframework /
/ .jspファイル-試合:ORG / springframeworkすべての.jspファイルの下のフォルダとサブフォルダ
  ORG / ** /サーブレット/ bla.jsp -試合:ORG / springframework /サーブレット/ bla.jsp 、ORG / springframework /テスト/サーブレット/ bla.jsp、ORG /サーブレット/ bla.jsp

あなたは試験例を書くことができます。

 public static void main(String[] args) {
        pathMatcher.setCachePatterns(true);
        pathMatcher.setCaseSensitive(true);
        pathMatcher.setTrimTokens(true);
        pathMatcher.setPathSeparator("/");

        Assert.assertTrue(pathMatcher.match("/**/*swagger.html", "/swagger.html"));
        Assert.assertTrue(pathMatcher.match("/**/*.png", "/webjars/springfox-swagger-ui/images/favicon-32x32.png"));
        Assert.assertTrue(pathMatcher.match("a*", "ab"));
        Assert.assertTrue(pathMatcher.match("a*/**/a", "ab/asdsa/a"));
        Assert.assertTrue(pathMatcher.match("a*/**/a", "ab/asdsa/asdasd/a"));


        Assert.assertTrue(pathMatcher.match("*", "a"));
        Assert.assertTrue(pathMatcher.match("*/*", "a/a"));
    }

参考:
https://wenchao.ren/2019/01/Spring%E7%9A%84AntPathMatcher%E6%98%AF%E4%B8%AA%E5%A5%BD%E4%B8%9C%E8%A5% BF /

https://www.cnblogs.com/leftthen/p/5212221.html

ます。https://www.jianshu.com/p/ce3e93670fc8で再現

おすすめ

転載: blog.csdn.net/weixin_34247032/article/details/91202647
おすすめ