好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

springboot-启动bean冲突的解决

启动bean冲突

在一次启动中遇到了bean冲突的问题,提示存在两个名称重复的bean

org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [com.test.api.Application]; nested exception is org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'healthCheckController' for bean class [com.test.datahub.controller.HealthCheckController] conflicts with existing, non-compatible bean definition of same name and class [com.test.api.controller.HealthCheckController]

项目中包括多个模块,其中A、B两个模块都有同一个类:

HealthCheckController,检查更改信息发现,不知道谁在A模块添加了B模块的依赖,造成了这一问题,删除后解决

?

1

2

3

4

5

        < dependency >

            < groupId >com.test</ groupId >

            < artifactId >B</ artifactId >

            < version >1.0.0-SNAPSHOT</ version >

        </ dependency >

启动提示bean重复问题

先说结论

只需要在@FeignClient注解的contextId属性上加上独一的标示,即可解决问题

原理

是因为注册feignClient的时候会注册ClientConfiguration,参考代码如下

?

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

public void registerFeignClients(AnnotationMetadata metadata,

      BeanDefinitionRegistry registry) {

    //...此处省略部分代码

    //

    for (String basePackage : basePackages) {

      Set<BeanDefinition> candidateComponents = scanner

            .findCandidateComponents(basePackage);

      for (BeanDefinition candidateComponent : candidateComponents) {

          if (candidateComponent instanceof AnnotatedBeanDefinition) {

            // verify annotated class is an interface

            //...省略部分代码

 

            //这块是把注解上的所有属性封装到map上

            Map<String, Object> attributes = annotationMetadata

            .getAnnotationAttributes(

            FeignClient. class .getCanonicalName());

 

            //这两个重点方法请看下面代码块

 

            //获取该feignClient的名字(重点关注该方法)

            String name = getClientName(attributes);

 

            //此方法就是spring注入beanDefination的步骤(重点关注该方法)

            registerClientConfiguration(registry, name,

                  attributes.get( "configuration" ));

 

            registerFeignClient(registry, annotationMetadata, attributes);

          }

      }

    }

}

上面的两处重点方法, 请看此处

?

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

//@param client 这个map就是通过上面的注解属性转map得到的

private String getClientName(Map<String, Object> client) {

    if (client == null ) {

      return null ;

    }

    //如果从contextId获取到名字,那么value有值的

    String value = (String) client.get( "contextId" );

    //如果value有值,那么如下3个if条件都不会走,所以contextId唯一就可以做到bean不重复,

    //如果value没有值,就会取value,因为多个client的serverName都是一样的,那么就会出现重复bean

    if (!StringUtils.hasText(value)) {

      value = (String) client.get( "value" );

    }

    if (!StringUtils.hasText(value)) {

      value = (String) client.get( "name" );

    }

    if (!StringUtils.hasText(value)) {

      value = (String) client.get( "serviceId" );

    }

    if (StringUtils.hasText(value)) {

      return value;

    }

 

    throw new IllegalStateException( "Either 'name' or 'value' must be provided in @"

          + FeignClient. class .getSimpleName());

}

 

private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,

      Object configuration) {

    BeanDefinitionBuilder builder = BeanDefinitionBuilder

          .genericBeanDefinition(FeignClientSpecification. class );

    builder.addConstructorArgValue(name);

    builder.addConstructorArgValue(configuration);

    //在这个位置,创建beanDefinition,但是他创建的名字格式可以看出,唯一改变变量就是name,这个name就是上面看到的那个方法获取的

    registry.registerBeanDefinition(

          name + "." + FeignClientSpecification. class .getSimpleName(),

          builder.getBeanDefinition());

}

以上就是feign导致的springBean重复问题的解释,仅上为个人经验,希望能给大家一个参考,也希望大家多多支持。

原文链接:https://blog.csdn.net/sky_flying1/article/details/97778377

查看更多关于springboot-启动bean冲突的解决的详细内容...

  阅读:55次