OkHttp 是一款优秀的 HTTP 框架,项目里一直在使用,但说来惭愧,用了这么久还没有仔细分析过它的源码。现在正好趁着团队成员分享的热乎劲,也来总结一下。

流程图

首先对流程有一个大体的认知,然后按此流程逐步分析。

首先通过建造者模式创建了 OkHttpClient,我们先来看下 OkHttpClient 类。

OkHttpClient

OkHttpClient 实现了 Call.Factory 接口,负责创建 Call 的实例发起请求得到响应。 我们来看一下它是如何创建 Call 实例的。

/**
 * 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 实例,RealCallCall 的唯一实现类。

获取到 Call 后我们就可以发起请求了。从流程图中我们可以看到异步请求和同步请求大致流程是相同的,只不过异步请求多了一个 Dispatcher 分发器。我们可以先绕过这块,先分析下同步请求的流程,回头再看下 Dispatcher。

同步网络请求

同步请求调用的是 RealCallexecute 方法。

@Override
public Response execute() throws IOException {
    // 1
    synchronized (this) {
        if (executed) throw new IllegalStateException("Already Executed");
        executed = true;
    }
    captureCallStackTrace();
    eventListener.fetchStart(this);
    try {
        // 2
        client.dispatcher().executed(this);
        // 3
        Response result = getResponseWithInterceptorChain();
        if (result == null) throw new IOException("Canceled");
        eventListener.fetchEnd(this, null);
        return result;
    } catch (IOException e) {
        eventListener.fetchEnd(this, e);
        throw e;
    } finally {
        // 4
        client.dispatcher().finished(this);
    }
}

1.每个 Call 只能被执行一次,如果执行过了则抛出异常。 2.将这个 Call 放入 Dispatcher 的用于存放正在执行的同步 Call 的 ArrayDeque 队列中 3.调用 getResponseWithInterceptorChain() 函数获取 HTTP 返回结果。 4.通知 dispatcher 自己已经执行完毕,从队列中清除。

getResponseWithInterceptorChain 源码

Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    // 创建拦截器列表
    List<Interceptor> interceptors = new ArrayList<>();
    // 1
    interceptors.addAll(client.interceptors());
    // 2
    interceptors.add(retryAndFollowUpInterceptor);
    // 3
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    // 4
    interceptors.add(new CacheInterceptor(client.internalCache()));
    // 5
    interceptors.add(new ConnectInterceptor(client));
    // 6
    if (!forWebSocket) {
        interceptors.addAll(client.networkInterceptors());
    }
    // 7
    interceptors.add(new CallServerInterceptor(forWebSocket));
    // 8
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
            originalRequest, this, eventListener, client.connectTimeoutMillis(),
            client.readTimeoutMillis(), client.writeTimeoutMillis());
    // 9
    return chain.proceed(originalRequest);
}

这里就是 OkHttp 最巧妙的部分了,拦截器链。链上的每一环负责不同的功能。 1.客户端自定义的拦截器 2.重试和重定向拦截器 3.桥接拦截器,负责将用户请求转换为网络请求,将网络请求结果转换为用户结果 4.缓冲拦截器 5.连接复用

评论