网上有很多解决此问题的文章,有的是加配置spring.main.allow-bean-definition-overriding=true,这不是解决问题的优雅的办法,有的是什么模块重复引入了,我这里不是这种情况,还有的文章说一个微服务只能调用一个feignClient接口,这就瞎扯了,你觉得写feign框架的作者会做出这种设计吗?
换位思考下,如果你来设计这个feign框架,如果引入了多个feignClient就要配置allow-bean-definition-overriding=true或者一个微服务只能有一个feignClient吗?
so,问题点肯定还没找到,看源码
org.springframework.cloud.openfeign.FeignClientsRegistrar#registerClientConfiguration
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,
Object configuration) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(FeignClientSpecification.class);
builder.addConstructorArgValue(name);
builder.addConstructorArgValue(configuration);
registry.registerBeanDefinition(
name + "." + FeignClientSpecification.class.getSimpleName(),
builder.getBeanDefinition());
}
每一个feignClient都会注册一个FeignClientSpecification到bean工厂,name参数就不能重复了,如何取的name,继续看代码
org.springframework.cloud.openfeign.FeignClientsRegistrar#getClientName
private String getClientName(Map<String, Object> client) {
if (client == null) {
return null;
}
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;
}
throw new IllegalStateException("Either 'name' or 'value' must be provided in @"
+ FeignClient.class.getSimpleName());
}
name的获取顺序是contextId--value--name--serviceId,至此,已非常清晰
我们只要在每一个FeignClient注解上加上contextId属性即可,属性值一般为类名,唯一即可
最后再看下FeignClient注解contextId属性的注释
/**
* This will be used as the bean name instead of name if present, but will not be used
* as a service id.
* @return bean name instead of name if present
*/
String contextId() default "";