源码分析SpringBoot2.x 静态资源被拦截器拦截的原因

1、静态资源路径的注册

先来看WebMvc的自动配置类:WebMvcAutoConfiguration,它里面有个内部类:WebMvcAutoConfigurationAdapter,其中有个方法addResourceHandlers,实现如下

@Configuration
//引入EnableWebMvcConfiguration对象到容器中
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
@Order(0)
public static class WebMvcAutoConfigurationAdapter
        implements WebMvcConfigurer, ResourceLoaderAware {
    
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        
        //是否有注册"/webjars/**"这个路径
        if (!registry.hasMappingForPattern("/webjars/**")) {
            customizeResourceHandlerRegistration(registry
                    .addResourceHandler("/webjars/**")
                    .addResourceLocations("classpath:/META-INF/resources/webjars/")
                    .setCachePeriod(getSeconds(cachePeriod))
                    .setCacheControl(cacheControl));
        }
        String staticPathPattern = this.mvcProperties.getStaticPathPattern();
        //是否有注册静态资源路径
        if (!registry.hasMappingForPattern(staticPathPattern)) {
            customizeResourceHandlerRegistration(
                    registry.addResourceHandler(staticPathPattern)
                            .addResourceLocations(getResourceLocations(
                                    this.resourceProperties.getStaticLocations()))
                            .setCachePeriod(getSeconds(cachePeriod))
                            .setCacheControl(cacheControl));
        }
    }
}

首先,它将/webjars/**注册,其次将默认的静态资源路径注册。在代码第20行,追踪发现变量staticPathPattern就等于/**,再看代码第26行,追踪对应的本地路径(见如下代码),就是springboot默认配置的资源路径。

public class WebMvcProperties {
    
    private String staticPathPattern = "/**";
    
    public String getStaticPathPattern() {
		return this.staticPathPattern;
	}
}

public class ResourceProperties {
    private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
			"classpath:/META-INF/resources/", "classpath:/resources/",
			"classpath:/static/", "classpath:/public/" };
    
	private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
    
    public String[] getStaticLocations() {
		return this.staticLocations;
	}
}

2、静态资源的处理器映射器

回到上面讲的WebMvcAutoConfigurationAdapter类,它使用Import注解引入EnableWebMvcConfiguration对象到容器中。

EnableWebMvcConfiguration也是WebMvcAutoConfiguration的一个内部类,查看它的父类如下。

@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

直接看EnableWebMvcConfiguration的间接父类WebMvcConfigurationSupport

public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
    
    /**
	 * Return a handler mapping ordered at Integer.MAX_VALUE-1 with mapped
	 * resource handlers. To configure resource handling, override
	 * 返回一个优先级为Integer.MAX_VALUE-1,映射静态资源处理器的HandlerMapping
	 */
	@Bean
	@Nullable
	public HandlerMapping resourceHandlerMapping()	 {
		ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext,
				this.servletContext, mvcContentNegotiationManager(), mvcUrlPathHelper());
        //对静态资源路径进行注册
		addResourceHandlers(registry);

        //返回映射有静态资源路径的HandlerMapping
		AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
		if (handlerMapping == null) {
			return null;
		}
		handlerMapping.setPathMatcher(mvcPathMatcher());
		handlerMapping.setUrlPathHelper(mvcUrlPathHelper());
        //添加所有拦截器
		handlerMapping.setInterceptors(getInterceptors());
		handlerMapping.setCorsConfigurations(getCorsConfigurations());
		return handlerMapping;
	}
}

类中有一个方法resourceHandlerMapping(),它返回一个专门处理静态资源路径的处理器映射器。

见代码第14行addResourceHandlers(registry),其实最终它就是调用类WebMvcAutoConfigurationAdapter中的方法addResourceHandlers将资源路径注册。

见代码第17行,调用getHandlerMapping(),查看该方法发现其将注册的资源路径形成映射放在handlerMapping中,并返回该handlerMapping

见代码第23行,将所有拦截器(包括我们自定义的拦截器)添加到该handlerMapping,这就是为什么我们自定义拦截器会拦截静态资源。而在springboot1.5中添加拦截器是这样子的

handlerMapping.setInterceptors(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider()));

并没有添加所有拦截器到该handlerMapping,这也是springboot1.5不拦截静态资源的原因。

3、解决方法

设置拦截路径时调用excludePathPatterns方法进行排除。例如:

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
 
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
                .excludePathPatterns("/webjars/**","/index.html");
    }
}

你可能感兴趣的:(Spring,Java,SpringBoot)