springboot-启动bean冲突的解决

 更新时间:2022年03月24日 11:31:08   作者:鬼~离未罔两  
这篇文章主要介绍了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模块的依赖,造成了这一问题,删除后解决

        <dependency>
            <groupId>com.test</groupId>
            <artifactId>B</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>

启动提示bean重复问题

先说结论

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

原理

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

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);
         }
      }
   }
}

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

//@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重复问题的解释,仅上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • idea启动Tomcat时控制台乱码的解决方法(亲测有效)

    idea启动Tomcat时控制台乱码的解决方法(亲测有效)

    最近在idea中启动tomcat出现控制台乱码问题,尝试了很多方法,最后终于解决了,所以下面这篇文章主要给大家介绍了关于idea启动Tomcat时控制台乱码的解决方法,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-07-07
  • Java TCP网络通信协议详细讲解

    Java TCP网络通信协议详细讲解

    TCP/IP是一种面向连接的、可靠的、基于字节流的传输层通信协议,它会保证数据不丢包、不乱序。TCP全名是Transmission Control Protocol,它是位于网络OSI模型中的第四层
    2022-09-09
  • Java编程接口回调一般用法代码解析

    Java编程接口回调一般用法代码解析

    本文的主要内容是同过实际代码向大家展示Java编程中接口回调的一般用法,具有一定参考价值,需要的朋友可以了解下
    2017-09-09
  • Java设计模式之观察者模式解析

    Java设计模式之观察者模式解析

    这篇文章主要介绍了Java设计模式之观察者模式解析,观察者模式,又被称为发布/订阅模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己,需要的朋友可以参考下
    2023-09-09
  • FeignClient如何共享Header及踩坑过程记录

    FeignClient如何共享Header及踩坑过程记录

    这篇文章主要介绍了FeignClient如何共享Header及踩坑过程记录,
    2022-03-03
  • Spring Boot2中如何优雅地个性化定制Jackson实现示例

    Spring Boot2中如何优雅地个性化定制Jackson实现示例

    这篇文章主要为大家介绍了Spring Boot2中如何优雅地个性化定制Jackson实现示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • 深度优先与广度优先Java实现代码示例

    深度优先与广度优先Java实现代码示例

    这篇文章主要介绍了深度优先与广度优先Java实现代码示例,具有一定借鉴价值,需要的朋友可以参考下。
    2017-12-12
  • Java数组传递及可变参数操作实例详解

    Java数组传递及可变参数操作实例详解

    这篇文章主要介绍了Java数组传递及可变参数操作,结合实例形式详细分析了java数组参数传递与可变参数相关使用技巧,需要的朋友可以参考下
    2019-09-09
  • SpringBoot中@Conditional注解的使用

    SpringBoot中@Conditional注解的使用

    这篇文章主要介绍了SpringBoot中@Conditional注解的使用,@Conditional注解是一个条件装配注解,主要用于限制@Bean注解在什么时候才生效,以指定的条件形式控制bean的创建,需要的朋友可以参考下
    2024-01-01
  • Spring createBeanInstance实例化Bean

    Spring createBeanInstance实例化Bean

    这篇文章主要为大家介绍了Spring createBeanInstance实例化Bean源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03

最新评论