為什麼不用最新版本 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:
-
兩種構造器:
第一種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);
}
-
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);
}
-
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對象。具體的我們下節分析。。