OkHttp( 3.9.0-SNAPSHOT)源码解析

OkHttp源码的samples的简单使用的示例:

public static void main(String... args) throws Exception{

OkHttpClient client=new OkHttpClient();

// Create request for remote resource.

Request request=new Request.Builder()

.url(ENDPOINT)

.build();

// Execute the request and retrieve the response.

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

// Deserialize HTTP response to concrete type.

ResponseBody body=response.body();

Listcontributors=CONTRIBUTORS_JSON_ADAPTER.fromJson(body.source());

body.close();

......

}

静态常量

OkHttpClient开始就定义了两个静态常量,这两个常量是与协议相关分别是DEFAULT_CONNECTION_SPECS和DEFAULT_PROTOCOLS。

静态代码块

接下来看OkHttpClient的static代码块主要就是创建了一个Internal的内部类对象。

接口

OkHttpClient实现了三个接口,分别是Cloneable,Call.Factory,WebSocket.Factory

重点在Call.Factory接口上,Call该接口的实例就是我么去执行请求网络数据的对象,

Call中的主要方法

/** 返回该Call创建的Request请求对象 */

Request request();

/** 同步执行请求网络数据,返回服务端响应结果*/

Response execute()throwsIOException;

/** 异步执行请求网络数据的回调方法*/

void enqueue(Callback responseCallback);

/** 取消网络请求*/

void cancel();

/** 判断网络请求是否被执行了*/

boolean isExecuted();

/** 判断网络请求是否被取消了*/

boolean isCanceled();

/**clone该方法是Cloneable接口中的方法,意义在于创建一个相同的请求对象*/

Call clone();

/**Factory内部接口就是创建Call的工厂接口,该接口定义的方法newCall需要传入Request对象*/

interface Factory{

Call newCall(Request request);

}

成员变量

最重要的就是OkHttpClient,该类的成员变量中6个成员变量进行重点说明的

final Dispatcher dispatcher;

final List interceptors;

final List networkInterceptors;

final EventListener.Factory eventListenerFactory;

final @Nullable Cache cache; 

final @Nullable InternalCache internalCache;

1、同步请求过程解析

Response response=client.newCall(request).execute(); 这句代码执行过程:

(1)client.newCall(request)

第一步:上面提到OkHttpClient的三个接口中有个Factory内部接口(创建Call的工厂接口),而Call对象有个实现类RealCall,其实newCall方法是RealCall执行自己的newRealCall方法创建了一个RealCall实例,该方法三个参数如下:

*@param client OkHttpClient对象

*@param originalRequest 之前传入的那个原始请求对象

*@param forWebSocket 是否是WebSocket

RealCall call=newRealCall(client,originalRequest,forWebSocket);

第二步:上面提到OkHttpClient的6个成员变量中有个EventListener.Factory eventListenerFactory对象(也是个工厂接口,内部定义了一个create方法用于创建EventListener对象),上一步传入了OkHttpClient对象,该对象已经创建完了eventListenerFactory实例,所以拿到该实例传入call对象创建EventListener对象。

抽象类EventListener中有一大堆的网络连接的监听方法

call.eventListener=client.eventListenerFactory().create(call);

最后返回当前的Call对象

(2)call.execute()

@Override

publicResponse execute()throwsIOException{

    synchronized(this) {

    if(executed)throw newIllegalStateException("Already Executed");

     executed=true;

}

   captureCallStackTrace();

 try{

       client.dispatcher().executed(this);

      Response result=getResponseWithInterceptorChain();

      if(result==null)throw newIOException("Canceled");

       returnresult;

      }finally{

       client.dispatcher().finished(this);

   }

}

2.1)call中的execute方法中的client.dispatcher().executed(this);

由于execute是同步执行网络请求所以要用关键字synchronized,

synchronized(this) {

    if(executed)throw newIllegalStateException("Already Executed");

   executed=true;

}

之后再执行captureCallStackTrace()方法,放入堆栈进行追踪捕捉。

client.dispatcher()是获得上面OkHttpClient的成员变量Dispatcher dispatcher,注意啦Dispatcher中的方法基本都是同步,用的Synchronized修饰的方法。为了分析清楚这里插一段Dispatcher的说明。

Dispatcher中维护着执行发送请求的线程池,所有的请求都是放在请求队列中的总共有三个队列readyAsyncCalls(准备的异步请求队列),runningAsyncCalls(正在在执行的异步请求还包括被中断的),runningSyncCalls(正在在执行的异步请求还包括被中断的)

private final Deque<AsyncCall> readyAsyncCalls=newArrayDeque<>();

private final Deque<AsyncCall> runningAsyncCalls=newArrayDeque<>();

private final Deque<RealCall> runningSyncCalls=newArrayDeque<>();

RealCall和AsyncCall的关系通过Dispatcher类的导入代码可以看出

import okhttp3.RealCall.AsyncCall;   // AsyncCall其实就是RealCall的内部类

具体实现如下:

