目录

1.概览(Overview)

2.详细说明(Details)

2.1 首先,定义调用接口

2.2 然后,构造可调用实例即可

2.3 接下来,展示一个实际的需求及使用示例

3.补充说明


1.概览(Overview)

springcloud中feignClient对原生feign进行了上层封装,得以在Spring环境下对开发人员有较好的细节屏蔽,方便了我们快捷的使用。

不过,有些时候我们想要跳出该封装,进行灵活的使用,比如以下场景:

  • 需要根据用户的配置,在不重启机器的情况下完成服务地址的切换,比如将临时传进来的参数作为基础地址
  • 大量的基础参数重复在各个接口间进行定义、传送,比如一些服务的基础参数:appId等(当然,Spring-cloud-netfix中的@Feignclient中的configuration也可以做同样的事,不过可以抛开Springcloud实现,深入看下feign内部结构)

这种情况下,则需要使用原生feign。

2.详细说明(Details)

接下来的介绍主要基于如何开发进行展开,分为三部分:

  • demo:定义调用接口
  • demo:如何进行调用
  • 真实场景实现及注意点

2.1 首先,定义调用接口

(主要使用@RequestLine标注method,代替Springcloud下的@Feignclient标注Class)

interface GitHub {
// 接口类型 uri
@RequestLine("GET /repos/{owner}/{repo}/contributors")
List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);
 
@RequestLine("POST /repos/{owner}/{repo}/issues")
void createIssue(Issue issue, @Param("owner") String owner, @Param("repo") String repo);
}
 
public static class Contributor {
String login;
int contributions;
}
 
public static class Issue {
String title;
String body;
List<String> assignees;
int milestone;
List<String> labels;
}

2.2 然后,构造可调用实例即可

说明:仅为示例,真实使用时不建议每次直接build,尤其时调用量较大的接口

public class MyApp {
public static void main(String... args) {
// 使用时进行构造
GitHub github = Feign.builder()
.decoder(new GsonDecoder())
.target(GitHub.class, "https://api.github.com");//传入url
 
// Fetch and print a list of the contributors to this library.
List<Contributor> contributors = github.contributors("OpenFeign", "feign");
for (Contributor contributor : contributors) {
System.out.println(contributor.login + " (" + contributor.contributions + ")");
}
}
}

实际项目使用过程中,不可能每次调用均新建feign实例,内存开销将会很大。

2.3 接下来,展示一个实际的需求及使用示例

(1) 需求描述

  • 产品需要对接一个外部系统openapi,但是此外部系统的详细信息需要通过界面配置(即运维人员在后期可灵活更改该系统地址而无需重启后台服务)进行灵活替换
  • 界面配置外部系统地址后立即生效

(2) 本示例实现如下能力

  • 根据外部接口方式(使用某个service作为获取源)作为feignclient的基础地址
  • 在feignclient构造时将其公共不变参数固定(从而无需在接口中重复定义和传入)

(3) 源码展示

  1. 接口定义
interface CustomFeignClient {
// 接口类型 uri
@RequestLine("GET /test/{resourceId}/list")
List<String> list(@Param("resourceId") String resourceId);
}
  1. feignclient构造及发布
@Autowired
private DynamicUrlService dus;
 
@Bean
public CustomFeignClient client(SpringEncoder encoder, SpringDecoder decoder) {
return Feign.builder()
.encoder(encoder)//编码器
.decoder(decoder)//解码器
.target(new Target<CustomFeignClient>() {
@Override
public Class<CustomFeignClient> type() {
return CustomFeignClient.class;
}
 
@Override
public String name() {
return "***";
}
 
@Override
public String url() {
// 获取实时url
return dus.url();
}
 
@Override
public Request apply(RequestTemplate input) {
if (input.url().indexOf("http") != 0) {
input.insert(0, url());
}
// 读取并设置基本参数,与Spring cloud netfix中的拦截器中apply功能一样
input.query("***", "**");
 
return input.request();
}
});
}
  1. 最后,可以正常调用该feignclient
@Autowired
private CustomFeignClient client;
 
public void test() {
// 调用
client.list(“testId”);
}

 

此方式相较于demo中的方式,可以避免频繁创建client,而且保证了动态性。

3.补充说明

以上展示了一个动态切换url需求,并以原生feign构造的方式进行了实现,此方式在Spring cloud体系下不建议使用(除非特定的需求),因为会破坏负载均衡等机制。

 

参考文档:https://github.com/OpenFeign/feign