关于 java:为什么 HATEOAS 在使用 Swagger 2.x 启动期间开始为 spring-boot 版本> = 2.2.x 创建问题?

Why HATEOAS starts creating issue for spring-boot version >= 2.2.x during startup with Swagger 2.x?

我将我的项目从 spring-boot 2.1.9 移动到 2.2.0。

在启动项目时,我面临以下 error 消息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.springframework.plugin.core.PluginRegistry<org.springframework.hateoas.client.LinkDiscoverer, org.springframework.http.MediaType>' available: expected single matching bean but found 17: modelBuilderPluginRegistry,modelPropertyBuilderPluginRegistry,typeNameProviderPluginRegistry,syntheticModelProviderPluginRegistry,documentationPluginRegistry,apiListingBuilderPluginRegistry,operationBuilderPluginRegistry,parameterBuilderPluginRegistry,expandedParameterBuilderPluginRegistry,resourceGroupingStrategyRegistry,operationModelsProviderPluginRegistry,defaultsProviderPluginRegistry,pathDecoratorRegistry,apiListingScannerPluginRegistry,relProviderPluginRegistry,linkDiscovererRegistry,entityLinksPluginRegistry


Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'linkDiscoverers' defined in class path resource [org/springframework/hateoas/config/HateoasConfiguration.class]: Unsatisfied dependency expressed through method 'linkDiscoverers' parameter 0; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.springframework.plugin.core.PluginRegistry<org.springframework.hateoas.client.LinkDiscoverer, org.springframework.http.MediaType>' available: expected single matching bean but found 17: modelBuilderPluginRegistry,modelPropertyBuilderPluginRegistry,typeNameProviderPluginRegistry,syntheticModelProviderPluginRegistry,documentationPluginRegistry,apiListingBuilderPluginRegistry,operationBuilderPluginRegistry,parameterBuilderPluginRegistry,expandedParameterBuilderPluginRegistry,resourceGroupingStrategyRegistry,operationModelsProviderPluginRegistry,defaultsProviderPluginRegistry,pathDecoratorRegistry,apiListingScannerPluginRegistry,relProviderPluginRegistry,linkDiscovererRegistry,entityLinksPluginRegistry


***************************
APPLICATION FAILED TO START
***************************

Description:


Parameter 0 of method linkDiscoverers in org.springframework.hateoas.config.HateoasConfiguration
required a single bean, but 17 were found:
- modelBuilderPluginRegistry: defined in null
- modelPropertyBuilderPluginRegistry: defined in null
- typeNameProviderPluginRegistry: defined in null
- syntheticModelProviderPluginRegistry: defined in null
- documentationPluginRegistry: defined in null
- apiListingBuilderPluginRegistry: defined in null
- operationBuilderPluginRegistry: defined in null
- parameterBuilderPluginRegistry: defined in null
- expandedParameterBuilderPluginRegistry: defined in null
- resourceGroupingStrategyRegistry: defined in null
- operationModelsProviderPluginRegistry: defined in null
- defaultsProviderPluginRegistry: defined in null
- pathDecoratorRegistry: defined in null
- apiListingScannerPluginRegistry: defined in null
- relProviderPluginRegistry: defined by method 'relProviderPluginRegistry' in class path resource [org/springframework/hateoas/config/HateoasConfiguration.class]
- linkDiscovererRegistry: defined in null
- entityLinksPluginRegistry: defined by method 'entityLinksPluginRegistry' in class path resource [org/springframework/hateoas/config/WebMvcEntityLinksConfiguration.class]

是什么导致了这个问题?

注意:我没有在我的 pom.xml 文件中使用 HATEOAS。

pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<properties>
    <java.version>1.8</java.version>
    <swagger-springfox.version>2.9.2</swagger-springfox.version>
    <sonar.jacoco.execPath>${project.basedir}/target/jacoco.exec</sonar.jacoco.execPath>
    <jasypt-spring-boot-starter>2.1.1</jasypt-spring-boot-starter>
    <logbook-spring-boot-starter>1.13.0</logbook-spring-boot-starter>
    0.8.1</assertj-swagger>
    <jacoco-version>0.8.4</jacoco-version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        spring-boot-starter-data-rest</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        spring-boot-devtools</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        spring-boot-configuration-processor</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        springfox-swagger2</artifactId>
        <version>${swagger-springfox.version}</version>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        springfox-swagger-ui</artifactId>
        <version>${swagger-springfox.version}</version>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        springfox-spring-web</artifactId>
        <version>${swagger-springfox.version}</version>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        springfox-core</artifactId>
        <version>${swagger-springfox.version}</version>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        springfox-data-rest</artifactId>
        <version>${swagger-springfox.version}</version>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        springfox-bean-validators</artifactId>
        <version>${swagger-springfox.version}</version>
    </dependency>


我的 spring-boot 应用程序中的 Swagger + HATEOAS 遇到了这个问题。

下面给出了修复(编辑你的 Swagger 配置类):

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
@EnableSwagger2
public class SwaggerConfiguration {

    @Bean
    public LinkDiscoverers discoverers() {
        List<LinkDiscoverer> plugins = new ArrayList<>();
        plugins.add(new CollectionJsonLinkDiscoverer());
        return new LinkDiscoverers(SimplePluginRegistry.create(plugins));

    }
}


对我来说这个链接有帮助:https://github.com/spring-projects/spring-hateoas/issues/731

简而言之,我添加了我的依赖项:

1
2
3
4
5
<dependency>
    <groupId>org.springframework.plugin</groupId>
    spring-plugin-core</artifactId>
    <version>2.0.0.RELEASE</version>
</dependency>


此类问题是由于 Hateoas 的一项新功能而发生的。

如果你想解决这个问题,只需在你的swagger配置文件中嵌入下面这行代码即可。

1
2
3
4
5
6
7
@Primary
@Bean
public LinkDiscoverers discoverers() {
    List<LinkDiscoverer> plugins = new ArrayList<>();
    plugins.add(new CollectionJsonLinkDiscoverer());
    return new LinkDiscoverers(SimplePluginRegistry.create(plugins));
}

我认为这会解决你的问题,因为它解决了我的问题。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    Use following 2 dependency to resolve Swagger and Hateoas dependency conflict.
   
    If Spring Boot version is >= 2.2.0 the use io.springfox version 3.0.0
   
    <dependency>
        <groupId>io.springfox</groupId>
        springfox-swagger2</artifactId>
        <version>3.0.0</version>
    </dependency>
   
    <dependency>
        <groupId>io.springfox</groupId>
        springfox-swagger-ui</artifactId>
        <version>3.0.0</version>
    </dependency>

使用 3.0.0 版本后,swagger-ui 将无法工作,因此请使用以下依赖项和用户 /swagger-ui/ 而不是 /swagger-ui.html

1
2
3
4
5
    <dependency>
        <groupId>io.springfox</groupId>
        springfox-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>


我使用

时遇到的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
<dependency>
   <groupId>org.springframework.boot</groupId>
   spring-boot-dependencies</artifactId>
   <version>2.2.6.RELEASE</version>
   <type>pom</type>
   <scope>import</scope>
</dependency>
.....
.....
<dependency>
  <groupId>org.springframework.boot</groupId>
  spring-boot-starter-hateoas</artifactId>
</dependency>

用springfox招摇

1
2
3
4
5
6
7
8
9
10
<dependency>
  <groupId>io.springfox</groupId>
  springfox-swagger2</artifactId>
  <version>2.9.2</version>
</dependency>
<dependency>
  <groupId>io.springfox</groupId>
  springfox-swagger-ui</artifactId>
  <version>2.9.2</version>
</dependency>

如果您查看 spring hateoas 依赖项,则存在对 spring-plugin-core 版本 2.0.0.RELEASE

