問題背景
項目正常更新以後,突然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]
所以使用WebMvcConfigurer
,swagger2
對應的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
,導致springboot
的webmvc
自動裝配失效了,所以,問題居然在這裏,略坑啊
重寫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/");
}