美文网首页Android Network
OkHttp源码分析(二)整体流程

OkHttp源码分析(二)整体流程

作者: J__Beyond | 来源:发表于2017-05-07 11:06 被阅读116次

    以如下请求为例进行说明

    OkHttpClient httpClient = new OkHttpClient();
    Request request = new Request.Builder().url("http://gank.io/api/data/Android/10/1").build();
    Call call = httpClient.newCall(request);
    call.enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            Log.e(TAG, e.getMessage());
        }
    
        @Override
        public void onResponse(Call call, Response response) throws IOException {
            String result = response.body().string();
            Log.d(TAG, result);
        }
    });
    

    OkHttp和Request的构建就不说了,我们来看下Call的构建

    Call的构建

    Call是个接口

    public interface Call extends Cloneable {
      Request request();
      Response execute() throws IOException;
      void enqueue(Callback responseCallback);
      boolean isExecuted();
      boolean isCanceled();
      Call clone();
    
      interface Factory {
        Call newCall(Request request);
      }
    }
    

    内部还定义了一个Factory接口,OkHttpClient实现了该接口

    QQ20170507-084805@2x.png
    @Override 
    public Call newCall(Request request) {
       return new RealCall(this, request, false /* for web socket */);
    }
    

    内部创建了一个RealCall,注意RealCall是Call唯一实现类

    RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
        final EventListener.Factory eventListenerFactory = client.eventListenerFactory();
        this.client = client;
        this.originalRequest = originalRequest;
        this.forWebSocket = forWebSocket;
        this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
    
        // TODO(jwilson): this is unsafe publication and not threadsafe.
        this.eventListener = eventListenerFactory.create(this);
      }
    

    构造函数中做了以下几件事

    • EventListener.Factory先忽略,这里不关心;
    • 保存OkHttpClient实例;
    • 保存原始的Request实例;
    • WebSocket的标识,传过来的是false,表示没用WebSocket;
    • 创建了第一个拦截器RetryAndFollowUpInterceptor,用来处理请求异常重试;

    Call执行

    这里是个异步请求

    @Override 
    public void enqueue(Callback responseCallback) {
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already Executed");
          executed = true;
        }
        captureCallStackTrace();
        client.dispatcher().enqueue(new AsyncCall(responseCallback));
     }
    
    • client.dispatcher()返回Dispatcher对象,它在OkHttpClient构建时创建,用来处理请求的任务队列,使用了生产者消费者模式
    • 创建一个AsyncCall,丢给Dispatcher
    synchronized void enqueue(AsyncCall call) {
        if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
          runningAsyncCalls.add(call);
          executorService().execute(call);
        } else {
          readyAsyncCalls.add(call);
        }
      }
    
    • maxRequests = 64: 最大并发请求数为64
    • maxRequestsPerHost = 5: 每个主机最大请求数为5

    当满足正在执行的请求数小于64并且每个主机最大请求数小于5,直接把AsyncCall加到runningCalls的队列中,并在ExecutorService中执行。反之就放入readyAsyncCalls进行等待。这里会进入第一个if块。
    接着执行AsyncCall#execute

    @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);
          }
        }
    

    这个方法做了三件事

    1. 通过getResponseWithInterceptorChain执行请求
    • 处理回调,onRespons or onFailure
    • 释放Call,将执行完毕的Call从runningCalls队列中移除,并取出readyAsyncCalls中的一个Call加入到runningCalls执行。

    1.责任链分发请求与响应

    Response getResponseWithInterceptorChain() throws IOException {
        // Build a full stack of interceptors.
        List<Interceptor> interceptors = new ArrayList<>();
        interceptors.addAll(client.interceptors());
        interceptors.add(retryAndFollowUpInterceptor);
        interceptors.add(new BridgeInterceptor(client.cookieJar()));
        interceptors.add(new CacheInterceptor(client.internalCache()));
        interceptors.add(new ConnectInterceptor(client));
        if (!forWebSocket) {
          interceptors.addAll(client.networkInterceptors());
        }
        interceptors.add(new CallServerInterceptor(forWebSocket));
    
        Interceptor.Chain chain = new RealInterceptorChain(
            interceptors, null, null, null, 0, originalRequest);
        return chain.proceed(originalRequest);
      }
    

    在这个方法中我们看到了大量的Interceptor,不同的Interceptor赋予不同的职责,有的处理请求重试、有的处理缓存、有的处理请求压缩、有的执行实际的请求等等,这些Interceptor被Interceptor.Chain串联起来,顺序执行。

    这里使用了责任链设计模式

    责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。

    689802-816d907d9939eb58.png

    我们看看责任链的实现
    Interceptor是个接口,定义如下

    public interface Interceptor {
      Response intercept(Chain chain) throws IOException;
    
      interface Chain {
        Request request();
        Response proceed(Request request) throws IOException;
        Connection connection();
      }
    }
    

    内部还定义了Chain接口,RealInterceptorChain是唯一实现类,在getResponseWithInterceptorChain内部new了一个RealInterceptorChain
    然后调用RealInterceptorChain#proceed

    @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 {
        if (index >= interceptors.size()) throw new AssertionError();
    
        calls++;
    
        // If we already have a stream, confirm that the incoming request will use it.
        if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
          throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
              + " must retain the same host and port");
        }
    
        // If we already have a stream, confirm that this is the only call to chain.proceed().
        if (this.httpCodec != null && calls > 1) {
          throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
              + " must call proceed() exactly once");
        }
    
        // Call the next interceptor in the chain.
        RealInterceptorChain next = new RealInterceptorChain(
            interceptors, streamAllocation, httpCodec, connection, index + 1, request);
        Interceptor interceptor = interceptors.get(index);
        Response response = interceptor.intercept(next);
    
        // Confirm that the next interceptor made its required call to chain.proceed().
        if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
          throw new IllegalStateException("network interceptor " + interceptor
              + " must call proceed() exactly once");
        }
    
        // Confirm that the intercepted response isn't null.
        if (response == null) {
          throw new NullPointerException("interceptor " + interceptor + " returned null");
        }
        return response;
    }
    
    • 循环取出拦截器集合中的每个Interceptpr
    • 新建一个RealInterceptorChain,作为上一步取出的Interceptor#Intercept的参数
    • 调用Interceptor#Intercept方法,取出Request,在把它转发给下一个Interceptor之前做一些加工处理。
    • intercept中通过调用RealInterceptorChain#proceed,将请求转发给下一个Interceptor处理
    • 当前Interceptor将阻塞等待下一个Interceptor返回Response,拿到Response后,自己在加工处理一下再交给上一个Interceptor。
    1819140-312c2f839564cfa3.png

    后面将具体分析每一个拦截器的职责。

    2. 请求响应回调

    在getResponseWithInterceptorChain中拿到Response后需要回调Callback了。

    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);
          }
     } 
    

    回调失败

    两种情况

    • 请求被取消;
    • getResponseWithInterceptorChain内部发生IO异常;

    回调成功

    • onResponse,请求结果封装在ResponseBody中

    注意:onFailure和onResponse都执行在线程池的线程中,而不是UI线程。
    如果在以上回调中操作UI将抛出如下异常

    QQ20170507-161133@2x.png

    3. 释放Call

    在finally中最后调用了

    client.dispatcher().finished(this);
    

    按照Java语法规范,无论发生异常与否,finally中的代码必然会执行的。
    因此,最终调用Dispatcher#finished

    /** Used by {@code AsyncCall#run} to signal completion. */
    void finished(AsyncCall call) {
       finished(runningAsyncCalls, call, true);
    }
    
    private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
        int runningCallsCount;
        Runnable idleCallback;
        synchronized (this) {
          if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
          if (promoteCalls) promoteCalls();
          runningCallsCount = runningCallsCount();
          idleCallback = this.idleCallback;
        }
    
        if (runningCallsCount == 0 && idleCallback != null) {
          idleCallback.run();
        }
    }
    
    • promoteCalls为true
    • 从runningSyncCalls中移除该Call
    • 接着执行promoteCalls()函数
    private void promoteCalls() {
        if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
        if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
    
        for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
          AsyncCall call = i.next();
    
          if (runningCallsForHost(call) < maxRequestsPerHost) {
            i.remove();
            runningAsyncCalls.add(call);
            executorService().execute(call);
          }
    
          if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
        }
    }
    
    • 如果正在执行的队列任务数仍大于64,继续等待;
    • 如果等待队列为空,啥也不做,返回;
    • 循环从等待队列中取出一个AsyncCall
      • 如果满足单个主机并发数小于5,则将该AsyncCall加入执行队列,并执行execute;
      • 当执行队列并发数大于64,退出循环;

    Refference

    http://www.jianshu.com/p/aad5aacd79bf
    https://blog.piasy.com/2016/07/11/Understand-OkHttp/

    相关文章

      网友评论

        本文标题:OkHttp源码分析(二)整体流程

        本文链接:https://www.haomeiwen.com/subject/zrfytxtx.html