的依赖项

1
2
3
4
5
<dependency>
    <groupId>org.springframework.plugin</groupId>
    spring-plugin-core</artifactId>
    <version>${spring-plugin.version}</version>
</dependency>

但是大张旗鼓的依赖使用 spring-plugin-core 和版本 1.2.0.RELEASE.

spring-boot创建bean有冲突,需要统一org.springframework.plugin版本让spring看到,如果选择2.0.0.RELEASEswagger就可以编译,

所以版本 1.2.0.RELEASE 将适用于两个依赖项,例如

1
2
3
4
5
 <dependency>
    <groupId>org.springframework.plugin</groupId>
    spring-plugin-core</artifactId>
    <version>1.2.0.RELEASE</version>
</dependency>

之后,您需要配置类来为 SwaggerHATEOAS 启动 bean,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@EnableSwagger2
@Configuration
public class SwaggerConfiguration {

    @Primary
    @Bean
    public LinkDiscoverers discoverers() {
        List<LinkDiscoverer> plugins = new ArrayList<>();
        plugins.add(new CollectionJsonLinkDiscoverer());
        return new LinkDiscoverers(SimplePluginRegistry.create(plugins));
    }

    @Bean
    public Docket postsApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("{ApplicationName}")
                .apiInfo(buildApiInfo())
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.regex("/.*"))
                .build();
    }

    private ApiInfo buildApiInfo() {
        Contact contact = new Contact("CompanyName","https://company-domain.com","[email protected]");
        return new ApiInfoBuilder()
                .title(""{ApplicationName}"")
                .description("API Description")
                .license("license")
                .version("1.0")
                .contact(contact)
                .licenseUrl("licenseURl")
                .build();
    }
}


对于 Spring boot 版本 2.1.3.RELEASE 用户,以下依赖项适用于 hatoas swagger:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    <dependency>
        <groupId>org.springframework.boot</groupId>
        spring-boot-starter-hateoas</artifactId>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        springfox-swagger2</artifactId>
        <version>2.9.2</version>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        springfox-swagger-ui</artifactId>
        <version>2.9.2</version>
    </dependency>

试试这个2.6.1版本,我已经用这个方法解决了

1
2
3
4
5
6
7
8
9
10
<dependency>
    <groupId>io.springfox</groupId>
    springfox-swagger2</artifactId>
    <version>2.6.1</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    springfox-swagger-ui</artifactId>
    <version>2.6.1</version>
</dependency>


我正在使用 springdoc-openapi,在遇到类似于这里提到的问题后:

1
2
3
4
5
6
7
8
9
10
11
Description:

Parameter 0 of method linkDiscoverers in org.springframework.hateoas.config.HateoasConfiguration required a single bean, but 3 were found:
    - relProviderPluginRegistry: defined by method 'relProviderPluginRegistry' in class path resource [org/springframework/hateoas/config/HateoasConfiguration.class]
    - linkDiscovererRegistry: defined in null
    - entityLinksPluginRegistry: defined by method 'entityLinksPluginRegistry' in class path resource [org/springframework/hateoas/config/WebMvcEntityLinksConfiguration.class]


Action:

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed

我只是在我的 pom 文件中添加了这个依赖

1
2
3
4
5
<dependency>
    <groupId>org.springframework.hateoas</groupId>
    spring-hateoas</artifactId>
    <version>1.1.1.RELEASE</version>
</dependency>

希望这可以帮助某人


最佳解决方案

在 SwaggerConfig 类中添加以下代码

1
2
3
4
5
6
@Bean
public LinkDiscoverers discovers() {    
    List<LinkDiscoverer> plugins = new ArrayList<>();
    plugins.add(new CollectionJsonLinkDiscoverer());
    return new LinkDiscoverers(SimplePluginRegistry.create(plugins));[enter image description here][1]  
}

