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条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Red5直播服务器,属于Java语言的直播服务器
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS6,CentOS7官方镜像安装Oracle11G
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- CentOS关闭SELinux安全模块
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Hadoop3单机部署,实现最简伪集群