Feign 使用服务名调用
之前都是使用@FeignClient,代码大概是这样的
@FeignClient(
name = "file-upload-service",
configuration = FileUploadServiceClient.MultipartSupportConfig.class
)
public interface FileUploadServiceClient extends IFileUploadServiceClient {
public class MultipartSupportConfig {
@Autowired
private ObjectFactory<HttpMessageConverters> 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