作为亚历山大·魏?已经回答,spring-plugin-core 依赖解决了错误的版本 1.2.0.RELEASE.

为了强制使用正确的2.0.0.RELEASE,你必须要么排除错误的传递依赖并明确指定正确的,要么在pom.xml中固定(!)那个依赖版本。这是在 <dependenciesManagement> 块中完成的,而不是在 <dependencies> 块中。 Springfox 3.0.0 的固定示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<properties>
    <spring-plugin-core.version>2.0.0.RELEASE</spring-plugin-core.version>
    <springfox.version>3.0.0</springfox.version>
</properties>

<dependencyManagement>
  <dependencies>
    <!-- API Documentation -->
    <!-- Fix wrong resolved `spring-plugin-core` dependency version for springfox -->
    <dependency>
      <groupId>org.springframework.plugin</groupId>
      spring-plugin-core</artifactId>
      <version>${spring-plugin-core.version}</version>
    </dependency>
    <dependency>
      <groupId>io.springfox</groupId>
      springfox-boot-starter</artifactId>
      <version>${springfox.version}</version>
    </dependency>
  </dependencies>
</dependencyManagement>

<dependencies>
  <!-- API Documentation -->
  <dependency>
    <groupId>io.springfox</groupId>
    springfox-boot-starter</artifactId>
  </dependency>
</dependencies>

我收到错误

"在类路径资源 [org/springframework/hateoas/mediatype/hal/HalMediaTypeConfiguration.class] 中定义名称为 'halLinkDisocoverer' 的 bean 创建错误"..

在构建超媒体驱动的 RESTful Web 服务时

删除这个依赖

1
2
3
4
5
<dependency>
     <groupId>com.jayway.jsonpath</groupId>
     json-path</artifactId>
     <scope>test</scope>
</dependency>

解决了我的问题。

查看此链接了解更多详情
为什么我收到错误工厂方法"halLinkDisocoverer"在 springboot 中引发异常?


您可以像这样更改版本:

1
2
3
4
5
6
7
8
9
10
<dependency>
    <groupId>io.springfox</groupId>
    springfox-swagger2</artifactId>
    <version>3.0.0</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    springfox-swagger-ui</artifactId>
    <version>2.8.0</version>
</dependency>

我正在使用 Spring Boot 2.4.1。但是在启动 Spring Boot 应用程序时看不到 Swagger 端点日志。


所以我实际上想要 hatoas 支持并且遇到了同样的问题。如果你有

就会发生这种情况

1
2
3
4
<dependency>
  <groupId>org.springframework.hateoas</groupId>
  spring-hateoas</artifactId>
</dependency>

而不是

1
2
3
4
<dependency>
  <groupId>org.springframework.boot</groupId>
  spring-boot-starter-hateoas</artifactId>
</dependency>


已解决,当 Swagger HATEOAS 与 Spring Boot 2.2.4.RELEASE 一起使用时,由于集成而发生此问题。RELEASE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package com.company.springbootworks.swagger;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.hateoas.client.LinkDiscoverer;
import org.springframework.hateoas.client.LinkDiscoverers;
import org.springframework.hateoas.mediatype.collectionjson.CollectionJsonLinkDiscoverer;
import org.springframework.http.ResponseEntity;
import org.springframework.plugin.core.SimplePluginRegistry;

