在使用過okhttp3之後,必然的一步當是對源碼的研究 這樣可以對其優劣和功能封裝有一個全面詳盡的了解
ok 下面粘貼okhttp3的核心代碼(url暫時随意定義)
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
.url("www.baidu.com")
.build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
下面進入正題,來對源碼進行分析
1.okhttp執行個體 和Request執行個體和配置
相當于初始化執行個體 比較簡單
首先來看okhttp初始化執行個體
1.1 //OkHttpClient okHttpClient = new OkHttpClient();
public OkHttpClient() {
this(new Builder());
}
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
connectTimeout = _000;
readTimeout = _000;
writeTimeout = _000;
pingInterval = ;
}
其實就是初始化對象 和屬性的相關配置過程
1.2Requst的初始化
Request request = new Request.Builder()
.url("www.baidu.com")
.build();
下面來看其源碼:
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
public Builder url(String url) {
if (url == null) throw new NullPointerException("url == null");
// Silently replace web socket URLs with HTTP URLs.
if (url.regionMatches(true, , "ws:", , )) {
url = "http:" + url.substring();
} else if (url.regionMatches(true, , "wss:", , )) {
url = "https:" + url.substring();
}
HttpUrl parsed = HttpUrl.parse(url);
if (parsed == null) throw new IllegalArgumentException("unexpected url: " + url);
return url(parsed);
}
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);
}
到這裡準備工作就完成了
下面來從請求開始詳細看源碼(以上比較簡單 沒有什麼可以講的)
2.請求處理
//Call call = okHttpClient.newCall(request);
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// Safely publish the Call instance to the EventListener.
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
okhttp3建立請求的主體call對象 其實傳回的是一個realCall的執行個體化對象,并完成一系列的相關初始化配置;
下面來看請求
//call.enqueue
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
由以上代碼 可以看出來 okhttp的請求是由dispatcher來完成的;而dispatcher又是什麼呢 ?
其實是一個網絡的任務排程器;
那麼下面來看下排程器的實作.
3.dispatcher任務排程
//最大請求數
private int maxRequests = ;
//最大主機請求數
private int maxRequestsPerHost = ;
private @Nullable Runnable idleCallback;
//消費者線程池
private @Nullable ExecutorService executorService;
//将要運作的異步請求隊列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
//正在運作的異步請求隊列
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
//正在運作的同步請求隊列
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
public Dispatcher() {
}
Dispatcher主要用于控制并發 并且維護了一部分變量
在請求之前dispatcher會自己建立線程池
當然也可以有程式員自己來建立線程池
ok~初步了解排程器之後來看異步請求的源碼
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
在排程器的enqueue中會先判斷目前最大請求數和目前最大主機請求數 如果不超過預設的最大值 則吧請求加入到正在運作的請求隊列—->runningAsyncCalls;
否則會加入到将要運作的請求隊列中進行等待—->readyAsyncCalls
然後 executorService().execute(call);開始運作傳入的線程 即傳入的AsyncCall;而AsyncCall作為RealCall的内部實作類 會走execute;
ok下面來看AsyncCall–>execute ,在這裡 開始進行網絡請求:
@Override protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("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 {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}
在上面代碼中不難看出走了一系列方法 來進行網絡請求 為了友善讀者了解 先來看finally下的方法 (這個方法必然會走到的):
void finished(AsyncCall call) {
finished(runningAsyncCalls, call, true);
}
//finished
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
if (promoteCalls) promoteCalls();
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == && idleCallback != null) {
idleCallback.run();
}
}
//####promoteCalls()
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
直接提取關鍵代碼:
finished—->if (promoteCalls) promoteCalls(); 當請求完之後 promoteCalls為true 則會走promoteCalls() ;從上面代碼中可圖看出來promoteCalls()中用疊代器周遊readyAsyncCalls 然後加入到runningAsyncCalls
其實就是在請求完成後 來請求緩存池中的線程
那麼繼續回頭看AsyncCall–>execute中的邏輯,在這之前先簡單介紹一下攔截器 okhttp中請求有用到攔截器
4.攔截器Interceptors
攔截器主要是用來監聽網絡的請求和響應 攔截器的添加可以添加,移除或者轉換請求頭;其實簡單來說就是對網絡請求和響應的一個包裝吧,有興趣可以自己研究一下 這裡簡單介紹一下友善接下來的講解;
繼續回到代碼:AsyncCall–>execute:
@Override protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("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 {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
上面代碼中關鍵的請求代碼是:
Response response = 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, ,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
在上面代碼中:
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, ,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
其實是初始化了攔截器 傳參為讀取/請求逾時等….
實際請求的代碼是:chain.proceed(originalRequest);
@Override public Response proceed(Request request) throws IOException {
// If there's another interceptor in the chain, call that.
if (index < client.interceptors().size()) {
Interceptor.Chain chain = new ApplicationInterceptorChain(index + , request, forWebSocket);
//從攔截器清單取出攔截器
Interceptor interceptor = client.interceptors().get(index);
Response interceptedResponse = interceptor.intercept(chain);
if (interceptedResponse == null) {
throw new NullPointerException("application interceptor " + interceptor
+ " returned null");
}
return interceptedResponse;
}
// No more interceptors. Do HTTP.
return getResponse(request, forWebSocket);
}
在攔截器攔截過程中,當存在多個攔截器,需要攔截等待,即第一個請求完下一個請求;其中攔截的代碼會在上面代碼中:
Interceptor interceptor = client.interceptors().get(index);
Response interceptedResponse = interceptor.intercept(chain);
而真正請求的代碼是//getResponse(request, forWebSocket);
那麼接着來看它的源碼:
Response getResponse(Request request, boolean forWebSocket) throws IOException {
//請求成功的核心源碼
engine = new HttpEngine(client, request, false, false, forWebSocket, null, null, null);
int followUpCount = ;
while (true) {
if (canceled) {
engine.releaseStreamAllocation();
throw new IOException("Canceled");
}
boolean releaseConnection = true;
try {
engine.sendRequest();
engine.readResponse();
releaseConnection = false;
} catch (RequestException e) {
// The attempt to interpret the request failed. Give up.
throw e.getCause();
} catch (RouteException e) {
...
}
//請求失敗的核心源碼
boolean releaseConnection = true;
try {
engine.sendRequest();
engine.readResponse();
releaseConnection = false;
} catch (RequestException e) {
// The attempt to interpret the request failed. Give up.
throw e.getCause();
} catch (RouteException e) {
// The attempt to connect via a route failed. The request will not have been sent.
HttpEngine retryEngine = engine.recover(e.getLastConnectException(), null);
if (retryEngine != null) {
releaseConnection = false;
engine = retryEngine;
continue;
}
// Give up; recovery is not possible.
throw e.getLastConnectException();
} catch (IOException e) {
// An attempt to communicate with a server failed. The request may have been sent.
HttpEngine retryEngine = engine.recover(e, null);
if (retryEngine != null) {
releaseConnection = false;
engine = retryEngine;
continue;
}
// Give up; recovery is not possible.
throw e;
} finally {
// We're throwing an unchecked exception. Release any resources.
if (releaseConnection) {
StreamAllocation streamAllocation = engine.close();
streamAllocation.release();
}
}
.....
engine = new HttpEngine(client, request, false, false, forWebSocket, streamAllocation, null,
response);
}
}
到這裡okhttp3的源碼就解析完畢了 感謝支援 希望可以幫到你們~