@FeignClient注解中屬性contextId的使用說(shuō)明
一、概述
如果我們使用Feign定義了兩個(gè)接口,但是目標(biāo)服務(wù)是同一個(gè),那么在SpringBoot啟動(dòng)時(shí)就會(huì)遇到一個(gè)問(wèn)題:
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: true2.2 方案2
在每個(gè)Feign的接口中,在注解上加 contextId屬性
contextId在Feign Client的作用是在注冊(cè)Feign Client Configuration的時(shí)候需要一個(gè)名稱,名稱是通過(guò)getClientName方法獲取的
@FeignClient(name = "sale-service",contextId= "saleservice1")
public interface saleClient{
@RequestMapping(value = "/sale/add", method = RequestMethod.GET)
String add(@RequestParam("saleNum") String queryStr);
}備注:contextId= "名稱" 中的名稱,不能用“_”會(huì)報(bào)錯(cuò),可以用“-”
三、源代碼分析
- 包名:spring-cloud-openfeign-core-2.2.5.RELEASE.jar
- 類路徑:org.springframework.cloud.openfeign.FeignClientsRegistrar
相關(guān)代碼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);
}代碼截圖:

相關(guān)代碼2
可以看到, name應(yīng)該是從注解中的屬性取值來(lái)的, 再看看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注解時(shí), 只使用了value屬性, 所以產(chǎn)生了沖突, 只要加上contextId就好了.
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring Boot+Drools規(guī)則引擎整合詳解
本篇文章主要介紹了Spring Boot+Drools規(guī)則引擎整合,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09
mall整合SpringSecurity及JWT認(rèn)證授權(quán)實(shí)戰(zhàn)下
這篇文章主要為大家介紹了mall整合SpringSecurity及JWT認(rèn)證授權(quán)實(shí)戰(zhàn)第二篇,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
詳解SpringSecurity如何實(shí)現(xiàn)前后端分離
這篇文章主要為大家介紹了詳解SpringSecurity如何實(shí)現(xiàn)前后端分離,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
Java實(shí)現(xiàn)替換集合中的元素的方法詳解
這篇文章主要為大家詳細(xì)介紹了Java中實(shí)現(xiàn)替換集合中的元素的常見(jiàn)方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-02-02

