Okhttp3原碼解析(一)
阿新 • • 發佈:2019-02-14
首先看一下Okhttp3是怎麼進行請求的
//建立OkHttpClient物件
OkHttpClient client = new OkHttpClient.Builder().readTimeout(5, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS)
.connectTimeout(5, TimeUnit.SECONDS).build();
Request request = new Request.Builder().url("www.baidu.com").get().build();//建立Request物件
Call call = client.newCall(request);//將Request封裝成Call 再用Call進行同步或者非同步請求
同步請求:
//同步 :開始請求後就會進入阻塞狀態,直接接到響應
try {
Response response = call.execute();//響應報文的資訊,比如響應頭,體...
} catch (IOException e) {
e.printStackTrace();
}
非同步請求:
//非同步 :不會阻塞當前執行緒 call.enqueue(new Callback() { @Override public void onFailure(@NonNull Call call, @NonNull IOException e) { } @Override public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { } });
以上就是Okhttp的用法,接下來我們來分析一下請求裡面做了什麼操作
先看一下client.newCall(request)這個方法
@Override public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
其實是建立了RealCall類,再跟進new RealCall裡面看下
RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) { //將client和之前建立的request在這裡面進行了賦值,並且建立了一個攔截器RetryAndFollowUpInterceptor(也叫重定向攔截器,後面會再進行分析) final EventListener.Factory eventListenerFactory = client.eventListenerFactory(); this.client = client; this.originalRequest = originalRequest; this.forWebSocket = forWebSocket; this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket); // TODO(jwilson): this is unsafe publication and not threadsafe. this.eventListener = eventListenerFactory.create(this); }
再進一步看看call.execute()裡面是怎麼操作的(其實就是在RealCall裡面具體實現)看如下程式碼
@Override public Response execute() throws IOException {
synchronized (this) {
//這個程式碼就是讓同一個請進只能進行一次操作
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
try {
client.dispatcher().executed(this);//用dispatcher(排程器)分配執行的任務
Response result = getResponseWithInterceptorChain();//獲取響應報文和一些攔截器操作,以後會重點介紹
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
再看看Dispatch的executed方法
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>(); 通過dispahch將call請求新增到了同步請求佇列裡面,很簡單
//dispatch的executed方法
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
再看一下非同步的方法
call.enqueue(CallBack)
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
看看dispatcher的enqueque,跟同步就大不一樣,看以下幾個方法
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();//正在執行的非同步請求佇列 private int maxRequests = 64;//最大的請求佇列 private int maxRequestsPerHost = 5;//最大請求主機數 private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();//非同步快取佇列
synchronized void enqueue(AsyncCall call) {
//如果正在執行的非同步請求佇列小於最大的請求佇列 及 最大的請求主機數小於設定值時 則將任務新增到正在執行的非同步佇列中然後執行
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);//建立執行緒池並且執行該任務
} else {//同理將其新增到快取佇列中
readyAsyncCalls.add(call);
}
}
public synchronized ExecutorService executorService() {//建立執行緒池
if (executorService == null) {
//0:當核心執行緒數為0時,一段時間後會將裡面的所有執行緒給清掉;Integer.MAX_VALUE最大的執行緒數其實在okhttp3裡面不會超過64; 60:大於核心執行緒數時,每個執行緒最長的存活時間60S
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false
}
return executorService;
}
非同步方法執行任務最終也會呼叫到getRequestWithInterseptorChain方法中,我們在呼叫非同步請求時會將Callback封裝成AsynCall,其實AsynCall繼承NamedRunnable最終繼承Runnable 當執行請求任務時就會呼叫到AsynCall的execute()方法,其實當執行緒池執行佇列任務裡就會執行asynCall的run方法 以下是程式碼AsynCall的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 {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);//最終都會走到這,將任務結束掉
}
}
void finished(AsyncCall call) {//非同步結束任務的程式碼
finished(runningAsyncCalls, call, true);
}
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!");//先將任務remove掉
if (promoteCalls) promoteCalls();//非同步promoteCalls傳過來的是true,如果會走promoteCalls()方法,就是對任務進行重新排列
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
//將非同步正在執行的任務佇列和快取佇列任務進行重新排列
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // 大於64return
if (readyAsyncCalls.isEmpty()) return; //快取佇列沒有任務,return
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();//取到第一個快取佇列裡的任務
if (runningCallsForHost(call) < maxRequestsPerHost) {//判斷請求主機數是否大於5
i.remove();//將任務從快取佇列中移除
runningAsyncCalls.add(call);//再新增到非同步執行佇列中
executorService().execute(call);//最後線上程池中執行該任務
}
if (runningAsyncCalls.size() >= maxRequests) return; // 正在執行的佇列大小小>=64 結束迴圈
}
}
所以非同步快取佇列裡的任務是在promoteCalls方法中執行的.
Okhttp3網路請求簡單的分析到這也就結束了,有時間再對裡面再具體的細節進行分析