上文中,我们了解到要实现
Feign
客户端,主要是将 Method 方法的参数解析成 Http 请求的请求行、请求行、请求体,然后使用 HttpClient 发送请求。但为了实现这些设想,要解决以下问题:
1. REST 声明式规范(即支持的注解)有以下几种:Feign、JAX-RS 1/2、Spring Web MVC 都需要进行适配。这几种声明式注解的适配接口是 feign.Contract。
2. Http 客户端有 JDK 自带的 HttpURLConnection、Apache HttpComponnets、OkHttp3 、Netty 等,需要适配。这几种客户端的适配接口是 feign.Client。
3. 支持负载均衡与熔断。负载均衡 Ribbon 是对 feign.Client 进行包装。熔断 Hystrix 在 HystrixFeign 中自定义 InvocationHandlerFactory 的实现,创建 HystrixInvocationHandler,对 method.invoke 请求做拦截。
4. 各种编解码的适配,实现接口 feign.codec.Decoder 和 feign.codec.Encoder。
下面一个一个来了解一下这些问题的feign解决方案:
REST框架 | 使用场景 | 请求映射注解 | 请求参数 |
---|---|---|---|
JAX-RS( Java API for RESTful Web Services, 参考:使用 JAX-RS 简化 REST 应用开发) | 客户端声明、 服务端声明 | @Path | @PathParam |
Feign | 客户端声明 | @RequestLine | @Param |
Spring Web MVC | 服务端声明 | @ReqeustMapping | @RequestParam |
总结: 这几种规范,其中 Feign
已经适配了 JAX-RS 1/2 和 Feign 自带的注解规范。Spring Cloud Open Feign
进一步适配了 Spring Web MVC 的注解规范。
//接口中用@RequestLine
public interface GitHub {
// https://api.github.com/repos/OpenFeign/feign/contributors
@RequestLine("GET /repos/{owner}/{repo}/contributors")
List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);
}
public class Test{
//这里用 Feign.builder()
public static void main(String[] args) {
GitHub github = Feign.builder()
.decoder(new GsonDecoder())
.target(GitHub.class, "https://api.github.com");
List<Contributor> contributors = github.contributors("OpenFeign", "feign");
for (Contributor contributor : contributors) {
System.out.println(contributor);
}
}
}
将上面的列子改成用JAX-RS的实现
<dependency>
<groupId>io.github.openfeigngroupId>
<artifactId>feign-jaxrsartifactId>
<version>9.5.0version>
dependency>
<dependency>
<groupId>javax.ws.rsgroupId>
<artifactId>jsr311-apiartifactId>
<version>1.1.1version>
dependency>
public interface GitHub2_javax {
@GET
@Path("/repos/{owner}/{repo}/contributors")
List<Contributor> contributors(@PathParam("owner") String owner, @PathParam("repo") String repo);
}
public class Test {
public static void main(String[] args) {
GitHub2_javax github = Feign.builder()
.decoder(new GsonDecoder())
.options( new Request.Options(1000,3500)) //options方法指定连接超时时长及响应超时时长
// retryer方法主要是指定重试策略
.retryer( new Retryer.Default(5000,5000,3))
// Contract 指明是哪种注解规范
.contract(new JAXRSContract())
// 为构造器配置本地的代理接口,和远程的根目录。代理接口类的每一个接口方法前@RequestLine 声明的值,最终都会加上这个根目录。
.target(GitHub2_javax.class, "https://api.github.com");
List<Contributor> contributors = github.contributors("OpenFeign", "feign");
for (Contributor contributor : contributors) {
System.out.println(contributor);
}
}
}
只演示一下OkHttp的用法,其它的客户端插件是一样的
feign-okhttp
<dependency>
<groupId>io.github.openfeigngroupId>
<artifactId>feign-okhttpartifactId>
<version>10.2.0version>
dependency>
GitHub2_javax github = Feign.builder()
.client(new OkHttpClient())
.decoder(new GsonDecoder())
.contract(new JAXRSContract())
.target(GitHub2_javax.class, "https://api.github.com");
com.netflix.feign
feign-hystrix
8.18.0
GitHub github = HystrixFeign.builder()
.target(GitHub.class, "https://myAppProd");
com.netflix.feign
feign-ribbon
8.15.1
GitHub github = Feign.builder()
.client(RibbonClient.create())
.target(GitHub.class, "https://myAppProd");
<dependency>
<groupId>io.github.openfeigngroupId>
<artifactId>feign-gsonartifactId>
<version>10.4.0version>
dependency>
public class MyApp {
public static void main(String[] args) {
GitHub github = Feign.builder()
.encoder(new GsonEncoder())
.decoder(new GsonDecoder())
.options(new Request.Options(10000,10000,true))
.target(GitHub.class, "https://api.github.com");
List<Contributor> contributors = github.contributors("OpenFeign", "feign");
for (Contributor contributor : contributors) {
System.out.println(contributor);
}
}
}
<dependency>
<groupId>io.github.openfeigngroupId>
<artifactId>feign-jacksonartifactId>
<version>11.0version>
dependency>
GitHub github = Feign.builder()
.encoder(new JacksonEncoder())
.decoder(new JacksonDecoder())
.options(new Request.Options(10000,10000,true))
.target(GitHub.class, "https://api.github.com");
参考: https://blog.csdn.net/zhangyingchengqi/article/details/109385205