特點:
支持HTTP2/SPDY黑科技(Http2 優(yōu)化了頭部壓縮仓手,多路復用多個http請求共用一個TCP連接)
socket自動選擇最好路線巩趁,并支持自動重連
擁有自動維護的socket連接池堤器,減少握手次數(shù)
擁有隊列線程池谨胞,輕松寫并發(fā)
擁有Interceptors輕松處理請求與響應(比如透明GZIP壓縮,LOGGING)
實現(xiàn)基于Headers的緩存策略
內(nèi)部有幾個比較重要的類:
OkHttpClient:
老規(guī)矩還是從最簡單的代碼來分析一下
OkHttpClient client = new OkHttpClient.Builder().build();
Request request = new Request.Builder().
url("https://www.baidu.com").
build();
Call call = client.newCall(request);
try {
//1.同步請求方式
Response response = call.execute();
//2.異步請求方式
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// 獲取失敗
}
@Override
public void onResponse(Call call, Response response) throws IOException {
// 獲取成功
}
});
} catch (IOException e) {
e.printStackTrace();
}
先看OkHttpClient
的Build
方法
public Builder() {
dispatcher = new Dispatcher();// 分發(fā)器 控制并發(fā) 保存了同步和異步的call(線程池執(zhí)行)
protocols = DEFAULT_PROTOCOLS; // http協(xié)議
connectionSpecs = DEFAULT_CONNECTION_SPECS; // 連接配置
eventListenerFactory = EventListener.factory(EventListener.NONE); // 監(jiān)聽器
proxySelector = ProxySelector.getDefault(); // 代理選擇
cookieJar = CookieJar.NO_COOKIES;// 默認沒有cookie
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
coBnectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}
Build
方法創(chuàng)建了默認的設(shè)置,當繼續(xù)調(diào)用build方法時會采用默認設(shè)置創(chuàng)建OkHttpClient對象扎阶。這時如果需要改變默認的屬性洛姑,可以這樣設(shè)置
new OkHttpClient.Builder().connectTimeout(DEFAULT_CONNECT_TIMEOUT, TimeUnit.SECONDS).build();
Request
接著看Request
類
public final class Request {
final HttpUrl url;
final String method;
final Headers headers;
final @Nullable RequestBody body;
final Object tag;
private volatile CacheControl cacheControl; // Lazily initialized.
}
看到這個類包含類請求的url 上沐,method,headers楞艾,body参咙,緩存控制等等龄广。
接著往下分析
Call
@Override public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
final EventListener.Factory eventListenerFactory = client.eventListenerFactory();
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
this.eventListener = eventListenerFactory.create(this);
}
RealCall是實現(xiàn)Call的子類,真正進行操作的類
Response
首先看下同步請求的
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
try {
// 這邊直接放入Running隊列中執(zhí)行
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
真正進行網(wǎng)絡(luò)請求的是Response result = 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));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
這些Interceptor
完成了一系列的鏈式使用蕴侧,CallServerInterceptor
負責向服務器請求數(shù)據(jù)是最后一個择同,這個類的intercept
不會再次調(diào)用下一個Interceptor
的intercept
方法。ConnectInterceptor
負責建立連接净宵,具體怎么實現(xiàn)可以看下代碼敲才,不過肯定逃不過Soket
的使用,再看下CallServerInterceptor
的intercept
方法择葡。
@Override public Response intercept(Chain chain) throws IOException {
HttpCodec httpCodec = ((RealInterceptorChain) chain).httpStream();
StreamAllocation streamAllocation = ((RealInterceptorChain) chain).streamAllocation();
Request request = chain.request();
long sentRequestMillis = System.currentTimeMillis();
httpCodec.writeRequestHeaders(request);
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
Sink requestBodyOut = httpCodec.createRequestBody(request, request.body().contentLength());
BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();
}
httpCodec.finishRequest();
Response response = httpCodec.readResponseHeaders()
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
if (!forWebSocket || response.code() != 101) {
response = response.newBuilder()
.body(httpCodec.openResponseBody(response))
.build();
}
if ("close".equalsIgnoreCase(response.request().header("Connection"))
|| "close".equalsIgnoreCase(response.header("Connection"))) {
streamAllocation.noNewStreams();
}
...
return response;
}
最后由HttpCodec
發(fā)起網(wǎng)絡(luò)請求紧武。
然后再看下異步網(wǎng)絡(luò)請求,按照思路基本流程肯定相似敏储,完成異步操作肯定需要新開線程完成操作阻星。
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
// 先放入Ready隊列
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
看下AsyncCall 怎么包裝的
// Dispatcher
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
// 提交線程池執(zhí)行
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
// 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 {
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);
}
}
}
// AsyncCall 繼承的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();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
Response response = getResponseWithInterceptorChain();
這個就和之前的同步請求一摸一樣。
梳理一下整個流程