如果我們想請求數據,使用少量的代碼就可以實現:
OkHttpClient client = new OkHttpClient();
String url = "https://www.baidu.com/";
Request request = new Request().Builder()
.url(url)
.get()
.build();
Call call = client.newCall(request);
request.enqueue(new CallBack(){
@Override
public void onResponse(Call call,Response response) throws IOException{
}
@Override
public void onFailure(Call call,IOException e){
}
})
OkHttpClient類
創建OkHttpClient類的兩種方式:
- 直接創建對象 new OkHttpClient()
- new OkHttpClient.Builder().build()
OkHttpClient對象源碼:
public OkHttpClient() {
this(new Builder());
}
OkHttpClient(Builder builder) {
//調度器,用于控制并發的請求。內部保存同步和異步請求的call,并使用線程池處理異步請求。
this.dispatcher = builder.dispatcher;
this.proxy = builder.proxy;//代理設置
this.protocols = builder.protocols;//默認支持http協議版本
this.connectionSpecs = builder.connectionSpecs;//okhttp連接 connection配置
this.interceptors = Util.immutableList(builder.interceptors);
this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
this.eventListenerFactory = builder.eventListenerFactory;//一個Call的狀態監聽器
this.proxySelector = builder.proxySelector;//使用默認的代理選擇器
this.cookieJar = builder.cookieJar;//默認是沒有cookie的
this.cache = builder.cache;//緩存
this.internalCache = builder.internalCache;
this.socketFactory = builder.socketFactory;//使用默認的Scoket工廠產生Socket
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 = Util.platformTrustManager();
this.sslSocketFactory = newSslSocketFactory(trustManager);
this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
}
if (sslSocketFactory != null) {
Platform.get().configureSslSocketFactory(sslSocketFactory);
}
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;//域名解析系統 domain name->ip address
this.followSslRedirects = builder.followSslRedirects;
this.followRedirects = builder.followRedirects;
this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
this.callTimeout = builder.callTimeout;
this.connectTimeout = builder.connectTimeout;
this.readTimeout = builder.readTimeout;
this.writeTimeout = builder.writeTimeout;
this.pingInterval = builder.pingInterval;//這個和websocket相關,為了保持長連接,我們必須每間隔一段時間放松一個ping指令
if (interceptors.contains(null)) {
throw new IllegalStateException("Null interceptor: " + interceptors);
}
if (networkInterceptors.contains(null)) {
throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
}
}
Call類
在定義了請求對象后,需要生成一個Call對象。該對象代表一個準備被執行的請求。Call是可以被取消的,Call表示單個請求/響應對流,不能執行兩次。
public interface Call extends Cloneable {
Request request();
Response execute() throws IOException;
void enqueue(Callback responseCallback);
void cancel();
boolean isExecuted();
boolean isCanceled();
Timeout timeout();
Call clone();
interface Factory {
Call newCall(Request request);
}
}
- 進入OkHttpClient的newCall方法
public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
- newRealCall
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.transmitter = new Transmitter(client, call);
return call;
}
newCall方法獲得Call實際是RealCall,RealCall就是準備執行的請求,是對接口Call的實現,其內部持有OkHttpClient實例,Request實例。并且這里還創建了Transmitter給RealCall的transmitter賦值。
Transmitter類
Transmitter意為發射器,是應用層和網絡層的橋梁。在進行連接、真正發出請求和讀取響應中起到很重要的作用。
public Transmitter(OkHttpClient client, Call call) {
this.client = client;
this.connectionPool = Internal.instance.realConnectionPool(client.connectionPool());
this.call = call;
this.eventListener = client.eventListenerFactory().create(call);
this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);
}
Transmitter內部持有OkHttpClient、連接池、call、事件監聽器。
Dispatcher類
Dispatcher類負責異步任務的請求策略。
public final class Dispatcher {
private int maxRequests = 64;
//每個主機的最大請求數,如果超過這個數,新的請求會被加到readyAsyncCalls隊列中
private int maxRequestsPerHost = 5;
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() {
}
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
}
同步請求執行流程
client.newCall(request).execute(),execute方法在Call的實現類RealCall中。
public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.timeoutEnter();//超時計時開始
transmitter.callStart();//回調監聽器的請求開始
try {
client.dispatcher().executed(this);//放入隊列
return getResponseWithInterceptorChain();//執行請求獲取結果
} finally {
client.dispatcher().finished(this);//請求結束
}
}
首先判斷 如果已經執行,就會拋出異常。這就是一個請求只能執行一次的原因。然后回調請求監聽器的請求開始。然后調用client的調度器Dispatcher的executed方法。
- dispatcher().executed()
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
請求放入一個雙端隊列runningSyncCalls中,表示正在執行的同步請求。
然后返回了getResponseWithInterceptorChain()的結果Response,同步請求真正的請求流程是在getResponseWithInterceptorChain方法中(詳情見下節)。
最后請求結束,會走Dispatcher的finished(Deque calls, T call)方法。
- dispatcher.finished()
void finished(RealCall call) {
finished(runningSyncCalls, call);
}
private <T> void finished(Deque<T> calls, T call) {
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
idleCallback = this.idleCallback;
}
boolean isRunning = promoteAndExecute();
if (!isRunning && idleCallback != null) {
idleCallback.run();
}
}
這里將call從同步隊列中移除,并且調用了promoteAndExecute()方法,這個方法在后面講述。
異步請求執行流程
- 異步方法equeue()
@Override
public void enqueue(Callback responseCallback) {
synchronized (this) {
//設置exexuted參數為true,表示不可以執行兩次
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.callStart();//回調請求監聽器的請求開始
//傳入一個新的對象AsyncCall
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
- AsyncCall類
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
String host() {
return originalRequest.url().host();
}
Request request() {
return originalRequest;
}
RealCall get() {
return RealCall.this;
}
@Override protected void execute() {
boolean signalledCallback = false;
try {
//執行耗時的IO操作
//獲取攔截器鏈,詳見下篇文章
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);
}
}
}
AsyncCall繼承NamedRunnable,NamedRunnable實現自Runnable,即AsyncCall就是個Runnable,它是會在線程或線程池中執行run方法的。
- NamedRunnable類
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
@Override public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
//execute抽象方法,在AsyncCall中有具體實現
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
在分析同步的時候知道Dispatcher調度器負責異步請求策略,去看看equeue方法。
- Dispatcher.equeue()
void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call);
// Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
// the same host.
//相同host請求,共用一個調用技術
if (!call.get().forWebSocket) {
AsyncCall existingCall = findExistingCallWithHost(call.host());
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
}
}
promoteAndExecute();
}
//從runningAsyncCalls和readyAsyncCalls找到相同的host請求
private AsyncCall findExistingCallWithHost(String host) {
for (AsyncCall existingCall : runningAsyncCalls) {
if (existingCall.host().equals(host)) return existingCall;
}
for (AsyncCall existingCall : readyAsyncCalls) {
if (existingCall.host().equals(host)) return existingCall;
}
return null;
}
- 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; //最大并發數64.
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host最大并發數.
i.remove();//從等待隊列中移除
//host并發數+1
asyncCall.callsPerHost().incrementAndGet();
//加入可執行請求的集合
executableCalls.add(asyncCall);
//加入正在執行的異步請求隊列
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
//可執行的請求
asyncCall.executeOn(executorService());
}
return isRunning;
}
public synchronized int runningCallsCount() {
return runningAsyncCalls.size() + runningSyncCalls.size();
}
遍歷readyAsyncCalls,先進行兩個檢查:
- 正在執行異步請求runningAsyncCalls數量大于最大并發請求數64就break;
- 相同host請求的數量大于5,就continue。
如果檢查都通過,就從等待隊列中移除,callPerHost自增1,放入可執行的集合executableCalls,并添加到隊列runningAsyncCalls中,表示正在執行的異步請求。
這里的異步請求等待隊列,是為了控制最大并發數的緩沖,異步請求并發數達到64、相同host的異步請求達到5,都要放入等待隊列。
- AsyncCall.executeOn()
void executeOn(ExecutorService executorService) {
assert (!Thread.holdsLock(client.dispatcher()));
boolean success = false;
try {
//在線程池中執行asyncCall
executorService.execute(this);
success = true;
} catch (RejectedExecutionException e) {
InterruptedIOException ioException = new InterruptedIOException("executor rejected");
ioException.initCause(e);
transmitter.noMoreExchanges(ioException);
responseCallback.onFailure(RealCall.this, ioException);//回調失敗
} finally {
if (!success) {
client.dispatcher().finished(this); //執行發生異常 結束
}
}
}
AsyncCall的run方法會走到execute()方法,在上面有展示。
下面總結一下請求的流程:
- 同步請求
- 調用client.newCall(request).execute()方法,也就是RealCall的execute方法;
- execute方法內部調用client.dispatcher().executed()方法,將當前RealCall加入到runningSyncCalls隊列;
- 使用getResponseWithInterceptorChain()獲取結果;
- 最后調用Dispatcher的finish方法結束請求。
- 異步請求
- 調用client.newCall(request).equeue()方法,其內部調用client.dispatcher().enqueue(new AsyncCall(responseCallback))方法;
- 先將AsyncCall加入到當前readyAsyncCalls隊列中,在找到執行當前主機的AsyncCall,一個主機用同一個AsyncCall;
- 使用promoteAndExecute()方法在控制異步并發的策略基礎上使用線程池執行異步請求(并發控制有包括最大并發數64,host最大并發數5)。異步請求的執行也是使用getResponseWithInterceptorChain(),獲得結果后回調出去。最后調用Dispatcher的finish方法結束請求。