OkHttp3源码详解(二整体流程)

来源:互联网 发布:电动汽车数据 编辑:程序博客网 时间:2024/05/01 06:37

     上一篇文章已经对Request相关的类进行了详细的学习,后面我发现Okhttp这种底层框架一个类一个类看没什么用,所以这篇文章开始就只对Okhttp的整体流程作一个学习

   1.简单的get请求

  

   Request request = new Request.Builder()                .url("https://www.baidu.com/")                .build();        client.newCall(request).enqueue(new Callback() {            @Override            public void onFailure(Call call, IOException e) {            }            @Override            public void onResponse(Call call, Response response) throws IOException {            }        });

  我们来看一下RealCall中的enqueue的逻辑看一下,
  @Override public void enqueue(Callback responseCallback) {    synchronized (this) {      if (executed) throw new IllegalStateException("Already Executed");      executed = true;    }    client.dispatcher().enqueue(new AsyncCall(responseCallback));  }

这个方法调用Dispatcher的enqueue方法

 synchronized void enqueue(AsyncCall call) {    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {      //正在运行的异步任务队列数量小于最大请求数,线程池执行该任务      runningAsyncCalls.add(call);      executorService().execute(call);    } else {      //把该方法放到异步任务准备队列中      readyAsyncCalls.add(call);    }  }

线程池执行该异步任务,会执行异步任务的run方法,run方法中调用了execute抽象方法,我们来看一下这个方法的实现

@Override protected void execute() {      boolean signalledCallback = false;      try {        //由getResponseWithInterceptorChain()来执行网络请求,得到response        Response response = getResponseWithInterceptorChain();        if (retryAndFollowUpInterceptor.isCanceled()) {          signalledCallback = true;          //失败后回调Callback的onFailure方法          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));        } else {          signalledCallback = true;          //成功后回调CallBack的onResponse方法          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 {        //最后调用Dispatcher的finish方法        client.dispatcher().finished(this);      }    }  

我们先来看finish方法,后面再去看getResponseWithInterceptorChain(),来解决简单的再去看复杂的

  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!");      //promoteCalls()该方法会去从异步准备运行的队列中去取任务去执行      if (promoteCalls) promoteCalls();      //得到异步和同步任务正在执行数      runningCallsCount = runningCallsCount();      idleCallback = this.idleCallback;    }    //如果设置了该线程,执行回调线程    if (runningCallsCount == 0 && idleCallback != null) {      idleCallback.run();    }  }

走完一个流程后我们来看一下getResponseWithInterceptorChain()方法的实现细节,这个方法在call.execute()也调用到了,OkHttp中真正发出网络请求,解析返回结果的,就是这个方法

private Response getResponseWithInterceptorChain() throws IOException {    //构建全栈拦截器    List 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 (!retryAndFollowUpInterceptor.isForWebSocket()) {      interceptors.addAll(client.networkInterceptors());//用户预定义的网络拦截器    }    interceptors.add(new CallServerInterceptor(        retryAndFollowUpInterceptor.isForWebSocket()));//调用服务拦截器    //内部通过责任链模式来使用拦截器    Interceptor.Chain chain = new RealInterceptorChain(        interceptors, null, null, null, 0, originalRequest);    return chain.proceed(originalRequest);//获取Response  }

这么多的拦截器,看着肯定很懵逼吧,是的我就是这样。我们就一个一个的来看吧


RetryAndFollowUpInterceptor

     重试与重定向拦截器,用来实现重试和重定向功能,内部通过while(true)死循环来进行重试获取Response(有重试上限,超过会抛出异常)。followUpRequest主要用来根据响应码来判断属于哪种行为触发的重试和重定向(比如未授权,超时,重定向等),然后构建响应的Request进行下一次请求。当然,如果没有触发重新请求就会直接返回Response。

 

BridgeInterceptor

 桥接拦截器,用于完善请求头,比如Content-Type、Content-Length、Host、Connection、Accept-Encoding、User-Agent等等,这些请求头不用用户一一设置,如果用户没有设置该库会检查并自动完善。此外,这里会进行加载和回调cookie。


CacheInterceptor

缓存拦截器,首先根据Request中获取缓存的Response,然后根据用于设置的缓存策略来进一步判断缓存的Response是否可用以及是否发送网络请求(CacheControl.FORCE_CACHE因为不会发送网络请求,所以networkRequest一定为空)。如果从网络中读取,此时再次根据缓存策略来决定是否缓存响应。


ConnectInterceptor

 连接拦截器,用于打开一个连接到远程服务器。说白了就是通过StreamAllocation获取HttpStream和RealConnection对象,以便后续读写。

 

@Override public Response intercept(Chain chain) throws IOException {    RealInterceptorChain realChain = (RealInterceptorChain) chain;    Request request = realChain.request();    StreamAllocation streamAllocation = realChain.streamAllocation();    // We need the network to satisfy this request. Possibly for validating a conditional GET.    boolean doExtensiveHealthChecks = !request.method().equals("GET");    HttpStream httpStream = streamAllocation.newStream(client, doExtensiveHealthChecks);    RealConnection connection = streamAllocation.connection();    return realChain.proceed(request, streamAllocation, httpStream, connection);  }
   实际上建立连接就是创建了一个HttpStream 对象,它将在后面的步骤中被使用,那它又是何方神圣呢?它是对 HTTP 协议操作

的抽象,有两个实现:Http2xStreamHttp1xStream,顾名思义,它们分别对应 HTTP/1.1 和 HTTP/2 版本的实现。

 在Http1xStram中,它利用Okio对Socket的读写操作进行封装,而创建HttpStream 对象的过程涉及到 StreamAllocationRealConnection,代码较长,这里就不展开,这个过程概括来说,就是找到一个可用的RealConnection,再利用RealConnection的输入输出(BufferedSourceBufferedSink)创建HttpStream 对象,供后续步骤使用。

  

 CallServerInterceptor

调用服务拦截器,拦截链中的最后一个拦截器,通过网络与调用服务器。通过HttpStream依次次进行写请求头、请求头(可选)、读响应头、读响应体。

@Override public Response intercept(Chain chain) throws IOException {    HttpStream httpStream = ((RealInterceptorChain) chain).httpStream();    StreamAllocation streamAllocation = ((RealInterceptorChain) chain).streamAllocation();    Request request = chain.request();        long sentRequestMillis = System.currentTimeMillis();    //向服务器发生request header    httpStream.writeRequestHeaders(request);        //如果有 request body    if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {      Sink requestBodyOut = httpStream.createRequestBody(request, request.body().contentLength());      BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);      //将请求实体内容通过Okio发送到服务器      request.body().writeTo(bufferedRequestBody);      bufferedRequestBody.close();    }        httpStream.finishRequest();       //读取 response header,先构造一个 Response 对象    Response response = httpStream.readResponseHeaders()        .request(request)        .handshake(streamAllocation.connection().handshake())        .sentRequestAtMillis(sentRequestMillis)        .receivedResponseAtMillis(System.currentTimeMillis())        .build();    //如果有 response body,就在response的基础上加上body构造一个新的 Response 对象           if (!forWebSocket || response.code() != 101) {      response = response.newBuilder()          .body(httpStream.openResponseBody(response))          .build();    }        if ("close".equalsIgnoreCase(response.request().header("Connection"))        || "close".equalsIgnoreCase(response.header("Connection"))) {      streamAllocation.noNewStreams();    }    int code = response.code();    if ((code == 204 || code == 205) && response.body().contentLength() > 0) {      throw new ProtocolException(          "HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());    }    return response;  }
 

  这里我们可以看到,核心工作都由HttpStream对象完成,而HttpStream实际上利用的是 Okio,而 Okio 实际上还是用的Socket,所以没什么神秘的,只不过一层套一层,层数有点多。

 其实 Interceptor 的设计也是一种分层的思想,每个Interceptor 就是一层。为什么要套这么多层呢?分层的思想在 TCP/IP 协议中就体现得淋漓尽致,分层简化了每一层的逻辑,每层只需要关注自己的责任(单一原则思想也在此体现),而各层之间通过约定的接口/协议进行合作(面向接口编程思想),共同完成复杂的任务。




OkHttp 还有很多细节部分没有在本文展开,例如 HTTP2/HTTPS 的支持等,但建立一个清晰的概览非常重要。对整体有了清晰认识之后,细节部分如有需要,再单独深入将更加容易。

在文章最后我们再来回顾一下完整的流程图:




   


 

  

 



 

2 0