@FeignClient注解中属性contextId的使用说明
一、概述
如果我们使用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<String, Object> 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); }
代码截图:
相关代码2
可以看到, name应该是从注解中的属性取值来的, 再看看getClientName()方法.
private String getClientName(Map<String, Object> 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注解时, 只使用了value属性, 所以产生了冲突, 只要加上contextId就好了.
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
相关文章
SpringBoot + Vue + ElementUI 实现 el-table 分页功能(详细步骤)
本文详细介绍了使用SpringBoot和Vue.js结合ElementUI实现分页功能的数据表格,从后端分页逻辑到前端展示和状态管理,全面解析如何高效处理大量数据,提升用户体验与系统性能,感兴趣的朋友跟随小编一起看看吧2024-09-09IDEA 集成log4j将SQL语句打印在控制台上的实现操作
这篇文章主要介绍了IDEA 集成log4j将SQL语句打印在控制台上的实现操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧2021-02-02springboot项目获取resources相对路径的方法
这篇文章主要介绍了springboot项目获取resources相对路径的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2020-12-12详解Java对象的强、软、弱和虚引用+ReferenceQueue
这篇文章主要介绍了详解Java对象的强、软、弱和虚引用+ReferenceQueue的相关资料,需要的朋友可以参考下2017-06-06基于OpenCv与JVM实现加载保存图像功能(JAVA 图像处理)
openCv有一个名imread的简单函数,用于从文件中读取图像,本文给大家介绍JAVA 图像处理基于OpenCv与JVM实现加载保存图像功能,感兴趣的朋友一起看看吧2022-01-01
最新评论