During that spring mvc source code analysis of the interceptor

Why origins, research interceptor matching rules are not enforced

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

Can be found, the interceptor is injected into the inside registrations

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

By idea, you can see the registration is only used in this method, the

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

Then this method is invoked here in WebMvcConfigurationSupport
maintenance interceptors variables in this class, but by the idea interceptors found, only to return the following methods is the use of this variable

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

The above method is WebMvcConfigurationSupport this method call

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

Previously, when spring mvc source code analysis, it is up to, call interceptor is called in doDispatch's method DispatchServlet

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

See call interceptor method
debug found here HandlerExecution of interceptors variables are already filtered interceptor, and has not matched the interceptor filter out
this variable is assigned interceptors in the end of it where? And debug processes under development by the idea, there is no place interceptors assigned to a valid value, the value of HandlerExecution interceptors in the end is how come?
It was very strange, and why? That is where the value of it?
Later, through, head construction HandlerExecution code, we found that overlooked a thing, interceptors is a collection, you can get to this collection through return, then off yo add a method to change the value, rather than a direct assignment to change the value

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

It is this line of code, filtered out interceptor

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

Finally locating here, which is filtered out here does not match the Interceptor

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

Look at how the filter is filtering
will find, first of all, by excludeUrl filtration, in excludeUrl in, directly filtered out, that is, do not add this interceptor ( but a lot of people will find that, added to the excludeUrl then found ineffective this is why? look at the bottom of the code )
and then filtered according to includeUrl, includeUrl is empty, add this filter, meaning that, if no custom includeUrl, the interceptor all.
If includeUrl is not empty, then matching intercept

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

This is a specific match codes: AntPathMatcher class, i.e. aut pattern matching, detailed matching aut way, there are many Baidu.
Critical look at the first line of code

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

So AntPathMatcher pattern matching what is it?
AntPathMatcher name used as matching rules ant, we look at and see.

Character wildcard description

? Matches one character

* Match zero or more characters (excluding / directory separator)

* Matches zero or more directories and directories

See some examples:
/*swagger.html matching /swagger.html, * is 0 or more Well

/ / Swagger.html /swagger.html ** also matches zero or more directories Well
/
/ .png multilayer matching directory matching /webjars/springfox-swagger-ui/images/favicon-32x32.png ** * matching multiple characters

? com / t st.jsp - match: com / test.jsp, COM / tast.jsp, COM / txst.jsp
  COM / .jsp - Matching: com all .jsp file folder under
  COM /
/test.jsp - matching: com folders and sub-folders under all .jsp file,
  ORG / springframework /
/ .jsp - match: org / springframework folders and sub-folders under all .jsp file
  org / ** / servlet / bla.jsp - match: org / springframework / servlet / bla.jsp , org / springframework / testing / servlet / bla.jsp, org / servlet / bla.jsp

You can write a test example:

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

Reference:
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

Reproduced in: https: //www.jianshu.com/p/ce3e93670fc8

Guess you like

Origin blog.csdn.net/weixin_34247032/article/details/91202647