安全漏洞修復導致SpringBoot2.7與Springfox不兼容的偽命題解決
項目基于 springboot2.5.2 實現(xiàn)的,用 springfox-swagger2 生成與前端對接的 API 文檔;pom.xml 中依賴如下
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.2</version>
</parent>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
啟動服務后,就可以訪問 Swagger UI
http://localhost:8080/swagger-ui/index.html

前端同事就可以訪問這個來對接接口了,后端省去了寫接口文檔的工作,一切都是那么美好!可突然有一天,安全部門發(fā)來報告,說服務存在很多安全漏洞
CVE-2023-20860、CVE-2022-45143、CVE-2023-46589、...
讓我們根據(jù)報告中的建議進行修復,然后就開始了我的踩坑之旅!
springboot 與 springfox 兼容問題
粗略看了一眼,將 spring-boot 升級,可以解決很多漏洞,既然要升,那就升到可升的最高版本;因為是基于 JDK8,所以 spring-boot 最高能升級到 2.7.8。那就升嘛,不要慫就是干!
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
</parent>
啟動服務,第一個坑來了:NullPointerException
2025-05-30 21:13:42.264|ERROR|main|818|o.s.boot.SpringApplication :Application run failed org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:182) at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54) at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:357) at java.lang.Iterable.forEach(Iterable.java:75) at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:156) at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:124) at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:946) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:594) at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:732) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:409) at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1289) at com.qsl.Application.main(Application.java:16) Caused by: java.lang.NullPointerException: null at springfox.documentation.spring.web.WebMvcPatternsRequestConditionWrapper.getPatterns(WebMvcPatternsRequestConditionWrapper.java:56) at springfox.documentation.RequestHandler.sortedPaths(RequestHandler.java:113) at springfox.documentation.spi.service.contexts.Orderings.lambda$byPatternsCondition$3(Orderings.java:89) at java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:469) at java.util.TimSort.countRunAndMakeAscending(TimSort.java:355) at java.util.TimSort.sort(TimSort.java:220) at java.util.Arrays.sort(Arrays.java:1512) at java.util.ArrayList.sort(ArrayList.java:1454) at java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:387) at java.util.stream.Sink$ChainedReference.end(Sink.java:258) at java.util.stream.Sink$ChainedReference.end(Sink.java:258) at java.util.stream.Sink$ChainedReference.end(Sink.java:258) at java.util.stream.Sink$ChainedReference.end(Sink.java:258) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) at springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider.requestHandlers(WebMvcRequestHandlerProvider.java:81) at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.withDefaults(AbstractDocumentationPluginsBootstrapper.java:107) at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.buildContext(AbstractDocumentationPluginsBootstrapper.java:91) at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.bootstrapDocumentationPlugins(AbstractDocumentationPluginsBootstrapper.java:82) at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.start(DocumentationPluginsBootstrapper.java:100) at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:179) ... 14 common frames omitted
遇到問題不要怕
查詢問題并解決問題嘛;從哪查,我想大家已經(jīng)達成了統(tǒng)一的共識:大數(shù)據(jù)模型。deepseek 就是熱門之一,我們直接將堆棧信息扔給他,讓他提供解決方案。他一針見血分析出了原因
這個錯誤通常是由于 Springfox Swagger(
springfox-swagger2)與 Spring Boot 版本不兼容 或 Spring MVC 路徑匹配策略沖突 導致的。以下是幾種解決方案
降級 Spring Boot 版本
Spring Boot 2.6+開始與springfox不兼容,但Springfox Swagger 2.x已經(jīng)停止維護了,所以說通過升級 Springfox Swagger 來適配 Spring Boot 2.6+ 是不行了。我們的目的是升級 Spring Boot,那么降級 Spring Boot 這個方案肯定是行不通的。
升級到 SpringDoc OpenAPI
SpringDoc 是 Swagger 的替代方案,支持 OpenAPI 3.0,兼容 Spring Boot 2.6+ 和 3.x
考慮到注解變動大,需要調(diào)整的地方太多,這個方案不到萬不得已不采用
修改路徑匹配策略
如果不想降級 Spring Boot,可以調(diào)整路徑匹配策略
spring: mvc: pathmatch: matching-strategy: ant_path_matcher這個調(diào)整簡單,感覺可行,試試發(fā)現(xiàn)雀氏可以,采用這種方案
Swagger 配置是否正確
確保
@EnableSwagger2和Docket配置正確@Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.basePackage("com.your.package")) // 替換成你的 Controller 包名 .paths(PathSelectors.any()) .build(); } }這個確定是配置正確的,不是這個問題
deepseek 還給了其他方案,大家可以結(jié)合自己的實際情況,看看方案是否適用。如果你們以為坑就這么填平了,那只能說你們還是太年輕啦
我再加個依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
啟動服務,同樣的問題又來了
org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:182) at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54) at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:357) at java.lang.Iterable.forEach(Iterable.java:75) at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:156) at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:124) at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:946) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:594) at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:732) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:409) at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1289) at com.qsl.Application.main(Application.java:16) Caused by: java.lang.NullPointerException: null at springfox.documentation.spring.web.WebMvcPatternsRequestConditionWrapper.getPatterns(WebMvcPatternsRequestConditionWrapper.java:56) at springfox.documentation.RequestHandler.sortedPaths(RequestHandler.java:113) at springfox.documentation.spi.service.contexts.Orderings.lambda$byPatternsCondition$3(Orderings.java:89) at java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:469) at java.util.TimSort.countRunAndMakeAscending(TimSort.java:355) at java.util.TimSort.sort(TimSort.java:220) at java.util.Arrays.sort(Arrays.java:1512) at java.util.ArrayList.sort(ArrayList.java:1454) at java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:387) at java.util.stream.Sink$ChainedReference.end(Sink.java:258) at java.util.stream.Sink$ChainedReference.end(Sink.java:258) at java.util.stream.Sink$ChainedReference.end(Sink.java:258) at java.util.stream.Sink$ChainedReference.end(Sink.java:258) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) at springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider.requestHandlers(WebMvcRequestHandlerProvider.java:81) at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.withDefaults(AbstractDocumentationPluginsBootstrapper.java:107) at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.buildContext(AbstractDocumentationPluginsBootstrapper.java:91) at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.bootstrapDocumentationPlugins(AbstractDocumentationPluginsBootstrapper.java:82) at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.start(DocumentationPluginsBootstrapper.java:100) at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:179) ... 14 common frames omitted
同個問題出現(xiàn)一次也就算了,換個方式出現(xiàn)第二次,有點欺負人了!
此時我們再去問 deepseek,給出的解決方案,嘗試了都不對,好在在網(wǎng)上找到了解決方案,增加如下配置
@Configuration
@EnableSwagger2
public class SwaggerConfig {
/**
* springboot 2.7.x不支持swagger2,注冊bean進行兼容
* 該方法在Spring Boot 2.7.x中手動注冊WebMvcEndpointHandlerMapping,用于解決Swagger無法直接訪問Actuator端點的問題。下面詳細說明其作用:
* 1. 收集所有可暴露的端點
* 使用以下組件獲取不同類型的端點:
* webEndpointsSupplier.getEndpoints():獲取所有基于Web的端點(如/actuator/health)。
* servletEndpointsSupplier.getEndpoints():獲取Servlet類型的端點(如/actuator/servlet)。
* controllerEndpointsSupplier.getEndpoints():獲取Controller類型的端點。
* 將這些端點統(tǒng)一添加到allEndpoints列表中,以便后續(xù)處理。
* 2. 設置端點的基礎路徑
* 從WebEndpointProperties中獲取配置的端點基礎路徑(basePath),默認值通常是/actuator。
* 創(chuàng)建一個EndpointMapping對象,并傳入基礎路徑,用于定義端點的URL映射規(guī)則。
* 3. 判斷是否需要注冊端點鏈接映射
* 判斷條件如下:
* 如果啟用了端點發(fā)現(xiàn)(webEndpointProperties.getDiscovery().isEnabled())。
* 并且設置了有效的基礎路徑(StringUtils.hasText(basePath)),或者管理端口與應用端口不同(ManagementPortType.DIFFERENT)。
* 如果滿足條件,則創(chuàng)建端點鏈接映射,用于生成包含所有可用端點的首頁鏈接(例如/actuator)。
* 4. 構(gòu)建并返回WebMvcEndpointHandlerMapping
* 創(chuàng)建WebMvcEndpointHandlerMapping實例時傳入以下參數(shù):
* endpointMapping:定義端點的基礎路徑。
* webEndpoints:需要注冊的Web類型端點集合。
* endpointMediaTypes:定義端點支持的媒體類型(如JSON、YAML等)。
* corsConfiguration:跨域資源共享(CORS)配置。
* new EndpointLinksResolver(allEndpoints, basePath):用于生成端點鏈接的解析器。
* shouldRegisterLinksMapping:是否注冊端點鏈接映射。
* null:通常用于指定自定義的請求謂詞,此處為默認值。
* 返回的WebMvcEndpointHandlerMapping使Swagger能夠正常訪問和展示Actuator端點的信息。
* 5. 兼容性適配
* Spring Boot 2.7.x之后,Swagger 2不再直接支持訪問Actuator端點,此方法通過手動注冊WebMvcEndpointHandlerMapping來恢復兼容性,確保Swagger UI可以正確顯示和調(diào)用這些監(jiān)控和管理接口。
* 總結(jié)
* 此方法的核心目的是手動注冊端點處理器映射,以確保Swagger能夠正確訪問Spring Boot Actuator提供的各種監(jiān)控和管理端點。通過整合多種端點類型、設置基礎路徑、啟用鏈接映射等方式,使得開發(fā)者能夠在Swagger UI中方便地測試和使用這些端點。
*/
@Bean
public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier,
ServletEndpointsSupplier servletEndpointsSupplier,
ControllerEndpointsSupplier controllerEndpointsSupplier,
EndpointMediaTypes endpointMediaTypes,
CorsEndpointProperties corsProperties,
WebEndpointProperties webEndpointProperties,
Environment environment) {
List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
allEndpoints.addAll(webEndpoints);
allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
String basePath = webEndpointProperties.getBasePath();
EndpointMapping endpointMapping = new EndpointMapping(basePath);
boolean shouldRegisterLinksMapping =
webEndpointProperties.getDiscovery().isEnabled() && (StringUtils.hasText(basePath)
|| ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT));
return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes,
corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath),
shouldRegisterLinksMapping, null);
}
}
啟動服務,不再報錯,Swagger UI 也能正常訪問

