OKHttp3源码解析(第一篇)

作者: 一盘好书 | 来源:发表于2018-04-11 22:27 被阅读147次

构建者模式

在创建OkHttpClient时,用到了构建者模式。就是在OkHttpClient对象中加入了一个Builder的内部类,在初始化时可以传递和构建一些内部数据。

下面我们来利用构建者模式简单来实现一个对象的初始化,看看其在构建对象时的优势何在。

public class Person {
    private final String name;
    private final int age;
    private final float height;

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

    public Person(Builder builder) {
        this.name = builder.name;
        this.age = builder.age;
        this.height = builder.height;
    }

    public Builder newBuilder() {
        return new Builder(this);
    }

    public static class Builder {
        private String name;
        private int age;
        private float height;

        public Builder(Person person) {
            name = person.name;
            age = person.age;
            height = person.height;
        }

        public Builder() {
            name = "lisa";
            age = 15;
            height = 156.5f;
        }

        public Builder age(int age) {
            this.age = age;
            return this;
        }

        public Builder name(String name) {
            this.name = name;
            return this;
        }

        public Person build() {
            return new Person(this);
        }
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public float getHeight() {
        return height;
    }
}

如上所示,优点如下:
第一,person对象不用理会具体的数据初始化与内部数据的管理;
第二,结构清晰明了,分工明确;
第三,使用简单,创建对象时可修改不同属性。

在来看看具体使用如下:

Person person = new Person().newBuilder()
        .name("tom")
        .age(17)
        .build();

发送请求入口

初始化OkHttpClient后,实际上利用RealCall对象发起请求,调用了RealCall对象的enqueue方法

okHttpClient.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
    }

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

RealCall初始化的时候传入了三个变量,并且初始化了一个拦截器。

private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}

最终通过调度器Dispatcher对象,利用线程池进行网络请求

synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

拦截器的添加

通过线程池调用了AsyncCall类中的execute方法,并在该方法中调用了getResponseWithInterceptorChain方法,添加多个拦截器。由以下代码可知,我们添加的拦截器会在添加中拦截器集合中最开始的位置,由后面的分析可知,我们的拦截器也会先于所有拦截器而被执行。

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, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
  }

然后再来看RealInterceptorChain.proceed()方法中的重要逻辑。

...

// 在RealInterceptorChain.proceed()方法中,会新创建一个RealInterceptorChain对象
//,其中index自增1,用于下次proceed方法调用时,启用下一个拦截器的intercept方法;
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);

...

然后在拦截器的intercept方法中调用新的RealInterceptorChain对象的proceed方法,形成一个闭环链式调用。
到这就明白了,为什么在拦截器中一定要调用RealInterceptorChain.proceed()方法的原因了,因为它是链式闭环上的一个环节,如下图:

示意图

最终进入到最后一个拦截器CallServerInterceptor中,在这里面进行真正的网络请求,之前所有拦截器中所有对request和response的修改最终集合到这一个拦截器中,这种设计挺巧妙的,而且逻辑和层次很清晰。

下一篇将重点介绍一下CallServerInterceptor这个网络请求的拦截器以及其他几个内部的拦截器的具体实现。

最后欢迎大家提问一起讨论,也欢迎指出文中错误,谢谢!

相关文章

网友评论

    本文标题:OKHttp3源码解析(第一篇)

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