OkHttp源码分析

作者: 721d739b6619 | 来源:发表于2017-12-16 16:48 被阅读60次

前言

之前看过Retrofit的源码,Retrofit发送http请求最终是通过OkHttp为其完成的。如果对Retrofit源码不是很了解可以看这里Retrofit使用范例的源码分析

真正从这里开始

那么我们从Retrofit该框架作切入点,看看okhttp是如何发送请求的。
这里简单概括一下。

  • Retrofit的作用在我看来就是对发送okhttp请求的封装(即参数的封装,url包装等)
  • OkHttp的作用其实类似于URLConnection和HttpClient这类型。

Retrofit通过OkHttp发送请求从这里出发

Retrofit.create(final Class<T> service)

image.png

大家都知道Retrofit是基于动态代理实现对发送http请求参数的封装。
而生成代理对象就要通过此类此方法为其实现:
Proxy.newProxyInstance方法


image.png

如果对以上不了解可以看看动态代理

关于Retrofit就说到这,今天重点是OkHttp。

从第一章截图可以看到:
创建了一个 OkHttpCall对象,而Retrofit发送http请求就是通过这个对象完成的。当然,如果不同Retrofit也可以自己构建这么一个对象完成通过OkHttp发送请求。

OkHttpCall为OkHttp请求入口

该类发送http请求其实就是两个方法:

  • enqueue()
  • execute()


    image.png

我先拿其中一个来看,后面再说两者有什么不同;

enqueue(final Callback<T> callback)方法

直接将代码贴出来:

@Override public void enqueue(final Callback<T> callback) {
    if (callback == null) throw new NullPointerException("callback == null");

    okhttp3.Call call;
    Throwable failure;

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;

      call = rawCall;
      failure = creationFailure;
      if (call == null && failure == null) {
        try {
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          failure = creationFailure = t;
        }
      }
    }

    if (failure != null) {
      callback.onFailure(this, failure);
      return;
    }

    if (canceled) {
      call.cancel();
    }

    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
        Response<T> response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        callSuccess(response);
      }

步骤如下:

  • 1、createRawCall();创建OkHttp的call对象;
  • 2、出现终止请求情况就会 call.cancel();即canceled变量为true
  • 3、call.enqueue(new okhttp3.Callback() {});发送http请求;
  • 4、Callback发送请求回调函数;这里就是谁显示Callback回调函数了。
    这里再说多一点,像我们通过Retrofit + RxJava 即Retrofit里面的CallAdapter是RxJavaCallAdapterFactory,这时候RxJavaCallAdapterFactory是通过OkHttpCall的execute()非现在说的enqueue()请求。

如果可以看整个OkHttp发送请求就是这样了。但这就等于什么都没有说嘛。所以再看看在发送请求前,对于OkHttp对其添加一些参数,如添加header相关参数,打印日志等。基于这些,看看OkHttp里面的实现过程。

OkHttpClient封装

我们可以基于OkHttpClient封装诸如这些参数:


image.png

这里就会有个疑问,到底这些参数是怎么样被调用的。
往下看...

RealCall

在上面不管是调用enqueue()或execute()的时候,会调用createRawCall();获得call对象。

image.png
image.png
在serviceMethod.callFactory这个参数其实就是OkHttpClient
在封装Retrofit对象中会传入OkHttpClient;
image.png
既然知道callFactory是OkHttpClient那么就可以看看newCall(request)方法:
image.png

细看RealCall对象:

  • RealCall是实现Okhttp的Call接口,而Call接口是贯穿与整个Okhttp请求的。


    image.png
  • RealCall的execute()或enqueue(Callback responseCallback) 就是前面OkHttpCall中execute()和enqueue()的真正实现。
    同上面一样选择其中一个来看。这次看execute()


    image.png

核心就这么两行代码:

client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();

client.dispatcher()是什么

其实点击一下就会看到Dispatcher这个类的作用是什么了。


image.png
image.png

上面两图是在Dispatcher发现的。
基本上看完这里会发现execute()和enqueue()有什么不同。

  • execute()方法就是将call放入runningSyncCalls队列,runningSyncCalls管理call对象,而真正执行call的execute()方法在RealCall上。
  • enqueue()方法当线程池还有线程可以执行的时候,将call放入runningAsyncCalls;如果没有的话将call放入readyAsyncCalls队列。readyAsyncCalls队列里的call也是会执行的当执行完队列中的call对象就会检查readyAsyncCalls队列有没有需要执行的call对象:


    image.png
    image.png

getResponseWithInterceptorChain();

image.png
这里可以看到将所有的拦截器都放在List集合上。
创建了一个RealInterceptorChain对象,执行其proceed(originalRequest)方法。
其实这里就是整个OkHttp的核心了。

RealInterceptorChain的proceed()方法,递归执行每个Interceptor的intercept(next);

这里标题都说明得很清楚,执行每个Interceptor。而自定义的Interceptor都会放在前面被先执行。下面我们看看每个Interceptor的作用。

RetryAndFollowUpInterceptor

该拦截器从失败中恢复和必要时有重定向。 如果call被取消就会抛出IO异常
上面是该类的官方解释。简单来说该Interceptor如果第一次发送请求他没有做什么事情。更多是请求发送失败重试中用到。

BridgeInterceptor

该Interceptor主要做的就是将从传入来的Request请求头封装成网络发送http的规范请求头:


BridgeInterceptor的intercept()方法的部分截图.png

这里其实你还会看到OkHttp默认情况下是要求服务端返回的数据进行gzip压缩。然后OkHttp会将返回的数据解压。


image.png
image.png

CacheInterceptor

看名字就应该知道这个Interceptor是干什么的。其实就是缓存用的。

ConnectInterceptor

该ConnectInterceptor就是连接目标服务器的:


image.png
基于http1.1发送请求.png

上面截图将三种超时的时间设置了。

socket连接在RealConnection的connect()方法

在上面截图中其实有个方法是findHealthyConnection(connectTimeout, readTimeout,
writeTimeout, connectionRetryEnabled, doExtensiveHealthChecks);
就是下面截图中核心的执行过程。

image.png
buildConnection()方法
image.png
看到这里有个地方可以说,如果是http请求其实设置writeTimeout是没有任何意义的。在http或https请求是没有用到这个参数的。这里也反映了OkHttp请求不单单是基于http1.X请求还有websocket和SPY和http2.0都可以的。
最终socket连接其实是AndroidPlatform.connectSocket()
image.png

总结下:

  • AndroidPlatform继承Platform,调用connectSocket()最终实现Socket连接
  • RealConnection的connect()方法实现OkHttp的各种协议连接请求
  • StreamAllocation构建HttpStream和RealConection,为Socket连接作准备

CallServerInterceptor

CallServerInterceptor的intercept()方法:

  • 获取最终的Request
  • Http1xStream(继承HttpStream)通过writeRequestHeaders(request);写入到流中;
  • httpStream.readResponseHeaders()读取Response

整个OkHttp的http请求就是这样。这里输入输出流OkHttp是用Okio,也是它自家公司的一个开源项目。

相关文章

网友评论

    本文标题:OkHttp源码分析

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