概述
Redis作者说到:“灵活性被过分高估–>约束才是解放”。
–> 返回Netflix OSS套件专栏汇总 <–
代码下载地址:https://github.com/f641385712/feign-learning
目录
- 前言
- 正文
- OkHttp
- 使用示例
- 源码解析
- Apache HttpClient
- 使用示例
- 源码解析
- GoogleHttpClient
- 哪个更香?
- 总结
- 关注A哥
前言
前八篇文章介绍完了feign-core核心内容,从本篇开始将介绍它的“其它模块”。其实核心模块可以独立的work,但是不免它的能力偏弱,比如只能编码字符串类型、只能解码字符串类型,默认使用java.net.HttpURLConnection
作为HC…
本篇将介绍它的第一个模块:Client相关模块。我们知道,流行的开源Http库的性能均远高于JDK源生的HttpURLConnection
,因此实际生产中肯定是用的三方库来发送Http请求。
Feign它提供了feign.Client
抽象来发送Http请求,因此使得它拥有良好的扩展性,而恰好Feign的子模块里亦提供了对OkHttp
以及Apache HttpClient
的整合,本文将教你如何把Feign切换为第三方HC以提高性能。
正文
我们知道Feign在默认情况下,它发送Http请求使用的是JDK源生的HttpURLConnection
。而在实际生产环境下,直接使用它是100%不可取的,这就需要我们使用更加高效的HC。
Feign的模块中有三个关于HC的子模块:feign-okhttp
、feign-httpclient
、feign-googlehttpclient
。本文将会讨论前两者
OkHttp
它的GAV如下:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
<version>${feign.version}</version>
</dependency>
"携带"的okhttp版本号是:3.6.0
。(若把Feign调整到最新版本10.7.4
,那么它携带的okhttp版本号也就是最新的3.14.6
的了)
说明:okhttp虽然目前最新版本是4.x版本的,关于区别你可以简单粗暴的理解:前者是用kotlin改写了,后者还是用Java写的,其它的并无什么变化。
所以,在Server端使用okhttp,请务必使用3.x版本~移动端可酌情使用4.x版本
通过前八篇文章对Feign核心内容的学习,知道Feign最终是通过它的feign.Client
这个API去发送远程请求的,而feign.Client
是可以在构建的时候由使用者自定义指定的。有了以上理论的支撑,若想切换最终发送Http请求的HC,仅需在构建时使用自己的feign.Client
即可。
使用示例
public interface DemoClient {
@RequestLine("GET /feign/demo1?name={name}")
String getDemo1(@Param("name") String name);
}
构建Feign时,指定使用OkHttpClient
:
public static void main(String[] args) {
DemoClient client = Feign.builder()
.client(new OkHttpClient()) // 显示指定使用OkHttpClient
.target(DemoClient.class, "http://localhost:8080");
String result = client.getDemo1("YourBatman");
System.out.println(result);
}
一切正常work。附如下截图,以证明确实是okhttp在生效:
当然喽,如果你已经有现成的定制好的okhttpClient里,直接使用即可,形如这样:
// 项目内定制好的共用的OkHttpClient
// 注意:它和feign.okhttp.OkHttpClient同名哦
private static okhttp3.OkHttpClient myOkHttpClient(){
okhttp3.OkHttpClient hc = new okhttp3.OkHttpClient.Builder()
.connectTimeout(1, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.followRedirects(true)
.build();
return hc;
}
Feign.builder().client(new OkHttpClient(myOkHttpClient()))
源码解析
feign-okhttp
这个jar包内,有且仅有一个类:feign.okhttp.OkHttpClient
,它是对feign.Client
接口的实现。
public final class OkHttpClient implements Client {
private final okhttp3.OkHttpClient delegate;
// 空构造器:使用默认的OkHttpClient配置
public OkHttpClient() {
this(new okhttp3.OkHttpClient());
}
// 自己指定Client,比如用你项目里配置好的、公用的HC
public OkHttpClient(okhttp3.OkHttpClient delegate) {
this.delegate = delegate;
}
// 静态方法:把feign.Request转换为okhttp3.Request
static Request toOkHttpRequest(feign.Request input) {
...
// 什么时候发送时带Body发送呢?
// 方法是POST/PUT/PATCH时body才生效,其它时候body直接忽略掉
// 这是和JDK源生Client的区别哦
boolean isMethodWithBody = HttpMethod.POST == input.httpMethod()
|| HttpMethod.PUT == input.httpMethod()
|| HttpMethod.PATCH == input.httpMethod();
...
}
// 静态方法:把okhttp3.Response转为feign.Response
static feign.Response toFeignResponse(Response response, feign.Request request) {
...
}
// 把okhttp3.ResponseBody转为feign.Response.Body
static feign.Response.Body toBody(final ResponseBody input) throws IOException {
...
}
// 执行:发送Http请求,交给OkHttpClient带来来发送
@Override
public feign.Response execute(feign.Request input, feign.Request.Options options) throws IOException {
// 此处采用局部变量,而非直接在delegate身上操作,是为了保证线程安全
okhttp3.OkHttpClient requestScoped;
// 注意这个判断:只有当你传进来的Options值,和当前的delegate不相等,我才给你重新构建一个实例
// 若相等就没必要构建了嘛
// 说明:请务必使用新构建的方式,以保证线程安全
if (delegate.connectTimeoutMillis() != options.connectTimeoutMillis()
|| delegate.readTimeoutMillis() != options.readTimeoutMillis()) {
// 重新构建,使用Options传进来的值
requestScoped = delegate.newBuilder()
.connectTimeout(options.connectTimeoutMillis(), TimeUnit.MILLISECONDS)
.readTimeout(options.readTimeoutMillis(), TimeUnit.MILLISECONDS)
.followRedirects(options.isFollowRedirects())
.build();
} else {
requestScoped = delegate;
}
// 转换为okHttp的请求对象
Request request = toOkHttpRequest(input);
// 发送http远程请求
Response response = requestScoped.newCall(request).execute();
// 把okhttp的respone转换为Feign自己的
return toFeignResponse(response, input).toBuilder().request(input).build();
}
}
这个逻辑不难,其实就一普通的Http请求的发送,不同之处在于进行了两次数据转换:
- Request之前的转换
- Response之间的转换
其中,需要特别特别注意的是:请务必确保每次请求都是线程安全的。feign.Client
接口的Javadoc也特别强调了这一点~
Apache HttpClient
GAV如下:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
<version>${feign.version}</version>
</dependency>
它是基于Apache HttpClient
实现的,携带的HttpClient
版本号是:4.5.3
。
使用示例
使用方式几乎同上。
Feign.builder().client(new ApacheHttpClient()) ...
你可以可以使用你定义好的HC:
Feign.builder().client(new ApacheHttpClient(myApacheHttpClient())) ...
源码解析
同样的,feign-httpclient
这个jar有且仅有一个类:ApacheHttpClient
public final class ApacheHttpClient implements Client {
private final HttpClient client;
public ApacheHttpClient() {
this(HttpClientBuilder.create().build());
}
public ApacheHttpClient(HttpClient client) {
this.client = client;
}
...
@Override
public Response execute(Request request, Request.Options options) throws IOException {
HttpUriRequest httpUriRequest;
try {
// 请注意:HttpUriRequest实例,每次都是通过`org.apache.http.client.methods.RequestBuilder`构建出来的一个新实例
// 因此确保了线程安全性
httpUriRequest = toHttpUriRequest(request, options);
} catch (URISyntaxException e) {
throw new IOException("URL '" + request.url() + "' couldn't be parsed into a URI", e);
}
// 发送http请求,然后转换response
HttpResponse httpResponse = client.execute(httpUriRequest);
return toFeignResponse(httpResponse, request);
}
}
GoogleHttpClient
它基于的是Google的HC客户端google-http-client
实现的。比如典型API是com.google.api.client.http.HttpTransport
,该jar包同样也只有一个类:GoogleHttpClient
。
因这个客户端国内使用实在太少,因此本文就此略过。
–
哪个更香?
Apache HttpClient
是老牌HC,具有很多优秀的“品质”,值得信赖;而OkHttp
作为后起之秀,具有更加优越的性能表现,大有干掉老牌HC的势头。
总的来说:个人倾向于推荐使用Feign + OkHttp
的组合应用在你的生产环境中。
总结
本文介绍了Feign它首个子模块:关于Client的子模块。因为生产环境是,必定会使用OkHttp
或者Apache HttpClient
作为实际的HC,所以本篇文章应该能对你实际工作中会有所帮助。
从此篇开始,介绍的均是Feign的其它子模块,它可以理解为对feign-core核心内容的扩展,使得它提供的能力越来越完善,方便在生产上提供一站式的解决方案,这样Feign才更优秀、更具竞争力。
关注A哥
Author | A哥(YourBatman) |
---|---|
个人站点 | www.yourbatman.cn |
yourbatman@qq.com | |
微 信 | fsx641385712 |
活跃平台 | |
公众号 | BAT的乌托邦(ID:BAT-utopia) |
知识星球 | BAT的乌托邦 |
每日文章推荐 | 每日文章推荐 |
- [享学Feign] 一、原生Feign初体验,Netflix Feign还是Open Feign?
- [享学Feign] 二、原生Feign的注解介绍及使用示例
- [享学Feign] 三、原生Feign的核心API详解(一):UriTemplate、HardCodedTarget…
- [享学Feign] 四、原生Feign的核心API详解(二):Contract、SynchronousMethodHandler…
- [享学Feign] 五、原生Feign的编码器Encoder、QueryMapEncoder
- [享学Feign] 六、原生Feign的解码器Decoder、ErrorDecoder
- [享学Feign] 七、请求模版对象RequestTemplate和标准请求对象feign.Request
- [享学Feign] 八、Feign是如何生成接口代理对象的?Feign实例的构建器Feign.Builder详解
最后
以上就是高贵芒果为你收集整理的[享学Feign] 九、Feign + OkHttp和Feign + Apache HttpClient哪个更香?关注A哥的全部内容,希望文章能够帮你解决[享学Feign] 九、Feign + OkHttp和Feign + Apache HttpClient哪个更香?关注A哥所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复