import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger.web.DocExpansion;
import springfox.documentation.swagger.web.ModelRendering;
import springfox.documentation.swagger.web.OperationsSorter;
import springfox.documentation.swagger.web.TagsSorter;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger.web.UiConfigurationBuilder;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public LinkDiscoverers discoverers() {
        List<LinkDiscoverer> plugins = new ArrayList<>();
        plugins.add(new CollectionJsonLinkDiscoverer());
        return new LinkDiscoverers(SimplePluginRegistry.create(plugins));

    }

    @Bean
    public Docket eDesignApi(SwaggerConfigProperties swaggerConfigProperties) {
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo(swaggerConfigProperties))
                .enable(Boolean.valueOf(swaggerConfigProperties.getEnabled())).select()
                .apis(RequestHandlerSelectors.any()).paths(PathSelectors.any()).build().pathMapping("/")
                .directModelSubstitute(LocalDate.class, String.class).genericModelSubstitutes(ResponseEntity.class)
                .useDefaultResponseMessages(Boolean.valueOf(swaggerConfigProperties.getUseDefaultResponseMessages()))
                .enableUrlTemplating(Boolean.valueOf(swaggerConfigProperties.getEnableUrlTemplating()));
    }

    @Bean
    UiConfiguration uiConfig(SwaggerConfigProperties swaggerConfigProperties) {
        return UiConfigurationBuilder.builder().deepLinking(Boolean.valueOf(swaggerConfigProperties.getDeepLinking()))
                .displayOperationId(Boolean.valueOf(swaggerConfigProperties.getDisplayOperationId()))
                .defaultModelsExpandDepth(Integer.valueOf(swaggerConfigProperties.getDefaultModelsExpandDepth()))
                .defaultModelExpandDepth(Integer.valueOf(swaggerConfigProperties.getDefaultModelExpandDepth()))
                .defaultModelRendering(ModelRendering.EXAMPLE)
                .displayRequestDuration(Boolean.valueOf(swaggerConfigProperties.getDisplayRequestDuration()))
                .docExpansion(DocExpansion.NONE).filter(Boolean.valueOf(swaggerConfigProperties.getFilter()))
                .maxDisplayedTags(Integer.valueOf(swaggerConfigProperties.getMaxDisplayedTags()))
                .operationsSorter(OperationsSorter.ALPHA)
                .showExtensions(Boolean.valueOf(swaggerConfigProperties.getShowExtensions()))
                .tagsSorter(TagsSorter.ALPHA).supportedSubmitMethods(UiConfiguration.Constants.DEFAULT_SUBMIT_METHODS)
                .validatorUrl(null).build();
    }

    private ApiInfo apiInfo(SwaggerConfigProperties swaggerConfigProperties) {
        return new ApiInfoBuilder().title(swaggerConfigProperties.getTitle())
                .description(swaggerConfigProperties.getDescription()).version(swaggerConfigProperties.getApiVersion())
                .build();
    }
}

及以下是swagger依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<properties>
    <java.version>1.8</java.version>
    <swagger.version>2.9.2</swagger.version>
    <swagger-annotations.version>1.5.21</swagger-annotations.version>
    <swagger-models.version>1.5.21</swagger-models.version>
    <spring-plugin.version>2.0.0.BUILD-SNAPSHOT</spring-plugin.version>
</properties>


<dependency>
    <groupId>io.springfox</groupId>
    springfox-swagger2</artifactId>
    <version>${swagger.version}</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    springfox-swagger-ui</artifactId>
    <version>${swagger.version}</version>
</dependency>
<dependency>
    <groupId>io.swagger</groupId>
    swagger-annotations</artifactId>
    <version>${swagger-annotations.version}</version>
</dependency>
<dependency>
    <groupId>io.swagger</groupId>
    swagger-models</artifactId>
    <version>${swagger-models.version}</version>
</dependency>


我已经删除了这些依赖项作为解决方法并工作了:

1
2
3
4
5
6
7
8
9
10
11
<dependency>
    <groupId>io.springfox</groupId>
    springfox-swagger2</artifactId>
    <version>2.4.0</version>
</dependency>

<dependency>
    <groupId>io.springfox</groupId>
    springfox-swagger-ui</artifactId>
    <version>2.4.0</version>
</dependency>

如果对你有用,请告诉我。


如果你想要 Swagger,但可以与 HATEOAS 妥协,那么只需删除 HATEOAS 依赖项并添加:

1
2
compile group: 'io.springfox', name: 'springfox-swagger-ui', version:'2.9.2'  
compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2'