OkHttp3源码详解之拦截器(四)

阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680
1.构造Demo

首先构造一个简单的异步网络访问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/
阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680

推荐阅读更多精彩内容