也許你們會覺得這個坑解決的也快呀,沒什么大不了的,可實際是項目中有眾多的依賴,你如何知道是因為 spring-boot-starter-actuator 導致的?我實際排查這個問題的過程,可不是如上所說的那般容易,但有一點我們要清楚
我們遇到的坑,肯定有前輩遇到過
所以我們要做的是想清楚關鍵詞,到大數(shù)據(jù)模型搜索,或者到搜索引擎搜索
總結(jié)
歸根結(jié)底,還是
Springfox沒有去適配Spring Boot的升級,所以可能的話,還是推薦大家用SpringDoc OpenAPI不到萬不得已,不要去升級組件
坑我已經(jīng)替你們踩過
都是血的教訓,希望大家引以為戒
遇到問題,當下推薦的做法是用
大數(shù)據(jù)模型,關鍵詞給的好,得到的回答八九不離十就是正確的解決方案
到此這篇關于安全漏洞修復導致SpringBoot2.7與Springfox不兼容的偽命題解決的文章就介紹到這了,更多相關SpringBoot2.7與Springfox不兼容內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
如何應對spring框架的HTTP ERROR 400 Bad Request錯
這篇文章主要介紹了如何應對spring框架的HTTP ERROR 400 Bad Request錯誤返回問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-08-08
Spring MVC學習之DispatcherServlet請求處理詳析
這篇文章主要給大家介紹了關于Spring MVC學習教程之DispatcherServlet請求處理的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧2018-11-11
solr 配置中文分析器/定義業(yè)務域/配置DataImport功能方法(測試用)
下面小編就為大家?guī)硪黄猻olr 配置中文分析器/定義業(yè)務域/配置DataImport功能方法(測試用)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-09-09
Springboot整合多數(shù)據(jù)源代碼示例詳解
這篇文章主要介紹了Springboot整合多數(shù)據(jù)源代碼示例詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-08-08
spring boot 加載web容器tomcat流程源碼分析
本文章主要描述spring boot加載web容器 tomcat的部分,為了避免文章知識點過于分散,其他相關的如bean的加載,tomcat內(nèi)部流程等不做深入討論,具體內(nèi)容詳情跟隨小編一起看看吧2021-06-06
SpringBoot集成WebSocket的兩種方式(JDK內(nèi)置版和Spring封裝版)
這篇文章主要介紹了SpringBoot集成WebSocket的兩種方式,這兩種方式為JDK內(nèi)置版和Spring封裝版,本文結(jié)合示例代碼給大家介紹的非常詳細,需要的朋友可以參考下2023-06-06
java中StringBuffer的length()和capacity()方法對比
這篇文章主要介紹了java中StringBuffer的length()和capacity()方法對比,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07
Eclipse搭建spring開發(fā)環(huán)境圖文教程(推薦)
下面小編就為大家?guī)硪黄狤clipse搭建spring開發(fā)環(huán)境圖文教程(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-07-07
Spring boot事件監(jiān)聽實現(xiàn)過程解析
這篇文章主要介紹了,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-06-06

