OkHttp3源码详解(三) 拦截器
首先构造一个简单的异步网络访问Demo:
1. OkHttpClient client = new OkHttpClient();
2. Request request = new Request.Builder()
3. .url("http://publicobject.com/helloworld.txt")
4. .build();
6. client.newCall(request).enqueue(new Callback() {
7. @Override
8. public void onFailure(Call call, IOException e) {
9. Log.d("OkHttp", "Call Failed:" + e.getMessage());
10. }
12. @Override
13. public void onResponse(Call call, Response response) throws IOException {
14. Log.d("OkHttp", "Call succeeded:" + response.message());
15. }
16. });
2. 发起请求
OkHttpClient.newCall
实际是创建一个RealCall
实例:
1. @Override
2. public Call newCall(Request request) {
3. return new RealCall(this, request, false /* for web socket */);
4. }
RealCall.enqueue
实际就是讲一个RealCall
放入到任务队列中,等待合适的机会执行:
1. @Override
2. public void enqueue(Callback responseCallback) {
3. synchronized (this) {
4. if (executed) throw new IllegalStateException("Already Executed");
5. executed = true;
6. }
7. captureCallStackTrace();
8. client.dispatcher().enqueue(new AsyncCall(responseCallback));
9. }
从代码中可以看到最终RealCall
被转化成一个AsyncCall
并被放入到任务队列中,任务队列中的分发逻辑这里先不说,相关实现会放在OkHttp源码分析——任务队列疑问进行介绍。这里只需要知道AsyncCall的excute方法最终将会被执行:
1. [RealCall.java]
2. @Override protected void execute() {
3. boolean signalledCallback = false;
4. try {
5. Response response = getResponseWithInterceptorChain();
6. if (retryAndFollowUpInterceptor.isCanceled()) {
7. signalledCallback = true;
8. responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
9. } else {
10. signalledCallback = true;
11. responseCallback.onResponse(RealCall.this, response);
12. }
13. } catch (IOException e) {
14. if (signalledCallback) {
15. // Do not signal the callback twice!
16. Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
17. } else {
18. responseCallback.onFailure(RealCall.this, e);
19. }
20. } finally {
21. client.dispatcher().finished(this);
22. }
23. }
24. }
execute方法的逻辑并不复杂,简单的说就是:
调用getResponseWithInterceptorChain获取服务器返回
通知任务分发器(client.dispatcher)该任务已结束
getResponseWithInterceptorChain构建了一个拦截器链,通过依次执行该拦截器链中的每一个拦截器最终得到服务器返回。
3. 构建拦截器链
首先来看下getResponseWithInterceptorChain的实现:
源码路径:okhttp3/RealCall.java
// 开始执行整个请求
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
// 拦截器栈
List<Interceptor> interceptors = new ArrayList<>();
// 前文说过的 普通拦截器
interceptors.addAll(client.interceptors());
// 重试拦截器,网络错误、请求失败等
interceptors.add(retryAndFollowUpInterceptor);
// 桥接拦截器,主要是重构请求头即header
interceptors.add(new BridgeInterceptor(client.cookieJar()));
// 缓存拦截器
interceptors.add(newCacheInterceptor(client.internalCache()));
// 连接拦截器,连接服务器,https包装
interceptors.add(new ConnectInterceptor(client));
// 网络拦截器,websockt不支持,同样是自定义
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
// 服务拦截器,主要是发送(write、input)、读取(read、output)数据
interceptors.add(new CallServerInterceptor(forWebSocket));
// 开启调用链
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, , originalRequest);
return chain.proceed(originalRequest);
}
其逻辑大致分为两部分:
创建一系列拦截器,并将其放入一个拦截器数组中。这部分拦截器即包括用户自定义的拦截器也包括框架内部拦截器
创建一个拦截器链RealInterceptorChain,并执行拦截器链的proceed方法
接下来看下RealInterceptorChain的实现逻辑:
public final class RealInterceptorChain implements Interceptor.Chain {
private final List<Interceptor> interceptors;
private final StreamAllocation streamAllocation;
private final HttpCodec httpCodec;
private final RealConnection connection;
private final int index;
private final Request request;
private int calls;
public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation,
HttpCodec httpCodec, RealConnection connection, int index, Request request) {
this.interceptors = interceptors;
this.connection = connection;
this.streamAllocation = streamAllocation;
this.httpCodec = httpCodec;
this.index = index;
this.request = request;
}
@Override public Connection connection() {
return connection;
}
public StreamAllocation streamAllocation() {
return streamAllocation;
}
public HttpCodec httpStream() {
return httpCodec;
}
@Override public Request request() {
return request;
}
@Override public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpCodec, connection);
}
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
......
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + , request);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
......
return response;
}
}
在proceed方法中的核心代码可以看到,proceed实际上也做了两件事:
创建下一个拦截链。传入index + 1使得下一个拦截器链只能从下一个拦截器开始访问
执行索引为index的intercept方法,并将下一个拦截器链传入该方法。
原文链接:https://www.bbsmax.com/A/MAzAEmQMz9/

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
OkHttp3源码详解(一) Request类
每一次网络请求都是一个Request,Request是对url,method,header,body的封装,也是对Http协议中请求行,请求头,实体内容的封装 public final class Request { private final HttpUrl url; private final String method; private final Headers headers; private final RequestBody body; private final Object tag; private volatile CacheControl cacheControl; // Lazily initialized. 1.HttpUrl HttpUrl主要用来规范普通的url连接,并且解析url的组成部分 现通过下面的例子来示例httpUrl的使用https://www.google.com/search?q=maplejaw①使用parse解析url字符串: 1. HttpUrl url = HttpUrl.parse("https://www.google.com/...
-
下一篇
OkHttp3源码详解(五)okhttp连接池复用机制
1、概述 提高网络性能优化,很重要的一点就是降低延迟和提升响应速度。 通常我们在浏览器中发起请求的时候header部分往往是这样的 keep-alive 就是浏览器和服务端之间保持长连接,这个连接是可以复用的。在HTTP1.1中是默认开启的。 连接的复用为什么会提高性能呢?通常我们在发起http请求的时候首先要完成tcp的三次握手,然后传输数据,最后再释放连接。三次握手的过程可以参考这里 TCP三次握手详解及释放连接过程 一次响应的过程 在高并发的请求连接情况下或者同个客户端多次频繁的请求操作,无限制的创建会导致性能低下。 如果使用keep-alive 在timeout空闲时间内,连接不会关闭,相同重复的request将复用原先的connection,减少握手的次数,大幅提高效率。 并非keep-alive的timeout设置时间越长,就越能提升性能。长久不关闭会造成过多的僵尸连接和泄露连接出现。 那么okttp在客户端是如果类似于客户端做到的keep-alive的机制。 2、连接池的使用 连接池的类位于okhttp3.ConnectionPool。我们的主旨是了解到如何在timeou...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7设置SWAP分区,小内存服务器的救世主
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Red5直播服务器,属于Java语言的直播服务器
- SpringBoot2全家桶,快速入门学习开发网站教程
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS8编译安装MySQL8.0.19
- MySQL数据库在高并发下的优化方案
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果