版本是3.14.9
同步請求
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder().url("http://wwww.baidu.com").build();
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
Log.d(TAG, "Response: " + response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
同步請求分析
- 創建OkHttpClient對象,
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
public OkHttpClient() {
this(new Builder());
}
public static final class Builder {
Dispatcher dispatcher;
public Builder() {
// 創建Dispatcher對象
dispatcher = new Dispatcher();
}
}
}
- 創建Request對象
public final class Request {
public static class Builder {
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
public Builder url(HttpUrl url) {
if (url == null) throw new NullPointerException("url == null");
this.url = url;
return this;
}
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
// build()之後返回Request
return new Request(this);
}
}
}
okHttpClient.newCall(request)
創建RealCall對象
// 創建RealCall對象, RealCall中的內部類AsyncCall其實是Runnable對象
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
RealCall.execute()
執行請求
// RealCall.java
final class RealCall implements Call {
// 執行同步請求
@Override public Response execute() throws IOException {
synchronized (this) {
// executed 每個RealCall只能請求一次網絡
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
...
try {
// 將RealCall加入到同步請求的隊列中
client.dispatcher().executed(this);
// 從攔截鏈獲取響應, 異步最終也會走到這個方法,現在再分析異步.
return getResponseWithInterceptorChain();
} finally {
client.dispatcher().finished(this);
}
}
}
// Dispatcher.java
public final class Dispatcher {
// 準備好,還未請求
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
// 正在運行的請求
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
// 同步請求
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
// 將RealCall對象加入到同步請求隊列中
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
}
異步請求
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder().url("http://wwww.baidu.com").build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: ");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, "Response: " + response.body().string());
}
});
異步請求分析
OkHttpClient
,Request
,RealCall
對象的創建與同步無異,區別在RealCall.execute()
與’RealCall.enqueue()’
final class RealCall implements Call {
@Override public void enqueue(Callback responseCallback) {
...
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
// 類型最終爲Runnable
final class AsyncCall extends NamedRunnable {
void executeOn(ExecutorService executorService) {
assert (!Thread.holdsLock(client.dispatcher()));
boolean success = false;
try {
// 通過線程池執行當前的AsyncCall,也就是Runnable對象中的run()
// NamedRunnable類中的run()方法最終調用execute(),該方法具體由AsyncCall實現.
executorService.execute(this);
success = true;
}
...
}
// run()方法的最終實現
@Override protected void execute() {
boolean signalledCallback = false;
transmitter.timeoutEnter();
try {
// 調用攔截器鏈獲取Response
Response response = getResponseWithInterceptorChain();
signalledCallback = true;
// Callback()中的回調方法
responseCallback.onResponse(RealCall.this, response);
} catch (IOException e) {
...
} catch (Throwable t) {
cancel();
if (!signalledCallback) {
...
canceledException.addSuppressed(t);
// Callback()中的回調方法
responseCallback.onFailure(RealCall.this, canceledException);
}
throw t;
} finally {
client.dispatcher().finished(this);
}
}
}
}
public final class Dispatcher {
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
// 準備好,還未請求
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
// 正在運行的請求
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
// 同步請求
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
// 將RealCall對象加入到同步請求隊列中
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
void enqueue(AsyncCall call) {
// 將AsyncCall對象加入異步請求準備隊列中
readyAsyncCalls.add(call);
...
//
promoteAndExecute();
}
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
// 存儲將要執行的異步請求
List<AsyncCall> executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
// 等待異步請求隊列中遍歷
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
i.remove();
asyncCall.callsPerHost().incrementAndGet();
// 將等待隊列中的AsyncCall 加入到正在異步請求的隊列中
executableCalls.add(asyncCall);
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}
for (int i = 0, size = executableCalls.size(); i < size; i++) {
// 從集合中取出AsyncCall
AsyncCall asyncCall = executableCalls.get(i);
// 調用AsyncCall中的executeOn()方法,executorService()返回一個線程池
asyncCall.executeOn(executorService());
}
return isRunning;
}
// 獲取一個線程池
public synchronized ExecutorService executorService() {
if (executorService == null) {
// 核心池大小爲0,空閒線程最多等待60s收回
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
}
getResponseWithInterceptorChain()
final class RealCall implements Call {
final class AsyncCall extends NamedRunnable {
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
// OkHttpClient中自己自定義的一些Interceptor
interceptors.addAll(client.interceptors());
// 錯誤、重定向攔截器
interceptors.add(new RetryAndFollowUpInterceptor(client));
// 橋接攔截器,橋接應用層與網絡層,添加必要的頭、
interceptors.add(new BridgeInterceptor(client.cookieJar()));
// 緩存處理,Last-Modified、ETag、DiskLruCache等
interceptors.add(new CacheInterceptor(client.internalCache()));
// 連接攔截器
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
// 網絡請求攔截器只對非網頁請求生效
interceptors.addAll(client.networkInterceptors());
}
// 真正訪問服務器的攔截器
interceptors.add(new CallServerInterceptor(forWebSocket));
// 創建RealInterceptorChain對象, 注意此時的index爲0
Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
boolean calledNoMoreExchanges = false;
try {
// 調用RealInterceptorChain.proceed() 接收參數是Request
Response response = chain.proceed(originalRequest);
...
return response;
}
...
}
}
}
RealInterceptorChain.proceed(originalRequest)
public final class RealInterceptorChain implements Interceptor.Chain {
public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
throws IOException {
...
// 注意此時的index爲index+1,回想之前的一步,創建RealInterceptorChain時候, index是爲0.
// 可以看出來這裏用的是責任鏈設計模式.
// 攔截器鏈最後就是一個遞歸調用, 最後調用到 CallServerInterceptor纔開始真正的請求網絡,然後再一步步將請求到的數據從攔截器返回來.
RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
// 上一步中index爲0,那麼這個 Interceptor 類型就是錯誤重定向攔截器
Interceptor interceptor = interceptors.get(index);
// 這裏的next還是RealInterceptorChain對象. 下面看下錯誤重定向請求攔截器
Response response = interceptor.intercept(next);
...
return response;
}
}
RetryAndFollowUpInterceptor.intercept(next)
public final class RetryAndFollowUpInterceptor implements Interceptor {
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RealInterceptorChain realChain = (RealInterceptorChain) chain;
...
try {
// 這樣一個循環最後又回到了RealInterceptorChain中的proceed()方法中了,此時的RealInterceptorChain中屬性index爲1.
// 這樣一個循環就會將所有的 Interceptor都調用到.
response = realChain.proceed(request, transmitter, null);
success = true;
}
...
}
}
總結
OkHttp的底層是通過Java的Socket發送HTTP請求與接受響應的,OkHttp實現了連接池的概念,即對於同一主機的多個請求,其實可以共用一個Socket連接,而不是每次發送完 HTTP請求就關閉底層的Socket,這樣就實現了連接池的概念。而OkHttp對Socket的讀寫操作使用的OkIo庫進行了一 層封裝。