final class AsyncCall extends NamedRunnable{

private final Callback responseCallback;

// 构造时需要传入一个Callback接口,也就是返回给我们成功失败的回调方法

AsyncCall(Callback responseCallback) {  

   super("OkHttp %s",redactedUrl());

   this.responseCallback=responseCallback;

}

String host() {

    return originalRequest.url().host();

}

Request request() {

     return originalRequest;

}

RealCall  get() {

    return RealCall.this;

}

@Override

protected void execute() {

          boolean signalledCallback=false;

   try{

          Response response=getResponseWithInterceptorChain();

          if(retryAndFollowUpInterceptor.isCanceled()) {

          signalledCallback=true;

          responseCallback.onFailure(RealCall.this,newIOException("Canceled"));

      }else{

          signalledCallback=true;

          responseCallback.onResponse(RealCall.this,response);

     }

  }catch(IOException e) {

       if(signalledCallback) {

       // Do not signal the callback twice!

        Platform.get().log(INFO,"Callback failure for "+toLoggableString(),e);

    }else{

       responseCallback.onFailure(RealCall.this,e);

   }

      }finally{

        client.dispatcher().finished(this);

      }

   }

}

dispatcher中erexecuted方法的具体实现

//  加入同步执行队列

synchronized void executed(RealCall call) {

  runningSyncCalls.add(call);

}

2.2)Response result=getResponseWithInterceptorChain();

下面回过头去看RealCall的execute方法中client.dispatcher().executed(this);执行结束后的代码Response result=getResponseWithInterceptorChain();

为了分析清楚这里插一段Interceptor的说明

Response getResponseWithInterceptorChain()throwsIOException{

//创建一个存放拦截器的集合,最后传入 newRealInterceptorChain对象中

   List<Intercepter>  interceptors=newArrayList<>();

// client.interceptors() (自定义的拦截器, 在call api的前的拦截) - > //retryAndFollowUpInterceptor (实现请求重试)

   interceptors.addAll(client.interceptors());

// 重定向拦截器

   interceptors.add(retryAndFollowUpInterceptor);

// 桥接拦截器(处理header 、cookie 等)

   interceptors.add(newBridgeInterceptor(client.cookieJar()));

// 缓存拦截器(处理 cache)

   interceptors.add(newCacheInterceptor(client.internalCache()));

// 连接拦截器(负责建立连接)

   interceptors.add(newConnectInterceptor(client));

   if(!forWebSocket) {

// 自定义网络拦截器(此时已建立连接)

     interceptors.addAll(client.networkInterceptors());

  }

// 服务请求拦截器(发起请求、接收响应)

   interceptors.add(newCallServerInterceptor(forWebSocket));

Interceptor.Chain chain = new RealInterceptorChain(interceptors,null,null,null,0,originalRequest,this,eventListener);   return chain.proceed(originalRequest);

上面的RealInterceptorChain方法具体实现。在RealCall里的getResponseWithInterceptorChain方法里,创建了一个RealInterceptorChain对象,调用proceed(),在interceptor的intercept()方法里又调用proceed(),明显形成了一个递归,像链表一下一个一个递归传递并且做相应的拦截处理。

RealInterceptorChain next=newRealInterceptorChain(interceptors,streamAllocation,httpCodec,

connection,index+1,request,call,eventListener);

Interceptor interceptor=interceptors.get(index);

Response response=interceptor.intercept(next);

最后一个拦截器返回处理的Response,也就是服务器端返回的结果,并且在代码中加了许多的判断如:this.httpCodec!=null 意思就是还没有拦截链执行完。interceptor必须执行一次proceed()方法,否则会抛异常。

RealInterceptorChain + Interceptor实现了装饰器模式,实现了请求/响应的串式或流式处理。只不过内层装饰器不是外层装饰器的成员变量,而是接口方法中创建的临时变量。

在ConnectInterceptor之后的拦截器必须满足:request的url要一致,interceptor必须执行一次proceed()。这样子做是为了保证递推的正常运作。而对与client.interceptors是在ConnectInterceptor之前的拦截器,可以不用必须执行一次proceed()。可以实现直接返回虚拟的response用于是测试等功能。

这几个Interceptor的职责:

RetryAndFollowUpInterceptor --->创建StreamAllocation对象,处理http的redirect,出错重试。对后续Interceptor的执行的影响:修改request及StreamAllocation。

BridgeInterceptor-------------->补全缺失的一些http header。对后续Interceptor的执行的影响:修改request。

CacheInterceptor-------------->处理http缓存。对后续Interceptor的执行的影响:若缓存中有所需请求的响应,则后续Interceptor不再执行。

ConnectInterceptor------------>借助于前面分配的StreamAllocation对象建立与服务器之间的连接,并选定交互所用的协议是HTTP 1.1还是HTTP 2。对后续Interceptor的执行的影响:创建了httpStream和connection。

CallServerInterceptor----------->处理IO,与服务器进行数据交换。对后续Interceptor的执行的影响:为Interceptor链中的最后一个Interceptor,没有后续Interceptor

2.3client.dispatcher().finished(this); 

dispatcher中finish方法的具体实现(注意第三个参数的差别)

/** Used by {@codeCall #execute} to signal completion.同步方法 */

void finished(RealCall call) {

    finished(runningSyncCalls,call,false);

}

/** Used by {@codeAsyncCall#run} to signal completion. 异步方法*/

void  finished(AsyncCall call) {

    finished(runningAsyncCalls,call,true);

}

上面的finished(runningAsyncCalls,call,true);方法实现如下:

private void finished(Dequecalls,T call,boolean promoteCalls) {

   int  runningCallsCount;

   Runnable idleCallback;

  synchronized(this) {

    if (!calls.remove(call) ) throw newAssertionError("Call wasn't in-flight!");

      if(promoteCalls)  promoteCalls(); // 异步Call数量多时需要维护队列,而不是立即执.行,所以要加入到runningAsyncCalls中

       runningCallsCount = runningCallsCount();

       idleCallback = this.idleCallback;

  }

  if(runningCallsCount==0&&idleCallback!=null) {

    idleCallback.run();

  }

}

上面promoteCalls方法的具体实现如下:

private int maxRequests=64;

private int maxRequestsPerHost=5;

private void promoteCalls() {

    if(runningAsyncCalls.size()>=maxRequests) return;// 已经达到最大容器.

     if ( readyAsyncCalls.isEmpty() ) return; // 队列为空

        for(Iterator i=readyAsyncCalls.iterator();i.hasNext();) {  // 遍历取出

          AsyncCall call=i.next();  

 // 当正在执行的任务总数及相同host下的任务数小于最大值时,直接执行当前请求,而任务数超过限定时,将其加入等待队列。

          if ( runningCallsForHost(call) < maxRequestsPerHost ){ 

             i.remove();

            runningAsyncCalls.add(call);

            executorService().execute(call);

          }

     }

    if ( runningAsyncCalls.size()>=maxRequests ) return;// Reached max capacity.

 }

}

