美文网首页
springboot中使用@EnableWebMvc时导致静态资

springboot中使用@EnableWebMvc时导致静态资

作者: _麻辣香锅不要辣 | 来源:发表于2019-08-02 22:19 被阅读0次
    代码
    @Configuration
    @EnableWebMvc
    public class WebConfig implements WebMvcConfigurer {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new MyInterceptors()).addPathPatterns("/**").excludePathPatterns("/admin/**");
        }
    }
    

    如果把@EnableWebMvc注解去掉的话就可以访问静态资源。

    首先看下springboot默认是如何访问静态资源的:
    以下是实现了WebMvcConfigurer接口的类

    WebMvcConfigurerAdapter 
    WebConfig  //自定义的
    WebMvcConfigurerComposite  
    WebMvcAutoConfigurationAdapter in WebMvcAutoConfiguration 
    Neo4jWebMvcConfiguration in Neo4jWebConfiguration in Neo4jDataAutoConfiguration 
    JpaWebMvcConfiguration in JpaWebConfiguration in JpaBaseConfiguration
    

    其中WebMvcConfigurerComposite 和 WebMvcAutoConfigurationAdapte中重写了addResourceHandlers方法

    WebMvcConfigurerComposite :
        private final List<WebMvcConfigurer> delegates = new ArrayList<>();
    
        public void addWebMvcConfigurers(List<WebMvcConfigurer> configurers) {
            if (!CollectionUtils.isEmpty(configurers)) {
                this.delegates.addAll(configurers);
            }
        }
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            //遍历所有的WebMvcConfigurer(自定义的和下面的默认的一个WebMvcAutoConfigurationAdapter)
            for (WebMvcConfigurer delegate : this.delegates) {
                delegate.addResourceHandlers(registry);
            }
        }
    
    WebMvcAutoConfigurationAdapter
    @Configuration
    @ConditionalOnWebApplication(type = Type.SERVLET)
    @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
    @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
    @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
    @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
            ValidationAutoConfiguration.class })
    public class WebMvcAutoConfiguration {
    
    
        @Configuration
        @Import(EnableWebMvcConfiguration.class)
        @EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
        public static class WebMvcAutoConfigurationAdapter
                implements WebMvcConfigurer, ResourceLoaderAware {
            @Override
            public void addResourceHandlers(ResourceHandlerRegistry registry) {
                if (!this.resourceProperties.isAddMappings()) {
                    logger.debug("Default resource handling disabled");
                    return;
                }
                Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
                CacheControl cacheControl = this.resourceProperties.getCache()
                        .getCachecontrol().toHttpCacheControl();
                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));
    }
    

    从上面的代码可以看出,WebMvcConfigurerComposite 中会遍历所有的WebMvcConfigurer,所以即使在自定义的配置类中重写了addResourceHandlers方法,在遍历的时候会被默认的覆盖,因为在WebMvcAutoConfigurationAdapter也有addResourceHandlers方法


    webmvcconfig.png

    但是加了@EnableWebMvc之后,为什么就不行了呢,先看下源码

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @Documented
    @Import(DelegatingWebMvcConfiguration.class)
    public @interface EnableWebMvc {
    }
    

    这里有个@Import(DelegatingWebMvcConfiguration.class),它是一个WebMvcConfigurationSupport ,并重写了addResourceHandlers方法,里面调用的还是之前WebMvcConfigurerComposite中的addResourceHandlers方法。

    @Configuration
    public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
    
        private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
        @Override
        protected void addResourceHandlers(ResourceHandlerRegistry registry) {
            this.configurers.addResourceHandlers(registry);
        }
    }
    
    那么此时,再调试一下。会发现此时只有自定义的一个配置类了,原本的WebMvcAutoConfiguration不在了 webmvcconfig2.png

    此时再观察一下WebMvcAutoConfiguration中有一个注解:
    @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)

    总结:

    用户配置了@EnableWebMvc

    Spring扫描所有的注解,再从注解上扫描到@Import,把这些@Import引入的bean信息都缓存起来 在扫描到@EnableWebMvc时,通过@Import加入了 DelegatingWebMvcConfiguration,也就是WebMvcConfigurationSupport

    spring再处理@Conditional相关的注解,判断发现已有WebMvcConfigurationSupport,就跳过了spring boot的WebMvcAutoConfiguration,所以默认的也就失效了。

    相关文章

      网友评论

          本文标题:springboot中使用@EnableWebMvc时导致静态资

          本文链接:https://www.haomeiwen.com/subject/kxirdctx.html