天天看點

Android基于Okhttp 3.5對Okhttp源碼解析一

為什麼不用最新版本 4.9呢?因為kotlin版本的不太好看。

基于Okhttp 3.5版本解析

Exec Code:

同步:

OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().build();
Call call = client.newCall(request);
call.execute();

           

異步:

enquene code:
OkhttpClient client = new OkHttpClient()
Request request = new Request.Builder().build();
Call call = client.newCall(request);
call.enquene();
           

Analyse:

  1. 兩種構造器:

    第一種New Okhttpclient();

    這種會設定根據預設的Builder進行設定,主要包含dispatcher排程器,protocolsHttp協定版本,connectionspec包括針對TLS和普通Http的連接配接,eventListenerFactory這是Call的狀态監聽器,Connectionpool連接配接池,hostnamevertify主機驗證等。

    實際上調用的是this(new Builder());

    第二種New OkhttpClient().newBuilder().……build();這種就設定了上面的一些參數。

final Dispatcher dispatcher;
final Proxy proxy;
final List<Protocol> protocols;
final List<ConnectionSpec> connectionSpecs;
final List<Interceptor> interceptors;
final List<Interceptor> networkInterceptors;
final ProxySelector proxySelector;
final CookieJar cookieJar;
final Cache cache;
final InternalCache internalCache;
final SocketFactory socketFactory;
final SSLSocketFactory sslSocketFactory;
final CertificateChainCleaner certificateChainCleaner;
final HostnameVerifier hostnameVerifier;
final CertificatePinner certificatePinner;
final Authenticator proxyAuthenticator;
final Authenticator authenticator;
final ConnectionPool connectionPool;
final Dns dns;
final boolean followSslRedirects;
final boolean followRedirects;
final boolean retryOnConnectionFailure;
final int connectTimeout;
final int readTimeout;
final int writeTimeout;
final int pingInterval;

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

OkHttpClient(Builder builder) {
  this.dispatcher = builder.dispatcher;
  this.proxy = builder.proxy;
  this.protocols = builder.protocols;
  this.connectionSpecs = builder.connectionSpecs;
  this.interceptors = Util.immutableList(builder.interceptors);
  this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
  this.proxySelector = builder.proxySelector;
  this.cookieJar = builder.cookieJar;
  this.cache = builder.cache;
  this.internalCache = builder.internalCache;
  this.socketFactory = builder.socketFactory;

  boolean isTLS = false;
  for (ConnectionSpec spec : connectionSpecs) {
    isTLS = isTLS || spec.isTls();
  }

  if (builder.sslSocketFactory != null || !isTLS) {
    this.sslSocketFactory = builder.sslSocketFactory;
    this.certificateChainCleaner = builder.certificateChainCleaner;
  } else {
    X509TrustManager trustManager = systemDefaultTrustManager();
    this.sslSocketFactory = systemDefaultSslSocketFactory(trustManager);
    this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
  }

  this.hostnameVerifier = builder.hostnameVerifier;
  this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
      certificateChainCleaner);
  this.proxyAuthenticator = builder.proxyAuthenticator;
  this.authenticator = builder.authenticator;
  this.connectionPool = builder.connectionPool;
  this.dns = builder.dns;
  this.followSslRedirects = builder.followSslRedirects;
  this.followRedirects = builder.followRedirects;
  this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
  this.connectTimeout = builder.connectTimeout;
  this.readTimeout = builder.readTimeout;
  this.writeTimeout = builder.writeTimeout;
  this.pingInterval = builder.pingInterval;
}
           

最後執行的build():

public OkHttpClient build() {
  return new OkHttpClient(this);
}
           
  1. Request的分析

    New Request.Builder():

    2.1:Request為final類,無法被繼承,不能被覆寫,執行速度比一般類更快。

    2.2:Buidler()的時候設定了預設的請求方式和請求頭,預設的請求方式為GET,請求頭也是final類,builder模式,内部維護着一個初始大小為20的ArrayList。

    這是Requeust類(截取部分):

public final class Request {
  final HttpUrl url;
  final String method;
  final Headers headers;
  final RequestBody body;
  final Object tag;
           

這是request的Builder

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

這是Header的Builder

public static final class Builder {
  final List<String> namesAndValues = new ArrayList<>(20);
           

2.3 build()方法

可見,request建構的時候必須要設定url,否則會抛出異常,然後把參數設定自身并傳回。

public Request build() {
  if (url == null) throw new IllegalStateException("url == null");
  return new Request(this);
}
           
  1. Call

