Springboot2.x+swagger2突然404解決分析

問題背景

​ 項目正常更新以後,突然swagger-ui.html界面就404了,很奇怪,報錯如下:

GET "/swagger-ui.html", parameters={}
2020-04-24 09:53:38.324 [http-nio-7799-exec-1] [WARN] - No mapping for GET /swagger-ui.html
2020-04-24 09:53:38.325 [http-nio-7799-exec-1] [DEBUG] - Completed 404 NOT_FOUND

No mapping for GET /swagger-ui.html這明顯是對應的處理handle-mapping沒有找到啊,奇怪了,之前運行的好好的,項目更新後,就404了呢

代碼比對

​ 於是,Compare搞起,比對發現如下:

@Configuration
public class WebConfig implements WebMvcConfigurer{
    ...
}

​ 修改後:

@Configuration
public class WebConfig extends WebMvcConfigurationSupport{
    ...
}

​ 然後想起來了,同事說,不推薦直接使用WebMvcConfigurer,所以改爲WebMvcConfigurationSupport,但是這也不該影響使用swagger2啊,好奇怪,那麼繼續分析爲啥呢?

分析WebMvcConfigurer

​ 分析WebMvcConfigurer#addResourceHandlers,這裏是註冊handler-mapping映射關係的

//WebMvcConfigurerComposite#addResourceHandlers
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    for (WebMvcConfigurer delegate : this.delegates) {
        delegate.addResourceHandlers(registry);
    }
}

​ 說明有多個WebMvcConfigurer的實現類註冊了,具體如下:
在這裏插入圖片描述
​ 調試,查看,ResourceHandlerRegistry裏面到底處理了那些url path

  • /webjars/**
  • /**
    在這裏插入圖片描述
    ​ 查看對應的日誌,果然
Creating chain [/v2/api-docs] from String definition [anon]
2020-04-24 10:07:58.044 [main] [DEBUG] - Attempting to apply path [/v2/api-docs] to filter [anon] with config [null]
# /webjars/springfox-swagger-ui/**
2020-04-24 10:07:58.044 [main] [DEBUG] - Creating chain [/webjars/springfox-swagger-ui/**] from String definition [anon]
2020-04-24 10:07:58.044 [main] [DEBUG] - Attempting to apply path [/webjars/springfox-swagger-ui/**] to filter [anon] with config [null]

​ 所以使用WebMvcConfigurerswagger2對應的handler被註冊了

分析WebMvcConfigurationSupport

​ 下面分析WebMvcConfigurationSupport#addResourceHandlers,實現如下:

//DelegatingWebMvcConfiguration#addResourceHandlers
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
    // 注意configurers------->WebMvcConfigurerComposite
    this.configurers.addResourceHandlers(registry);
}

​ 也就是說,使用WebMvcConfigurationSupport,最終也是調用到了WebMvcConfigurerComposite#addResourceHandlers,但是在最後的ResourceHandlerRegistry裏面確實沒有/webjars/**,說明,根本就沒有去註冊對應的url

​ 所以打斷點分析

//WebMvcConfigurerComposite#addResourceHandlers
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    //打斷點
    for (WebMvcConfigurer delegate : this.delegates) {
        delegate.addResourceHandlers(registry);
    }
}

​ 結果,根本就沒有執行到這個方法,也就是使用WebMvcConfigurationSupport根本就沒有去註冊。

​ 怎麼呢?繼續分析WebMvcConfigurer的實現類,因爲是直接使用的starter

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

​ 所以,分析一下WebMvcAutoConfigurationAdapter,

@Configuration
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
@Order(0)
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();
        // /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));
        }
    }    
    ......    

}

​ 看似沒有問題啊,裏面也註冊了, 因爲是內部類,所以繼續分析父類WebMvcAutoConfiguration

@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
// 重點
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
		TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
    
}

@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)也就是說,只有在上下文中沒有找到這個WebMvcConfigurationSupport纔會起作用啊 ,而我後來更新的代碼,的確是加了WebMvcConfigurationSupport,導致springbootwebmvc自動裝配失效了,所以,問題居然在這裏,略坑啊

重寫addResourceHandlers

​ 可以肯定的是,自己在WebMvcConfigurationSupport裏面重寫addResourceHandlers添加swagger2應該是沒問題的,代碼如下:

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/statics/**")
            .addResourceLocations("classpath:/statics/");
        registry.addResourceHandler("/swagger-ui.html")
            .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
            .addResourceLocations("classpath:/META-INF/resources/webjars/");
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章