Skip to content

Spring Boot 2.6.0 Springfox 启动失败:documentationPluginsBootstrapper 错误解决方案

问题描述

在 Spring Boot 2.6.0 及以上版本中,当使用 Springfox 3.x 时,应用程序启动时可能会遇到以下错误:

log
org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; 
nested exception is java.lang.NullPointerException: Cannot invoke 
"org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getPatterns()" 
because "this.condition" is null

这个问题的根本原因是 Spring Boot 2.6.0 引入了默认的路径匹配策略变更,与 Springfox 库存在兼容性问题。

问题根源

自 Spring Boot 2.6.0 开始,默认的路径匹配策略从 AntPathMatcher 改为 PathPatternParser。Springfox 3.x 版本在设计时假设 Spring MVC 使用的是基于 Ant 的路径匹配器,因此在新版本的 Spring Boot 中会出现兼容性问题。

注意

如果您同时使用了 Spring Boot Actuator,情况会更加复杂。Actuator 始终使用基于 PathPattern 的解析器,不受 matching-strategy 配置的影响。

解决方案

方案一:修改路径匹配策略(适用于无 Actuator 的场景)

application.properties 文件中添加以下配置:

properties
spring.mvc.pathmatch.matching-strategy=ant_path_matcher

这个简单的配置可以解决大多数情况下的问题,但如果您使用了 Spring Boot Actuator,可能需要下面的方案。

方案二:自定义 Bean 配置(适用于包含 Actuator 的场景)

添加以下 Bean 配置类:

java
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
import springfox.documentation.spring.web.plugins.WebFluxRequestHandlerProvider;
import springfox.documentation.spring web.plugins.WebMvcRequestHandlerProvider;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Configuration
public class SpringFoxConfig {

    @Bean
    public BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
        return new BeanPostProcessor() {
            @Override
            public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {
                    customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
                }
                return bean;
            }

            private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
                List<T> copy = mappings.stream()
                        .filter(mapping -> mapping.getPatternParser() == null)
                        .collect(Collectors.toList());
                mappings.clear();
                mappings.addAll(copy);
            }

            @SuppressWarnings("unchecked")
            private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
                try {
                    Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
                    if (Objects.isNull(field)) {
                        return new ArrayList<>();
                    }
                    field.setAccessible(true);
                    return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
                } catch (IllegalArgumentException | IllegalAccessException e) {
                    throw new IllegalStateException(e);
                }
            }
        };
    }
}

方案三:降级 Spring Boot 版本

如果以上方案对您不适用,可以考虑将 Spring Boot 降级到 2.5.x 版本:

gradle
// build.gradle
plugins {
    id 'org.springframework.boot' version '2.5.6' // 使用 2.5.x 版本
    // 其他配置...
}

方案四:迁移到 Springdoc OpenAPI

考虑到 Springfox 已停止维护,迁移到 Springdoc OpenAPI 是推荐的长期解决方案。

  1. 添加依赖:
gradle
// build.gradle
implementation "org.springdoc:springdoc-openapi-ui:1.6.4"
  1. 在主应用类上添加注解:
java
@SpringBootApplication
@OpenAPIDefinition
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}
  1. 访问 Swagger UI:http://localhost:8080/swagger-ui/index.html

完整配置示例

如果您决定继续使用 Springfox,以下是完整的配置示例:

java
@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket apiDocket() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.any())
                .build()
                .apiInfo(metadata());
    }

    private ApiInfo metadata() {
        return new ApiInfoBuilder()
                .title("API文档")
                .description("API接口文档")
                .version("1.0")
                .contact(new Contact("开发团队", "", "contact@example.com"))
                .build();
    }
    
    // 添加方案二中的 BeanPostProcessor
    @Bean
    public BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
        // 实现同上
    }
}
properties
# application.properties
spring.mvc.pathmatch.matching-strategy=ant_path_matcher

总结

Spring Boot 2.6.0 与 Springfox 3.x 的兼容性问题主要由路径匹配策略变更引起。您可以根据自己的项目需求选择适合的解决方案:

  1. 简单应用:使用 spring.mvc.pathmatch.matching-strategy=ant_path_matcher
  2. 包含 Actuator 的应用:添加自定义 BeanPostProcessor 配置
  3. 长期项目:考虑迁移到 Springdoc OpenAPI
  4. 临时解决:降级 Spring Boot 到 2.5.x 版本

建议

对于新项目,强烈推荐使用 Springdoc OpenAPI 替代 Springfox,因为它提供了更好的兼容性和持续的维护支持。

通过以上解决方案,您应该能够解决 Spring Boot 2.6.0 与 Springfox 3.x 的兼容性问题,并成功启动应用程序。