原始碼分析:Android Okhttp原始碼淺析(一)
Okhttp的呼叫
分析原始碼,我們都需要通過呼叫來檢視原始碼的每一步都做了什麼事情。
看下非同步呼叫
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url("").build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
原始碼分析。
我們首先看下,OkHttpClient初始化做的事情
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.readTimeout = builder.readTimeout;
this.writeTimeout = builder.writeTimeout;
this.pingInterval = builder.pingInterval;
}
...
public Builder() {
dispatcher = new Dispatcher();
...
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0 ;
}
這裡我們看到,Okhttp是通過建造者模式初始化的。做的事情,主要是一些常用的配置。
(初始化排程器,快取策略,連線時間等等)
我們接著看Request的初始化
public final class Request {
final HttpUrl url;
final String method;
final Headers headers;
final RequestBody body;
final Object tag;
Request(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers.build();
this.body = builder.body;
this.tag = builder.tag != null ? builder.tag : this;
}
...
}
我們可以看到,Request裡面,主要是通過建造者模式,配置進行網路請求的url,method,header等等內容。
接著看client.newCall(request)
上面做的事情都是配置網路請求的資訊。下面,這個呼叫會執行什麼呢。
@Override public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
我們發現這句程式碼非常簡單,就做了一件事。把上面我們構建好的Okhttp,Request傳給RealCall。
並初始化它。
最後看下執行call.enqueue(Callback)
我們看下最後是怎麼執行的呢
@Override public void enqueue(Callback responseCallback) {
//檢查是否已經執行了。
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
//把我們需要監聽的返回callback傳給AsyncCall,並初始化
//呼叫我們okhttp建立的dispatcher的enqueue()方法。
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
我們看下AysncCall這個類
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
它的父類
public abstract class NamedRunnable implements Runnable {
@Override public final void run() {
...
execute();
...
}
protected abstract void execute();
}
我們發現AsyncCall是一個執行緒,並且父類實現了run()方法,並重新抽象了一個execute()方法,在run()裡面呼叫。讓AsyncCall來實現這個execute()方法。
如果呼叫這個執行緒的話,AsyncCall的execute()方法就會執行。
再看看 client.dispatcher().enqueue(AsyncCall)
看下這個裡面做了什麼操作。
public final class Dispatcher {
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
/** Ready async calls in the order they'll be run. */
//這個是準備執行,非同步任務的佇列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
//這個是正在執行非同步任務的佇列
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
//這個是正在執行的同步任務的佇列
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
獲取執行緒池
public synchronized ExecutorService executorService() {
if (executorService == null) {
//核心執行緒數為9,最大執行緒數Integer.MAX_VALUE,保留時間60秒
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
...
synchronized void enqueue(AsyncCall call) {
//判斷正在執行非同步任務的佇列數量是不是已經達到最大值了
//如果沒有到最大值,並且host數量小於5。
//我們就把這個執行緒放到正在執行的佇列裡,並執行它
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
//新增
runningAsyncCalls.add(call);
//執行
executorService().execute(call);
} else {
//否則,我們就放到準備執行的非同步任務佇列裡
readyAsyncCalls.add(call);
}
}
}
到這裡,我們發現它確實就是一個排程器。
我們假設可以執行。我們看下AsyncCall的execute()方法,都做了什麼
AsyncCall的execute()方法
@Override protected void execute() {
boolean signalledCallback = false;
try {
注:1
Response response = getResponseWithInterceptorChain();
//如果沒有取消的話,就呼叫callback的onResponse,否則就呼叫onFailure。
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 {
//注:2
client.dispatcher().finished(this);
}
}
}
這裡,我們先不管注:1和注:2。這就不管成功還是失敗,就把資料返回給了我們的callback。
接著,先看下注:2。它是在finally裡面執行的。所以執行完後,不管有沒有異常,這個方法總會執行的,我們先看下這個。
client.dispatcher().finished(this)
/** Used by {@code AsyncCall#run} to signal completion. */
void finished(AsyncCall call) {
//呼叫過載方法,第三個引數為true
finished(runningAsyncCalls, call, true);
}
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
//同步
synchronized (this) {
//這裡把我們執行完的call移除了
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
//呼叫了promoteCalls()方法
if (promoteCalls) promoteCalls();
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
···
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();
//如果執行的佇列Host不大於最大的host。
//把這個準備的任務,從等待佇列移除,放到正在執行的佇列,並立即執行。
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
//直到達到了最大的請求數量,就返回
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
這裡,我們就看完了一個任務完成後,做的事情。
1,移除完成的任務
2,判斷正在執行的佇列,是否還大於最大的請求數。
3,如果大於就返回,如果不大於就從等待的佇列裡面去取任務並執行,直到達到了,最大的請求數。
現在,我們就差分析,是怎麼返回的Response的了。接下來,我們就看下它是怎麼執行的。
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));
//初始化一個RealInterceptorChain跟Request,把攔截器都傳進去
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
//呼叫proceed()方法
return chain.proceed(originalRequest);
}
這裡也非常簡單,把我們自己設定的攔截器和它自身的,都放到集合裡。跟Request一塊傳給RealInterceptorChain。並呼叫proceed()方法。
我們再進去看看proceed犯法
RealInterceptorChain.proceed(originalRequest);
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
Connection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
...
// Call the next interceptor in the chain.
//初始化,角標+1,取出interceptor呼叫intercept方法
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
//並把下一個RealInterceptorChain穿進去,index+1
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;
}
這裡就是建立下一個攔截器。
呼叫當前攔截器的intercept(next)方法,把下一個攔截器傳進去。
- 我們自己的interceptor
- retryAndFollowUpInterceptor
- BridgeInterceptor
- CacheInterceptor
- ConnectInterceptor
- NetworkInterceptors
- 我們自己的networkInterceptors
- CallServerInterceptor
我們看下攔截器是怎麼傳下去的
RetryAndFollowUpInterceptor.java
@Override public Response intercept(Chain chain) throws IOException {
...
response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);
...
}
BridgeInterceptor.java
@Override public Response intercept(Chain chain) throws IOException {
Response networkResponse = chain.proceed(requestBuilder.build());
}
...
都是呼叫下一個構造的chain的proceed方法。
然後,在裡面構造下一個chain,執行intercept方法。
* 攔截器的作用:*
- 對當前的request請求做處理(新增/刪除頭資訊等)。
- 呼叫下一個攔截器。
- 對響應的Response結果,做處理(寫入快取等),並返回給上一個攔截器。
呼叫完之後,響應Response。整個流程完成。
下一次,看下攔截器都做了什麼功能呢。