OKHttp源码解析

作者: Dotry | 来源:发表于2019-07-30 19:45 被阅读10次

前言

关于okhttp在Android开发中经常使用到,但是最近在从okhttp 2.0升级之后,发现改动的内容蛮大,在各种研究整理后,发现okhttp 不是几天就能够钻研透,现将自己的总结与思考做个小结,后面会持续read the fuck code.

架构

这篇博客主要是从okhttp的总体流程分析源码的执行过程,对okhttp源码有大体上的理解,从全局上看出okhttp的设计思想。先上一张自己总结的图,后面会由开始基础使用逐渐升入。


OKHttp请求流程.jpg

okhttp的整体基本流程基本上就是这个图了,简单概括可以做如下说明:

  1. 采用建造者设计模式创建okhttpclient 对象和请求request对象。
  2. 采用newCall 方法来生成真正的请求对象。
  3. 请求分为同步和异步两种方式,最终均是通过getResponseWithInterceptorChain 方法来实现网络请求。

分析

1 client 创建方式:
默认创建方式

public OkHttpClient() {
  this(new Builder());
}

创建者创建方式

 public OkHttpClient build() {
      return new OkHttpClient(this);
    }
  1. Request 创建方式:
 Request(Builder builder) {
    this.url = builder.url;
    this.method = builder.method;
    this.headers = builder.headers.build();
    this.body = builder.body;
    this.tags = Util.immutableMap(builder.tags);
  }

可以看出对于Request 也是一个构造者模式,那么我们来看一下builder构造方法:

public Builder() {
      this.method = "GET";
      this.headers = new Headers.Builder();
    }

会指定默认的方法和header。
无论是client还是request,亦或者是header都是使用创建者设计模式,整个模式在OKHttp中使用的非常多。
3 . 同步请求方式
构建完Request后,我们就需要构建一个Call,一般都是这样的Call call = mOkHttpClient.newCall(request);
通过call去执行相关的同步请求。

Response response = client.newCall(request).execute();

response 即为请求结果。

  1. 异步请求方式
    同样也是需要构造一个Call对象,请求方式如下:
client.newCall(request).enqueue(new Callback() {
      @Override
      public void onFailure(Call call, IOException e) {

      }

      @Override
      public void onResponse(Call call, Response response) throws IOException {

      }
    });

可以看出两者的请求方式都是通过一个Call 对象去执行,那么我们可以去看下这个call对象是什么了。查看源码可以看出newCall方法:

 /**
     * Prepares the {@code request} to be executed at some point in the future.
     */
    @Override
    public Call newCall(Request request) {
        return RealCall.newRealCall(this, request, false /* for web socket */);
    }

最终都是返回RealCall对象。RealCall构造方法如下:

 private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client);
    this.timeout = new AsyncTimeout() {
      @Override protected void timedOut() {
        cancel();
      }
    };
    this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);
  }

可以看出会判断是否是WebScoket 和增加一个默认的Interceptor--RetryAndFollowUpInterceptor。
正同架构图中所介绍一样,会有各种Interceptor。

同步与异步方法

  1. 同步方法:
@Override
    public Response execute() throws IOException {
        synchronized (this) {
            if (executed) throw new IllegalStateException("Already Executed");
            executed = true;
        }
        captureCallStackTrace();
        timeout.enter();
        eventListener.callStart(this);
        try {
            //执行同步请求,其实是将同步任务添加到集合中
            client.dispatcher().executed(this);
            //执行网络请求
            Response result = getResponseWithInterceptorChain();
            if (result == null) throw new IOException("Canceled");
            return result;
        } catch (IOException e) {
            e = timeoutExit(e);
            eventListener.callFailed(this, e);
            throw e;
        } finally {
            //无论结果如何均会调用finish 方法
            client.dispatcher().finished(this);
        }
    }

getResponseWithInterceptorChain 为网络请求相关方法,可以看到无论只想结果如何都会执行dispatcher对象的finish 方法。
2.异步方法:

 @Override
    public void enqueue(Callback responseCallback) {
        synchronized (this) {
            if (executed) throw new IllegalStateException("Already Executed");
            executed = true;
        }
        captureCallStackTrace();
        eventListener.callStart(this);
        client.dispatcher().enqueue(new AsyncCall(responseCallback));
    }

继续查看:

void enqueue(AsyncCall call) {
    synchronized (this) {
      readyAsyncCalls.add(call);

      // Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
      // the same host.
      if (!call.get().forWebSocket) {
        AsyncCall existingCall = findExistingCallWithHost(call.host());
        if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
      }
    }
    promoteAndExecute();
  }

对于Dispatcher 类主要关注这几个集合:

/**
   * Ready async calls in the order they'll be run.
   * 将要执行的异步任务集合
    */
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

  /**
   *  Running asynchronous calls. Includes canceled calls that haven't finished yet.
   *  正在执行的异步任务集合
   */
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

  /**
   *  Running synchronous calls. Includes canceled calls that haven't finished yet.
   *  同步任务的集合
   */
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

以上为一个简单分析,后面会依次查看原来来分析okhttp的相关源码。

相关文章

网友评论

    本文标题:OKHttp源码解析

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