26
2017
09

OKHttp3源码学习(一)

前言:一直就想研究okhttp的源码,以此来提高自己的android水平,最近终于决定着手来研究学习,至于okhttp的优缺点我就不去复制网上别人的东西了,我希望能在我研究学习的过程中亲身感受到那些所谓的特性。

    首先,我们来看下最简单的使用:
    

String url = "https://www.baidu.com";
OkHttpClient client = new OkHttpClient.Builder().build();
Request request = new Request.Builder().url(url).build();
client.newCall(request).enqueue(new Callback() {
     @Override
     public void onFailure(Call call, IOException e) {

     }

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

            }
     });

    这是异步请求的最简单写法,所有参数诸如连接池,超时设置之类的都采用的默认配置,同时默认也是get请求。从这里可以看出一个请求最基本的几个元素就是OkHttpClient、Request 和Response。因此我的思路就是从这三个元素着手一步步往下看。

Request

    打开Request类可以看到,Request是个final类,意味着我们无法继承该类,也就无法改变该类中的方法。至于详细的final关键字的说明,这里不再赘述,之后再去详细研究,为了不让自己忘记,这里记录一下(//TODO:final关键字详解)。
    我们知道,一个http请求请求方法URL协议/方法、请求头、请求正文三部分组成,所以我们可以看到Request的构造方法(如下所示)中有url、method、headers、body。不过传入的参数是Builder,这里涉及到了设计模式中的Builder模式,至于这里为何使用Builder模式,待我详细研究了Builder模式后再作补充(//TODO:Builder模式研究学习)。
    

 private Request(Request.Builder builder) {
        this.url = builder.url;
        this.method = builder.method;
        this.headers = builder.headers.build();
        this.body = builder.body;
        this.tag = builder.tag != null?builder.tag:this;
    }

    除了上述的几个参数,我们可以看到Request类里还定义了另外两个参数,一个是tag,一个是cacheControl,tag我们知道是一个标志,平时我们也经常用到,这里应该是用作对请求的标志,以便做其他关于该请求的操作。cacheControl从名字上来看应该是缓存控制,看了下这个类,确实是一个缓存机制的管理类,由于涉及篇幅过长,也只能放在之后研究了。(//TODO:OKHttp 缓存机制研究学习)。
    同时,我发现cacheControl变量是使用volatile这个关键字来修饰的,又是一个知识盲点=。=(//TODO:关键字volatile详解),经过大致地查阅资料以及看okhttp源码里给出的注释是// Lazily initialized.,我大致明白了,这里暂且引用一下别人博客里的说法(Java中Volatile关键字详解):
    在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此volatile变量是一种比sychronized关键字更轻量级的同步机制。
    当对非 volatile 变量进行读写的时候,每个线程先从内存拷贝变量到CPU缓存中。如果计算机有多个CPU,每个线程可能在不同的CPU上被处理,这意味着每个线程可以拷贝到不同的 CPU cache 中。
  而声明变量是 volatile 的,JVM 保证了每次读变量都从内存中读,跳过 CPU cache 这一步。

    所有的变量都有了之后我们再回过头看我们的request初始化语句:Request request = new Request.Builder().url(url).build();这里实际省略了很多参数的设置,比如请求方法、请求正文、请求头。而这些很显然都在Builder类里有默认的配置。我们先看构造方法:
    

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

        Builder(Request request) {
            this.url = request.url;
            this.method = request.method;
            this.body = request.body;
            this.tag = request.tag;
            this.headers = request.headers.newBuilder();
        }

    第一个我们可以看到默认配置了method为GET,这就能解释了为何默认是get请求。但是到了第二个我有点搞不懂了,首先他是私有的,其次我也没找到哪边有用这个构造函数,希望看到的前辈在留言区进行指导,感激涕零。
    接下来就是各个参数具体配置需要调用的方法的定义了,可以看到url方法有三个,传入的参数分别是HttpUrl、String和URL三种类型的url,细看之下就可以发现最终url是要符合HttpUrl这个类型的,同时将ws和wss替换成了和https,ws是属于长连接的,所以可以理解。(//TODO:OKHttp中的HttpUrl解析)其余方法就没啥要点需要分析了,最终我们通过调用build()方法创建了一个Request对象。
    到这里这篇博客就结束了,主要干了一件事,就是分析创建一个Request对象的具体流程,在此过程中记录了难点与盲点,方便之后继续研究okhttp以及提高Java和android水平。

okhttp源码地址
    

上一篇:大牛建议的Java初学者的学习(1—5年内) 下一篇:关于Toolbar的使用小结