這裏以非Kotlin版本介紹java
build.gradle
中添加組件:implementation 'com.squareup.okhttp3:okhttp:3.14.2'
複製代碼
//注意這裏,通常咱們用單例,Okhttp官方描述若是不用單例,線程管理等都失效了,浪費開銷
/*Http performs best when you create a single {@code OkHttpClient} instance and reuse it for * all of your HTTP calls. This is because each client holds its own connection pool and thread * pools. Reusing connections and threads reduces latency and saves memory. Conversely, creating a * client for each request wastes resources on idle pools. */
OkHttpClient client = new OkHttpClient();
String run(String url) throws IOException {
Request request = new Request.Builder()
.url(url)
.build();
Response response = client.newCall(request).execute();
return response.body().string();
}
複製代碼
經過okhttp源碼分析,直接建立的 OkHttpClient對象而且默認構造builder對象進行初始化web
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
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.eventListenerFactory = builder.eventListenerFactory;
this.proxySelector = builder.proxySelector;
this.cookieJar = builder.cookieJar;
this.cache = builder.cache;
this.internalCache = builder.internalCache;
this.socketFactory = builder.socketFactory;
...
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;
this.followSslRedirects = builder.followSslRedirects;
this.followRedirects = builder.followRedirects;
this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
this.connectTimeout = builder.connectTimeout;
this.readTimeout = builder.readTimeout;
this.writeTimeout = builder.writeTimeout;
this.pingInterval = builder.pingInterval;
}
}
複製代碼
通常以下:設計模式
Request request = new Request.Builder().url("url").build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
複製代碼
初始化構建者模式和請求對象,而且用URL替換Web套接字URL。緩存
public final class Request {
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
public Builder url(String url) {
......
// Silently replace web socket URLs with HTTP URLs.
if (url.regionMatches(true, 0, "ws:", 0, 3)) {
url = "http:" + url.substring(3);
} else if (url.regionMatches(true, 0, "wss:", 0, 4)) {
url = "https:" + url.substring(4);
}
HttpUrl parsed = HttpUrl.parse(url);
......
return url(parsed);
}
public Request build() {
......
return new Request(this);
}
}
複製代碼
主裏主要是調用了newCall
方法,咱們跟進去看看:cookie
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
@Override
public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
}
複製代碼
發現去new RealCall
了,咱們跟到RealCall
看看:網絡
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
}
複製代碼
能夠看到只是初始化一些成員變量,真正的調用是RealCall
裏面的enqueue(添加到隊列)/execute(當即執行)
方法,咱們看看:架構
void enqueue(AsyncCall call) {
synchronized (this) {
/** Ready async calls in the order they'll be run. */
//private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
// readyAsyncCalls是一個雙端隊列,把該call加入到準備的隊列裏
readyAsyncCalls.add(call);
// Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
// the same host.
if (!call.get().forWebSocket) {
AsyncCall existingCall = findExistingCallWithHost(call.host());
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
}
}
promoteAndExecute();
}
複製代碼
上面不難發現最終調用了promoteAndExecute()
,咱們跟進去看看:socket
/** * Promotes eligible calls from {@link #readyAsyncCalls} to {@link #runningAsyncCalls} and runs * them on the executor service. Must not be called with synchronization because executing calls * can call into user code. * * @return true if the dispatcher is currently running calls. */
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. // 最大的線程請求的時候,再也不添加, maxRequests默認值是:64
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity. // 最大的DNS解析爲:5
i.remove();
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;
}
複製代碼
有一個問題,enqueue
是拿到Reponse的? 它和execute
區別?async
帶着問題,咱們能夠在RealCall
中能夠發現 final class AsyncCall extends NamedRunnable
ide
這個NamedRunnable
是什麼?
/** * Runnable implementation which always sets its thread name. */
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();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
複製代碼
根據源碼發現它原來是一個runable
,而且抽象了execute
,因此execute
就是enqueue
去執行的核心方法,那麼我就能夠看到execute
方法的實現:
@Override protected void execute() {
boolean signalledCallback = false;
transmitter.timeoutEnter();
try {
Response response = getResponseWithInterceptorChain();
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);
}
}
複製代碼
實際上跟execute
方法同樣,都是調用了getResponseWithInterceptorChain
,跟進去看看:
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());// 1.添加自定義的攔截器
interceptors.add(new RetryAndFollowUpInterceptor(client));// 2.重試攔截
interceptors.add(new BridgeInterceptor(client.cookieJar())); // 3.Build一個適配的Request
interceptors.add(new CacheInterceptor(client.internalCache()));// 4.添加緩存攔截器
interceptors.add(new ConnectInterceptor(client)); // 5.ConnectInterceptor驗證Get請求
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors()); // 6.非Websocket下建立的自定義網絡攔截器
}
interceptors.add(new CallServerInterceptor(forWebSocket)); // 7. 真實的IO訪問,使用了OKIO庫去實現的
Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
.....
return response;
}
複製代碼
從上面的設計模式能夠看出來OKHttp使用了責任鏈
的設計模式. 至此流程已經完畢. 下面學習一些優秀的細節.