zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    现代软件工程 第一周博客作业
    最后一周总结
    阅读后感
    软件工程作业个人项目——csdn app分析
    第二次结对编程
    软件工程作业二
    软件工程作业一
    ASE 课程最后小结
    阅读后感
    Judy Beta 第五天
  • 原文地址:https://www.cnblogs.com/Android-Alvin/p/12102857.html
Copyright © 2011-2022 走看看