众妙之门

业精于勤,荒于嬉;行成于思,毁于随

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

属性:

value:指定FeignClient的名称,如果项目使用了Ribbon,name属性会作为微服务的名称,用于服务发现

configuration: Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contract

contextId:用来区分FeignClient实例名称

比如我们有个HBS_SERVICE服务,但HBS_SERVICE服务中有很多个对外接口,我们不想将所有的调用接口都定义在一个类中,比如:

CustomerClient1

@FeignClient(value = ServiceNameConstants.HBS_SERVICE, fallbackFactory = CustomerClientFallbackFactory.class)
public interface CustomerClient1 {
    ......
}

CustomerClient2

@FeignClient(value = ServiceNameConstants.HBS_SERVICE, fallbackFactory = CustomerClientFallbackFactory.class)
public interface CustomerClient2 {
    ......
}

在定义多个的时候,因为定了相同的value,启动服务会报错

Description:
The bean 'optimization-user.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

为了解决这个错误,有两种办法:

1.避免name重复,给contextId赋值。
2.在name重复的情况下允许BeanDefinition的覆盖,则配置spring.main.allow-bean-definition-overriding=true

如果我们使用的是第二种办法,而且要自定义一个Client的configuration时,设置对应Client的configuration属性,可能配置会不生效

@FeignClient(value = ServiceNameConstants.HBS_SERVICE, configuration = FeignSupportConfig.class, fallbackFactory = CustomerClientFallbackFactory.class)
public interface CustomerClient2 {
    ......
}

因为允许BeanDefinition的覆盖时,对应的FeignContext的配置也会覆盖,这种就需要单独设置contextId,配置才会生效

@FeignClient(contextId = "CustomerClient2", value = ServiceNameConstants.HBS_SERVICE, configuration = FeignSupportConfig1.class, fallbackFactory = CustomerClientFallbackFactory.class)
public interface CustomerClient2 {
    ......
}
FeignClientsRegistrar#registerClientConfiguration中去名字时,会根据规则使用FeignClient的名称来生成配置bean,如果名称相同,就会覆盖
    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());
    }

后面在调用的时候,就会通过代理FeignClientFactoryBean#getTarget来取FeignContext

    <T> T getTarget() {
        FeignContext context = beanFactory != null
                ? beanFactory.getBean(FeignContext.class)
                : applicationContext.getBean(FeignContext.class);
        Feign.Builder builder = feign(context);
        ......
    }

因为FeignClientSpecification被覆盖了,使用配置就没有起作用

posted on 2023-02-17 14:16  xuanm  阅读(1220)  评论(0编辑  收藏  举报