博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
OkHttp3源码详解(三) 拦截器
阅读量:6310 次
发布时间:2019-06-22

本文共 5285 字,大约阅读时间需要 17 分钟。

1.构造Demo

 

首先构造一个简单的异步网络访问Demo:

OkHttpClient client = new OkHttpClient();       Request request = new Request.Builder()  .url("http://publicobject.com/helloworld.txt")  .build();client.newCall(request).enqueue(new Callback() {  @Override  public void onFailure(Call call, IOException e) {    Log.d("OkHttp", "Call Failed:" + e.getMessage());  }  @Override  public void onResponse(Call call, Response response) throws IOException {    Log.d("OkHttp", "Call succeeded:" + response.message());  }});

2. 发起请求

OkHttpClient.newCall实际是创建一个RealCall实例:

@Override public Call newCall(Request request) {    return new RealCall(this, request, false /* for web socket */);}

RealCall.enqueue实际就是讲一个RealCall放入到任务队列中,等待合适的机会执行:

@Override public void enqueue(Callback responseCallback) {    synchronized (this) {      if (executed) throw new IllegalStateException("Already Executed");      executed = true;    }    captureCallStackTrace();    client.dispatcher().enqueue(new AsyncCall(responseCallback));}

从代码中可以看到最终RealCall被转化成一个AsyncCall并被放入到任务队列中,任务队列中的分发逻辑这里先不说,相关实现会放在疑问进行介绍。这里只需要知道AsyncCall的excute方法最终将会被执行:

[RealCall.java]    @Override protected void execute() {      boolean signalledCallback = false;      try {        Response response = getResponseWithInterceptorChain();        if (retryAndFollowUpInterceptor.isCanceled()) {          signalledCallback = true;          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));        } else {          signalledCallback = true;          responseCallback.onResponse(RealCall.this, response);        }      } catch (IOException e) {        if (signalledCallback) {          // Do not signal the callback twice!          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);        } else {          responseCallback.onFailure(RealCall.this, e);        }      } finally {        client.dispatcher().finished(this);      }    }  }

execute方法的逻辑并不复杂,简单的说就是:

  • 调用getResponseWithInterceptorChain获取服务器返回
  • 通知任务分发器(client.dispatcher)该任务已结束

getResponseWithInterceptorChain构建了一个拦截器链,通过依次执行该拦截器链中的每一个拦截器最终得到服务器返回。

3. 构建拦截器链

首先来看下getResponseWithInterceptorChain的实现:

源码路径:okhttp3/RealCall.java

1 // 开始执行整个请求 2 Response getResponseWithInterceptorChain() throws IOException { 3   // Build a full stack of interceptors. 4   // 拦截器栈 5   List
interceptors = new ArrayList<>(); 6 // 前文说过的 普通拦截器 7 interceptors.addAll(client.interceptors()); 8 // 重试拦截器,网络错误、请求失败等 9 interceptors.add(retryAndFollowUpInterceptor);10 // 桥接拦截器,主要是重构请求头即header11 interceptors.add(new BridgeInterceptor(client.cookieJar()));12 // 缓存拦截器13 interceptors.add(newCacheInterceptor(client.internalCache()));14 // 连接拦截器,连接服务器,https包装15 interceptors.add(new ConnectInterceptor(client));16 // 网络拦截器,websockt不支持,同样是自定义17 if (!forWebSocket) {18 interceptors.addAll(client.networkInterceptors());19 }20 // 服务拦截器,主要是发送(write、input)、读取(read、output)数据21 interceptors.add(new CallServerInterceptor(forWebSocket));22 23 // 开启调用链24 Interceptor.Chain chain = new RealInterceptorChain(25 interceptors, null, null, null, 0, originalRequest);26 return chain.proceed(originalRequest);27 }

其逻辑大致分为两部分:

  • 创建一系列拦截器,并将其放入一个拦截器数组中。这部分拦截器即包括用户自定义的拦截器也包括框架内部拦截器
  • 创建一个拦截器链RealInterceptorChain,并执行拦截器链的proceed方法

接下来看下RealInterceptorChain的实现逻辑:

1 public final class RealInterceptorChain implements Interceptor.Chain { 2   private final List
interceptors; 3 private final StreamAllocation streamAllocation; 4 private final HttpCodec httpCodec; 5 private final RealConnection connection; 6 private final int index; 7 private final Request request; 8 private int calls; 9 10 public RealInterceptorChain(List
interceptors, StreamAllocation streamAllocation,11 HttpCodec httpCodec, RealConnection connection, int index, Request request) {12 this.interceptors = interceptors;13 this.connection = connection;14 this.streamAllocation = streamAllocation;15 this.httpCodec = httpCodec;16 this.index = index;17 this.request = request;18 }19 20 @Override public Connection connection() {21 return connection;22 }23 24 public StreamAllocation streamAllocation() {25 return streamAllocation;26 }27 28 public HttpCodec httpStream() {29 return httpCodec;30 }31 32 @Override public Request request() {33 return request;34 }35 36 @Override public Response proceed(Request request) throws IOException {37 return proceed(request, streamAllocation, httpCodec, connection);38 }39 40 public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,41 RealConnection connection) throws IOException {42 43 ......44 // Call the next interceptor in the chain.45 RealInterceptorChain next = new RealInterceptorChain(46 interceptors, streamAllocation, httpCodec, connection, index + 1, request);47 Interceptor interceptor = interceptors.get(index);48 Response response = interceptor.intercept(next);49 50 ...... 51 52 return response;53 }54 }

proceed方法中的核心代码可以看到,proceed实际上也做了两件事:

  • 创建下一个拦截链。传入index + 1使得下一个拦截器链只能从下一个拦截器开始访问
  • 执行索引为index的intercept方法,并将下一个拦截器链传入该方法

 

转载于:https://www.cnblogs.com/ganchuanpu/p/6876283.html

你可能感兴趣的文章
关于量子理论:最初无意的简化,和一些人有意的强化和放大
查看>>
CentOS 6.9通过RPM安装EPEL源(http://dl.fedoraproject.org)
查看>>
“区块链”并没有什么特别之处
查看>>
没有功能需求设计文档?对不起,拒绝开发!
查看>>
4星|《先发影响力》:影响与反影响相关的有趣的心理学研究综述
查看>>
IE8调用window.open导出EXCEL文件题目
查看>>
python之 列表常用方法
查看>>
vue-cli脚手架的搭建
查看>>
在网页中加入百度搜索框实例代码
查看>>
在Flex中动态设置icon属性
查看>>
采集音频和摄像头视频并实时H264编码及AAC编码
查看>>
3星|《三联生活周刊》2017年39期:英国皇家助产士学会于2017年5月悄悄修改了政策,不再鼓励孕妇自然分娩了...
查看>>
高级Linux工程师常用软件清单
查看>>
堆排序算法
查看>>
folders.cgi占用系统大量资源
查看>>
路由器ospf动态路由配置
查看>>
zabbix监控安装与配置
查看>>
python 异常
查看>>
last_insert_id()获取mysql最后一条记录ID
查看>>
可执行程序找不到lib库地址的处理方法
查看>>