    3.1 看看client.newCall,就是Okhttp的newCall,傳回的是RealCall

@Override public Call newCall(Request request) {
  return new RealCall(this, request, false /* for web socket */);
}
           

3.2 RealCall的構造函數

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

上面可以看出Okhttp支援websocket但是預設是false不支援,那如需websocket該怎樣使用呢,簡單說一下

第一步:繼承Okhttp的抽象類websocketListener,重寫onfail ,onclose,onOpen等方法

第二步:建構OkHttpClient和Request對象

第三部:調用newWebSocket建立連接配接

第四部:調用shutdown關閉

EchoWebSocketListener listener = new EchoWebSocketListener();
    Request request = new Request.Builder()
            .url("ws://echo.websocket.org")
            .build();
    OkHttpClient client = new OkHttpClient();
    client.newWebSocket(request, listener);
 
client.dispatcher().executorService().shutdown();
           

構造函數設定了okhttpclient對象和請求資訊request的封裝以及是否支援websocket,然後建構了一個Retryandfollowupinterceptor

3.3 Retryandfollowupinterceptor

public RetryAndFollowUpInterceptor(OkHttpClient client, boolean forWebSocket) {
  this.client = client;
  this.forWebSocket = forWebSocket;
}
           

裡面隻是将okhttpclient和是否支援websocket傳了進去。

3.4然後執行同步或者異步請求

4.分析同步請求

實際上是調用realcall的execute方法

@Override public Response execute() throws IOException {
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  captureCallStackTrace();
  try {
    client.dispatcher().executed(this);
    Response result = getResponseWithInterceptorChain();
    if (result == null) throw new IOException("Canceled");
    return result;
  } finally {
    client.dispatcher().finished(this);
  }
}
           

4.1 先用同步鎖鎖住目前類,realcall内部維護者一個私有的boolean executed對象,執行過抛出異常若沒有接着往下走,并且将該變量置為true。

4.2調用captureCallStackTrace():列印錯誤資訊

4.3 client.dispatcher().executed(this)

4.3.1 client.dispatcher:其實是在 new okhttpClient的時候設定的dispatcher分發器

4.3.2 execute方法:注意是關鍵字同步鎖方法

synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
           

runningSyncCalls其實是一個隊列

private final Deque runningSyncCalls = new ArrayDeque<>();

Deque是一個能夠快速通路任何一個元素和高效删除插入的一個雙向隊列。

将需要執行的同步call添加進來。

如果空閑的話立即執行。

4.3.3 然後執行getresponsewithIntercepterchain方法

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);
 return chain.proceed(originalRequest);
}
           

4.3.4 先看interceptor 這是一個接口

public interface Interceptor {
  Response intercept(Chain chain) throws IOException;

  interface Chain {
    Request request();

    Response proceed(Request request) throws IOException;

    Connection connection();
  }
}
           

4.3.5 集合首先添加okhttpclient裡自定義的intercepter,然後

添加realcall構造函數生成的retryandfollowupinterceptor,然後bridgeinterceptor,cacheinterceptor,connectInterceptor,如果不是websocket則添加networkinterceptor,接着CallserverIntercaptor,然後構造RealInterceptorChain,将添加了所有interceptor的集合參數傳了進去,再傳回chain.proceed。

4.3.6 注意到interceptors隻是一個添加攔截器的集合,真正的處理在RealInterceptorChain的proceed方法,先看下RealinterceptorChanin的構造方法

public final class RealInterceptorChain implements Interceptor.Chain {
  private final List<Interceptor> interceptors;
  private final StreamAllocation streamAllocation;
  private final HttpCodec httpCodec;
  private final Connection connection;
  private final int index;
  private final Request request;
  private int calls;

  public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation,
      HttpCodec httpCodec, Connection connection, int index, Request request) {
    this.interceptors = interceptors;
    this.connection = connection;
    this.streamAllocation = streamAllocation;
    this.httpCodec = httpCodec;
    this.index = index;
    this.request = request;
  }
           

和Call類似,Call是一個接口,RealCall是一個實作類,Chain也是一個接口,Realinterceptor就是其實作類。同樣的Interceptor也是一個接口。

public interface Interceptor {
  Response intercept(Chain chain) throws IOException;

  interface Chain {
    Request request();

    Response proceed(Request request) throws IOException;

    Connection connection();
  }
}
           

chain即為鍊子,将包含所有攔截器的集合裡的攔截器依次取對外連結式執行。構造方法裡主要知道interceptors和request即可。

4.3.7 然後看最終的proceed方法

@Override public Response proceed(Request request) throws IOException {
  return proceed(request, streamAllocation, httpCodec, connection);
}
           

這裡proceed調用的是由構造函數傳過來的幾個參數,再看真正的執行

public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
    Connection connection) throws IOException {
  if (index >= interceptors.size()) throw new AssertionError();

  calls++;

  // If we already have a stream, confirm that the incoming request will use it.
  if (this.httpCodec != null && !sameConnection(request.url())) {
    throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
        + " must retain the same host and port");
  }

  // If we already have a stream, confirm that this is the only call to chain.proceed().
  if (this.httpCodec != null && calls > 1) {
    throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
        + " must call proceed() exactly once");
  }

  // Call the next interceptor in the chain.
  RealInterceptorChain next = new RealInterceptorChain(
      interceptors, streamAllocation, httpCodec, connection, index + 1, request);
  Interceptor interceptor = interceptors.get(index);
  Response response = interceptor.intercept(next);

  // Confirm that the next interceptor made its required call to chain.proceed().
  if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
    throw new IllegalStateException("network interceptor " + interceptor
        + " must call proceed() exactly once");
  }

  // Confirm that the intercepted response isn't null.
  if (response == null) {
    throw new NullPointerException("interceptor " + interceptor + " returned null");
  }

  return response;
}
           

第一行我們看到如果index > interceptors.size()即抛出AssertionError,斷言錯誤異常。然後繼續建構RealInterceptorChain對象傳入必要的參數,讓實作了Interceptor接口的各個攔截器去執行對于的intercept方法,最終得到response對象。具體的我們下節分析。。

繼續閱讀