Feign 使用服务名调用

之前都是使用@FeignClient,代码大概是这样的

@FeignClient(
    name = "file-upload-service",
    configuration = FileUploadServiceClient.MultipartSupportConfig.class
)
public interface FileUploadServiceClient extends IFileUploadServiceClient {

  public class MultipartSupportConfig {

    @Autowired
    private ObjectFactory messageConverters;

    @Bean
    public Encoder feignFormEncoder () {
      return new SpringFormEncoder(new SpringEncoder(messageConverters));
    }
  }
}

在@FeignClient中的name指定服务名,但是我不想使用MultipartFile做参数,因为这样需要将file转MultipartFile。于是我就决定使用这种方式

public class BankService {
  public static void main(String[] args) {
    Bank bank = Feign.builder().decoder(
        new AccountDecoder())
        .target(Bank.class, "https://api.examplebank.com");
  }
}

一开始,我从github上Feign的示例看到使用服务名代替url的Host部分有个示例

public class Example {
  public static void main(String[] args) {
    MyService api = Feign.builder()
          .client(RibbonClient.create())
          .target(MyService.class, "https://myAppProd");
  }
}

刚好我这项目也用到了Ribbon,但是在RibbonClient的介绍中看到了这个

This integration relies on the Feign Target.url() being encoded like https://myAppProd where myAppProd is the ribbon client or loadbalancer name and myAppProd.ribbon.listOfServers configuration is set.

这个意思是需要设置.ribbon.listOfServers,如果设置这个的话不还是得在配置文件中写IP和端口吗?我觉得不合理,然后查看spring cloud的文档,我看到了这个


TIM图片20190522150008.png

不使用Eureka的时候才需要设置.ribbon.listOfServers,但是项目是使用Eureka的,应该不需要设置才对,但是不设置的话,用这个方式调用是不行的,根据服务名找不到服务

MyService api = Feign.builder()
          .client(RibbonClient.create())
          .target(MyService.class, "https://myAppProd");

但是使用RestTemplate 加上@LoadBalanced是没有问题的,通过debug源码,发现使用@LoadBalanced是有个地方会加载服务列表,但是使用Feign的RibbonClient不会。所以我觉得是RibbonClient的问题,所以我在github上提了一个issue,但是没有得到解决。

因为使用@FeignClient的时候是可以找到服务的,说明Feign完全可以支持使用服务名调用,于是我查看Feign中Client的实现有哪些


1.png

很好,有个LoadBalancerFeignClient,我猜使用这个就可以达到服务名调用,于是查看怎么实例化这个Client,一搜构造方法的调用就找到了这个

@Configuration
class DefaultFeignLoadBalancedConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
                              SpringClientFactory clientFactory) {
        return new LoadBalancerFeignClient(new Client.Default(null, null),
                cachingFactory, clientFactory);
    }
}

这都实例化好了,所以直接注入就可以使用

最终解决方法来了

@Autowired
    private Client feignClient;
    
    public Result test() {
        TestApi test= Feign.builder()
                               .encoder(new FormEncoder(new JacksonEncoder()))
                               .decoder(new JacksonDecoder())
                               .client(feignClient)
                               .target(TestApi .class, "http://service-name/");
        return test.test();
    }

把RibbonClient换成注入的feignClient

你可能感兴趣的:(Feign 使用服务名调用)