还可以通setMaxRequests()设置同时允许执行的最大请求数,以及setMaxRequestsPerHost()设置相同host下最多运行的请求数。从源码中看出OkHttpClient用了许多的Budiler设计模式,几个重要的类Response、Request、OkHttpClient。

2、异步请求过程解析

RealCall的enqueue方法,其中遇到的大部分方法在同步请求中有分析就不赘述了。主要讲一下异步网络请求的流程

@Override

public voidenqueue(Callback responseCallback) {

  synchronized(this) {

      if(executed)throw newIllegalStateException("Already Executed");  

     executed=true;

 }

    captureCallStackTrace();

    client.dispatcher().enqueue(newAsyncCall(responseCallback));

}

上面client.dispatcher().enqueue(newAsyncCall(responseCallback));中Dispatcher的enqueue方法

synchronized void enqueue(AsyncCall call) {

// 如果正在执行异步请求的队列没有超过最大请求数量,并且有没有超过每个主机允许的最大访问量

// 就将请求加入到正在执行异步请求的队列中,否则就加入到准备异步请求的队列中去

  if(runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost

     runningAsyncCalls.add(call); 

     executorService().execute(call);

   }else{

      readyAsyncCalls.add(call);

   }


异步请求返回是通过接口回调的具体实现如下:

final classAsyncCallextendsNamedRunnable{

private finalCallback responseCallback;

AsyncCall(Callback responseCallback) {

    super("OkHttp %s",redactedUrl());

    this.responseCallback=responseCallback;

}

String host() {

    return  originalRequest.url().host();

}

Request request() {

  return originalRequest;

}

RealCall get() {

    return  RealCall.this;

}

@Override

protected voidexecute() {

   booleansignalledCallback=false;

try{

    Response response=getResponseWithInterceptorChain();

    if (retryAndFollowUpInterceptor.isCanceled() ) {

       signalledCallback=true;

       responseCallback.onFailure(RealCall.this,newIOException("Canceled"));

    }else{

      signalledCallback=true;

      responseCallback.onResponse(RealCall.this,response);

}

  }catch(IOException e) {

        if(signalledCallback) {

          // Do not signal the callback twice!

          Platform.get().log(INFO,"Callback failure for "+toLoggableString(),e);

      }else{

          responseCallback.onFailure(RealCall.this,e);

       }

   }finally{

     client.dispatcher().finished(this);

   }

 }

}

推荐阅读更多精彩内容

  • 前言 用了那么久的OkHttp,解决了不少的联网问题。对于热门的好轮子,总不能一直停留在会用这个层面上吧,是时候动...
    Goo_Yao阅读 1,225评论 3 9
  • 这篇文章主要讲 Android 网络请求时所使用到的各个请求库的关系,以及 OkHttp3 的介绍。(如理解有误,...
    小庄bb阅读 540评论 0 4
  • 这段时间老李的新公司要更换网络层,知道现在主流网络层的模式是RxJava+Retrofit+OKHttp,所以老李...
    隔壁老李头阅读 22,573评论 55 366
  • OkHttp作为时下最受欢迎的网络请求框架之一,它有着自己的优点: 使用了众多的设计模式(如:Builder模式、...
    allenjones_23阅读 48评论 1 1
  • OkHttp源码分析-同步篇 很早就想拿okhttp开刀了,这次就记一次使用OKhttp的网络请求。首先需要说明的...
    埃赛尔阅读 597评论 1 2