@FeignClient注解中属性contextId的使用说明

发布时间:2023-08-03 09:30

目录
  • 一、概述
  • 二、解决方案
    • 2.1 方案1
    • 2.2 方案2
  • 三、源代码分析
    • 相关代码1
    • 相关代码2

一、概述

如果我们使用Feign定义了两个接口,但是目标服务是同一个,那么在SpringBoot启动时就会遇到一个问题:

Description:
The bean \'xxxxxxxx.FeignClientSpecification\', defined in null, could not be registered. A bean with that name has already been defined in null and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

二、解决方案

2.1 方案1

修改yml配置:spring.main.allow-bean-definition-overriding=true

spring:
  main:
    allow-bean-definition-overriding: true

2.2 方案2

在每个Feign的接口中,在注解上加 contextId属性

contextId在Feign Client的作用是在注册Feign Client Configuration的时候需要一个名称,名称是通过getClientName方法获取的

@FeignClient(name = \"sale-service\",contextId= \"saleservice1\")
 
public interface saleClient{
 
    @RequestMapping(value = \"/sale/add\", method = RequestMethod.GET)
 
    String add(@RequestParam(\"saleNum\") String queryStr);
 
}

备注:contextId= \"名称\" 中的名称,不能用“_”会报错,可以用“-”

三、源代码分析

  • 包名:spring-cloud-openfeign-core-2.2.5.RELEASE.jar
  • 类路径:org.springframework.cloud.openfeign.FeignClientsRegistrar

相关代码1

 private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map attributes) {
        String className = annotationMetadata.getClassName();
        BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
        this.validate(attributes);
        definition.addPropertyValue(\"url\", this.getUrl(attributes));
        definition.addPropertyValue(\"path\", this.getPath(attributes));
        String name = this.getName(attributes);
        definition.addPropertyValue(\"name\", name);
        String contextId = this.getContextId(attributes);
        definition.addPropertyValue(\"contextId\", contextId);
        definition.addPropertyValue(\"type\", className);
        definition.addPropertyValue(\"decode404\", attributes.get(\"decode404\"));
        definition.addPropertyValue(\"fallback\", attributes.get(\"fallback\"));
        definition.addPropertyValue(\"fallbackFactory\", attributes.get(\"fallbackFactory\"));
        definition.setAutowireMode(2);
        String alias = contextId + \"FeignClient\";
        AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
        beanDefinition.setAttribute(\"factoryBeanObjectType\", className);
        boolean primary = (Boolean)attributes.get(\"primary\");
        beanDefinition.setPrimary(primary);
        String qualifier = this.getQualifier(attributes);
        if (StringUtils.hasText(qualifier)) {
            alias = qualifier;
        }
 
        BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[]{alias});
        BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
    }

代码截图:

\"@FeignClient注解中属性contextId的使用说明_第1张图片\"

相关代码2

可以看到, name应该是从注解中的属性取值来的, 再看看getClientName()方法.

 private String getClientName(Map client) {
        if (client == null) {
            return null;
        } else {
            String value = (String)client.get(\"contextId\");
            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;
            } else {
                throw new IllegalStateException(\"Either \'name\' or \'value\' must be provided in @\" + FeignClient.class.getSimpleName());
            }
        }
    }

代码截图:

\"@FeignClient注解中属性contextId的使用说明_第2张图片\"

一目了然了, 我们声明@FeignClient注解时, 只使用了value属性, 所以产生了冲突, 只要加上contextId就好了.

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号