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