學(xué)習(xí)一下OkHttp原理章姓,探究他發(fā)送請(qǐng)求的過(guò)程
合理的跳過(guò)了一些內(nèi)容秃殉,比如DNS、Cookie咪笑、Protocol可帽、okio
OkHttp版本3.14.9
btn.setOnClickListener(v -> {
new Thread(() -> {
OkHttpClient client = new OkHttpClient.Builder().build();
Request request = new Request.Builder()
.url("這里是一個(gè)能訪問(wèn)的url")
.build();
Call call = client.newCall(request);
try{
//同步請(qǐng)求
Response response = call.execute();
System.out.println(response.body().string());
}catch(IOException e){
e.printStackTrace();
}
}).start();
OkHttpClient client = new OkHttpClient.Builder().build();
Request request = new Request.Builder()
.url("這里是一個(gè)能訪問(wèn)的url")
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
System.out.println(response.body().string());
}
});
});
隨便寫(xiě)了一個(gè)按鈕,定義 OkHttpClient
蒲肋、 Request
蘑拯、 Call
, 然后同步請(qǐng)求,寫(xiě)了一個(gè)最少的http代碼請(qǐng)求兜粘,返回 Response
輸出body
2塊內(nèi)容一個(gè)是同步請(qǐng)求申窘,一個(gè)是異步請(qǐng)求,同步請(qǐng)求不加線程會(huì)拋出異常
開(kāi)始
OkHttpClient.Builder()
看到 OkHttpClient.Builder()
我已經(jīng)不想開(kāi)了孔轴,肯定是初始各種值
build()各種賦值剃法,然后返回一個(gè) OkHttpClient
對(duì)象
Builder(OkHttpClient okHttpClient) {
this.dispatcher = okHttpClient.dispatcher;//調(diào)度器
//..
this.connectionPool = okHttpClient.connectionPool;
//..
this.callTimeout = okHttpClient.callTimeout;
this.connectTimeout = okHttpClient.connectTimeout;
this.readTimeout = okHttpClient.readTimeout;
this.writeTimeout = okHttpClient.writeTimeout;
this.pingInterval = okHttpClient.pingInterval;
}
只留關(guān)鍵的,看名字大概都能知道是什么了
調(diào)度器路鹰,連接池贷洲,call超時(shí),連接超時(shí)等等晋柱,其他的基本也能根據(jù)名字看出來(lái)是干什么的
Request.Builder()
public static class Builder {
@Nullable HttpUrl url;
String method;
Headers.Builder headers;
@Nullable RequestBody body;
Map<Class<?>, Object> tags = Collections.emptyMap();
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
}
一個(gè)請(qǐng)求包含url
优构、method
、headers
和body
,默認(rèn)GET
client.newCall(request)
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false);
}
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.transmitter = new Transmitter(client, call);
return call;
}
根據(jù) newCall()
返回了一個(gè) RealCall
對(duì)象,還new了一個(gè)Transmitter發(fā)射器雁竞,對(duì)象交給了call
看一下RealCall和Transmitter構(gòu)造函數(shù)
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
}
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);
}
也是簡(jiǎn)單的初始化钦椭,不過(guò)能看出這個(gè)RealCall已經(jīng)有了發(fā)射器拧额,并且里面有連接池了
call.execute() 同步請(qǐng)求
關(guān)鍵部分,先看call.execute()彪腔,同步執(zhí)行侥锦,根據(jù)安卓機(jī)制必須在子線程
@Override public Response execute() throws IOException {
//保證只有一個(gè)執(zhí)行
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);
}
}
//dispatcher的executed, 這里把RealCall放到了同步隊(duì)列里
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
getResponseWithInterceptorChain()
是庫(kù)的最關(guān)鍵代碼,直接貼代碼
interceptor 是攔截器的意思
Response getResponseWithInterceptorChain() throws IOException {
//創(chuàng)建了一個(gè)攔截器List,然后添加了寫(xiě)攔截器對(duì)象
List<Interceptor> interceptors = new ArrayList<>();
//這是自定義的 先不管
interceptors.addAll(client.interceptors());
//重定向攔截器
interceptors.add(new RetryAndFollowUpInterceptor(client));
//橋攔截器
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//緩存攔截器
interceptors.add(new CacheInterceptor(client.internalCache()));
//連接攔截器
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
//呼叫服務(wù)攔截器德挣。恭垦。。
interceptors.add(new CallServerInterceptor(forWebSocket));
//正真串聯(lián)攔截器的地方
Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
boolean calledNoMoreExchanges = false;
try {
//這里是正真的把攔截器串聯(lián)起來(lái)的地方 格嗅,并返回Response對(duì)象
Response response = chain.proceed(originalRequest);
if (transmitter.isCanceled()) {
closeQuietly(response);
throw new IOException("Canceled");
}
return response;
} catch (IOException e) {
calledNoMoreExchanges = true;
throw transmitter.noMoreExchanges(e);
} finally {
if (!calledNoMoreExchanges) {
transmitter.noMoreExchanges(null);
}
}
}
看看是怎么連起來(lái)的
chain.proceed(originalRequest)
執(zhí)行攔截器方法
public final class RealInterceptorChain implements Interceptor.Chain {
@Override public Response proceed(Request request) throws IOException {
return proceed(request, transmitter, exchange);
}
public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)throws IOException {
//保留重要代碼
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
return response;
}
}
可以看到 RealInterceptorChain
類(lèi)實(shí)現(xiàn)了 Interceptor.Chain
接口,完成了 proceed(Request request)
方法
在下面的 proceed(...)
中,又new了一個(gè) RealInterceptorChain
把攔截器List等參數(shù)又傳了進(jìn)去番挺,有個(gè)關(guān)鍵的變量 index
也就是說(shuō) 自己new了自己,并告訴new出來(lái)的自己索引+1
在看下面2行獲取了一個(gè)攔截器吗浩,執(zhí)行他的攔截方法interceptor.intercept(next)
這里構(gòu)造了一個(gè) 責(zé)任鏈模式建芙,簡(jiǎn)單理解下責(zé)任鏈模式,有點(diǎn)鏈表結(jié)構(gòu)的感覺(jué)懂扼,但不是鏈表,相當(dāng)于把一個(gè)節(jié)點(diǎn)一個(gè)節(jié)點(diǎn)的連起來(lái)右蒲,當(dāng)輸出第一個(gè)節(jié)點(diǎn)阀湿,會(huì)依次調(diào)用下面一個(gè)節(jié)點(diǎn)輸出內(nèi)容
按著順序來(lái)取第一個(gè)攔截器
1、RetryAndFollowUpInterceptor 重定向攔截器
重定向攔截器:主要負(fù)責(zé)失敗重連瑰妄,但并不是所有失敗都重連
public final class RetryAndFollowUpInterceptor implements Interceptor {
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Transmitter transmitter = realChain.transmitter();
int followUpCount = 0;
Response priorResponse = null;
while (true) {
transmitter.prepareToConnect(request);
//如果取消就拋異常
if (transmitter.isCanceled()) {
throw new IOException("Canceled");
}
Response response;
boolean success = false;
try {
//使用realChain執(zhí)行下一個(gè)攔截器
//為什么要直接執(zhí)行下一個(gè)攔截器陷嘴?
//因?yàn)檫@個(gè)是為重定向做的攔截器,肯定是等請(qǐng)求返回結(jié)果之后再?zèng)Q定是否要重定向
response = realChain.proceed(request, transmitter, null);
success = true;
} catch (RouteException e) {
// The attempt to connect via a route failed. The request will not have been sent.
if (!recover(e.getLastConnectException(), transmitter, false, request)) {
throw e.getFirstConnectException();
}
continue;
}//這里刪了catch间坐,出了異常灾挨,catch肯定是關(guān)閉流
//如果priorResponse不為null,又newBuilder()
//把上一個(gè)Response和現(xiàn)在的結(jié)合在一起
//正常來(lái)說(shuō)第一次肯定是空的
//prior 先前的竹宋,先前的Response不為null
if (priorResponse != null) {
response = response.newBuilder()
.priorResponse(priorResponse.newBuilder()
.body(null)
.build())
.build();
}
Exchange exchange = Internal.instance.exchange(response);
Route route = exchange != null ? exchange.connection().route() : null;
//檢查是否符合要求
//這個(gè)方法里是一個(gè)switch劳澄、case去找HttpCode狀態(tài)碼 比如200,404
Request followUp = followUpRequest(response, route);
//正常來(lái)說(shuō)應(yīng)該是200 followUpRequest()就會(huì)返回null
if (followUp == null) {
if (exchange != null && exchange.isDuplex()) {
transmitter.timeoutEarlyExit();
}
return response;
}
RequestBody followUpBody = followUp.body();
if (followUpBody != null && followUpBody.isOneShot()) {
return response;
}
closeQuietly(response.body());
if (transmitter.hasExchange()) {
exchange.detachWithViolence();
}
//限制重定向次數(shù)
if (++followUpCount > MAX_FOLLOW_UPS) {
throw new ProtocolException("Too many follow-up requests: " + followUpCount);
}
request = followUp;
priorResponse = response;
}
}
}
這個(gè)攔截器就是先請(qǐng)求蜈七,請(qǐng)求返回?cái)?shù)據(jù)之后根據(jù)數(shù)據(jù)來(lái)判斷秒拔,是否需要重定向
2、BridgeInterceptor 橋攔截器
這里很長(zhǎng)飒硅,橋攔截器主要用來(lái)添加頭部信息砂缩、編碼方式
public final class BridgeInterceptor implements Interceptor {
@Override public Response intercept(Chain chain) throws IOException {
Request userRequest = chain.request();
Request.Builder requestBuilder = userRequest.newBuilder();
RequestBody body = userRequest.body();
if (body != null) {
MediaType contentType = body.contentType();
if (contentType != null) {
requestBuilder.header("Content-Type", contentType.toString());
}
long contentLength = body.contentLength();
if (contentLength != -1) {
requestBuilder.header("Content-Length", Long.toString(contentLength));
requestBuilder.removeHeader("Transfer-Encoding");
} else {
requestBuilder.header("Transfer-Encoding", "chunked");
requestBuilder.removeHeader("Content-Length");
}
}
if (userRequest.header("Host") == null) {
requestBuilder.header("Host", hostHeader(userRequest.url(), false));
}
if (userRequest.header("Connection") == null) {
requestBuilder.header("Connection", "Keep-Alive");
}
// If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
// the transfer stream.
boolean transparentGzip = false;
if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
transparentGzip = true;
requestBuilder.header("Accept-Encoding", "gzip");
}
List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
if (!cookies.isEmpty()) {
requestBuilder.header("Cookie", cookieHeader(cookies));
}
if (userRequest.header("User-Agent") == null) {
requestBuilder.header("User-Agent", Version.userAgent());
}
//這里調(diào)用下一層的攔截器
Response networkResponse = chain.proceed(requestBuilder.build());
//下面是處理cookie緩存和GZip的內(nèi)容
HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
Response.Builder responseBuilder = networkResponse.newBuilder()
.request(userRequest);
//判斷服務(wù)器是否支持GZip,支持交給okio處理
if (transparentGzip
&& "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
&& HttpHeaders.hasBody(networkResponse)) {
GzipSource responseBody = new GzipSource(networkResponse.body().source());
Headers strippedHeaders = networkResponse.headers().newBuilder()
.removeAll("Content-Encoding")
.removeAll("Content-Length")
.build();
responseBuilder.headers(strippedHeaders);
String contentType = networkResponse.header("Content-Type");
//處理之后build 一個(gè)新的Response
responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
}
return responseBuilder.build();
}
}
這里就是3段內(nèi)容三娩,增加頭信息庵芭、調(diào)用下一層攔截器、處理緩存和GZip
3雀监、CacheInterceptor 緩存攔截器
緩存攔截器双吆,顧名思義處理緩存
public final class CacheInterceptor implements Interceptor {
@Override public Response intercept(Chain chain) throws IOException {
Response cacheCandidate = cache != null
? cache.get(chain.request())
: null;
long now = System.currentTimeMillis();
CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
Request networkRequest = strategy.networkRequest;
Response cacheResponse = strategy.cacheResponse;
if (cache != null) {
cache.trackResponse(strategy);
}
if (cacheCandidate != null && cacheResponse == null) {
closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
}
//注釋寫(xiě)明了,如果沒(méi)網(wǎng)和沒(méi)緩存 直接返回失敗
// If we're forbidden from using the network and the cache is insufficient, fail.
if (networkRequest == null && cacheResponse == null) {
return new Response.Builder()
.request(chain.request())
.protocol(Protocol.HTTP_1_1)
.code(504)
.message("Unsatisfiable Request (only-if-cached)")
.body(Util.EMPTY_RESPONSE)
.sentRequestAtMillis(-1L)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
}
//這里沒(méi)網(wǎng)
// If we don't need the network, we're done.
if (networkRequest == null) {
return cacheResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.build();
}
Response networkResponse = null;
try {
//調(diào)用下一層攔截器
networkResponse = chain.proceed(networkRequest);
} finally {
// If we're crashing on I/O or otherwise, don't leak the cache body.
if (networkResponse == null && cacheCandidate != null) {
closeQuietly(cacheCandidate.body());
}
}
// If we have a cache response too, then we're doing a conditional get.
//如果有緩存并且code為304,使用緩存內(nèi)容
if (cacheResponse != null) {
if (networkResponse.code() == HTTP_NOT_MODIFIED) {
Response response = cacheResponse.newBuilder()
.headers(combine(cacheResponse.headers(), networkResponse.headers()))
.sentRequestAtMillis(networkResponse.sentRequestAtMillis())
.receivedResponseAtMillis(networkResponse.receivedResponseAtMillis())
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
networkResponse.body().close();
// Update the cache after combining headers but before stripping the
// Content-Encoding header (as performed by initContentStream()).
cache.trackConditionalCacheHit();
cache.update(cacheResponse, response);
return response;
} else {
closeQuietly(cacheResponse.body());
}
}
Response response = networkResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
if (cache != null) {
if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
// Offer this request to the cache.
CacheRequest cacheRequest = cache.put(response);
return cacheWritingResponse(cacheRequest, response);
}
if (HttpMethod.invalidatesCache(networkRequest.method())) {
try {
cache.remove(networkRequest);
} catch (IOException ignored) {
// The cache cannot be written.
}
}
}
return response;
}
}
這一層也很明確伊诵,專(zhuān)門(mén)處理緩存单绑,有個(gè)關(guān)鍵cache對(duì)象,如果最開(kāi)始o(jì)khttp初始化曹宴,賦值了搂橙,則會(huì)使用這個(gè)緩存,如果沒(méi)賦值則不會(huì)使用笛坦。
4区转、ConnectInterceptor 連接攔截器
連接攔截器,這層是關(guān)鍵內(nèi)容版扩,也最復(fù)雜废离,負(fù)責(zé)與服務(wù)器建立連接
public final class ConnectInterceptor implements Interceptor {
public final OkHttpClient client;
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Request request = realChain.request();
Transmitter transmitter = realChain.transmitter();
// We need the network to satisfy this request. Possibly for validating a conditional GET.
boolean doExtensiveHealthChecks = !request.method().equals("GET");
Exchange exchange = transmitter.newExchange(chain, doExtensiveHealthChecks);
return realChain.proceed(request, transmitter, exchange);
}
}
//前面只是獲取對(duì)象
//關(guān)鍵 發(fā)射機(jī) transmitter.newExchange(chain, doExtensiveHealthChecks)
public final class Transmitter {
//這個(gè)exchangeFinder也是new出來(lái)的
private ExchangeFinder exchangeFinder;
//這里看方法是返回一個(gè)Exchange對(duì)象
//我也不知道為什么要叫這個(gè)名字,歷史版本我也沒(méi)看過(guò)
Exchange newExchange(Interceptor.Chain chain, boolean doExtensiveHealthChecks) {
synchronized (connectionPool) {
if (noMoreExchanges) {
throw new IllegalStateException("released");
}
if (exchange != null) {
throw new IllegalStateException("cannot make a new request because the previous response "
+ "is still open: please call response.close()");
}
}
//exchangeFinder礁芦,exchange查找器
ExchangeCodec codec = exchangeFinder.find(client, chain, doExtensiveHealthChecks);
Exchange result = new Exchange(this, call, eventListener, exchangeFinder, codec);
synchronized (connectionPool) {
this.exchange = result;
this.exchangeRequestDone = false;
this.exchangeResponseDone = false;
return result;
}
}
}
//Exchange查找器
final class ExchangeFinder {
public ExchangeCodec find(
OkHttpClient client, Interceptor.Chain chain, boolean doExtensiveHealthChecks) {
int connectTimeout = chain.connectTimeoutMillis();
int readTimeout = chain.readTimeoutMillis();
int writeTimeout = chain.writeTimeoutMillis();
int pingIntervalMillis = client.pingIntervalMillis();
boolean connectionRetryEnabled = client.retryOnConnectionFailure();
//上面只是賦值 連接時(shí)間 讀取時(shí)間超時(shí)等等
try {
//獲取一個(gè)健康的連接
RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
writeTimeout, pingIntervalMillis, connectionRetryEnabled, doExtensiveHealthChecks);
return resultConnection.newCodec(client, chain);
} catch (RouteException e) {
trackFailure();
throw e;
} catch (IOException e) {
trackFailure();
throw new RouteException(e);
}
}
//尋找一個(gè)健康的連接
private RealConnection findHealthyConnection(int connectTimeout, int readTimeout,int writeTimeout, int pingIntervalMillis, boolean connectionRetryEnabled,boolean doExtensiveHealthChecks) throws IOException {
while (true) {
//while ture 去尋找一個(gè) 連接
//這里死循環(huán)去找鏈接的連接 可能是有問(wèn)題的連接
RealConnection candidate = findConnection(connectTimeout, readTimeout, writeTimeout,
pingIntervalMillis, connectionRetryEnabled);
synchronized (connectionPool) {
//這里鎖 一下 判斷 蜻韭,如果是全新的連接就直接返回
if (candidate.successCount == 0 && !candidate.isMultiplexed()) {
return candidate;
}
}
//這里判斷連接是否健康,無(wú)非是socket沒(méi)有關(guān)閉柿扣,等等
if (!candidate.isHealthy(doExtensiveHealthChecks)) {
candidate.noNewExchanges();
continue;
}
return candidate;
}
}
//最長(zhǎng)代碼肖方,一點(diǎn)點(diǎn)看
vate RealConnection findConnection(int connectTimeout, int dTimeout, int writeTimeout,
nt pingIntervalMillis, boolean connectionRetryEnabled) throws OException {
boolean foundPooledConnection = false;
RealConnection result = null;
Route selectedRoute = null;
RealConnection releasedConnection;
Socket toClose;
synchronized (connectionPool) {
if (transmitter.isCanceled()) throw new IOException("Canceled");
hasStreamFailure = false; // This is a fresh attempt.
//這里鎖池子,看看當(dāng)前發(fā)射機(jī)transmitter里面的連接能不能用
releasedConnection = transmitter.connection;
toClose = transmitter.connection != null && transmitter.connection.noNewExchanges
? transmitter.releaseConnectionNoEvents()
: null;
if (transmitter.connection != null) {
//這里判斷有點(diǎn)特別
//發(fā)射機(jī)連接不為空 能用 就賦值給result對(duì)象
result = transmitter.connection;
releasedConnection = null;
}
//當(dāng)然result為空就要從連接池取
if (result == null) {
//里面就是循環(huán)連接池未状,循環(huán)取俯画,當(dāng)然 也有可能取不到
//取不到下面會(huì)new的,第一次肯定取不到
if(connectionPool.transmitterAcquirePooledConnection(address, transmitter, null, false)) {
foundPooledConnection = true;
result = transmitter.connection;
} else if (nextRouteToTry != null) {
selectedRoute = nextRouteToTry;
nextRouteToTry = null;
} else if (retryCurrentRoute()) {
selectedRoute = transmitter.connection.route();
}
}
}
closeQuietly(toClose);
if (releasedConnection != null) {
eventListener.connectionReleased(call, releasedConnection);
}
if (foundPooledConnection) {
eventListener.connectionAcquired(call, result);
}
if (result != null) {
//到這里result不為空 則直接返回發(fā)射機(jī)里的 連接
return result;
}
// If we need a route selection, make one. This is a blocking operation.
boolean newRouteSelection = false;
if (selectedRoute == null && (routeSelection == null || !routeSelection.hasNext())) {
newRouteSelection = true;
routeSelection = routeSelector.next();
}
List<Route> routes = null;
synchronized (connectionPool) {
if (transmitter.isCanceled()) throw new IOException("Canceled");
if (newRouteSelection) {
//獲取路由表司草,再次嘗試從連接池里取連接
routes = routeSelection.getAll();
if (connectionPool.transmitterAcquirePooledConnection(
address, transmitter, routes, false)) {
foundPooledConnection = true;
//取到了就賦值給result
result = transmitter.connection;
}
}
if (!foundPooledConnection) {
if (selectedRoute == null) {
selectedRoute = routeSelection.next();
}
//各種都取不到 new了
result = new RealConnection(connectionPool, selectedRoute);
connectingConnection = result;
}
}
//這里是回調(diào) 艰垂,獲取連接后調(diào)用的
if (foundPooledConnection) {
eventListener.connectionAcquired(call, result);
return result;
}
//到這里肯定是新連接了,開(kāi)始握手
result.connect(connectTimeout, readTimeout, writeTimeout, pingIntervalMillis,
connectionRetryEnabled, call, eventListener);
connectionPool.routeDatabase.connected(result.route());
Socket socket = null;
synchronized (connectionPool) {
connectingConnection = null;
//這里又嘗試去取連接
if(connectionPool.transmitterAcquirePooledConnection(address, transmitter, routes, true)) {
result.noNewExchanges = true;
socket = result.socket();
result = transmitter.connection;
// It's possible for us to obtain a coalesced connection that is immediately unhealthy. In
// that case we will retry the route we just successfully connected with.
nextRouteToTry = selectedRoute;
} else {
connectionPool.put(result);
transmitter.acquireConnectionNoEvents(result);
}
}
closeQuietly(socket);
eventListener.connectionAcquired(call, result);
return result;
}
//到這里一個(gè)連接就找到了
//返回上面 埋虹,根據(jù)這個(gè)連接去判斷他是否健康猜憎,不健康就再取
}
1、從transmitter中取吨岭,取到就返回
2拉宗、如果取不到從ConnectionPool中取,取到就返回
3辣辫、遍歷路由地址旦事、再?gòu)腃onnectionPool中取
4、創(chuàng)建新的Connection
5急灭、用新的Connection進(jìn)行握手
到這里 從find()->findHealthyConnection()->findConnection()很清晰
這里我有個(gè)不明白的地方姐浮,如果大佬看到了可以為我解釋?zhuān)嚎赡苓@里偏向網(wǎng)絡(luò)了,不太明白這里的路由表Route有什么作用葬馋。
再來(lái)看一下 握手
result.connect(...) 握手
public void connect(int connectTimeout, int readTimeout, int writeTimeout,int pingIntervalMillis, boolean connectionRetryEnabled, Call call,EventListener eventListener) {
if (protocol != null) throw new IllegalStateException("already connected");
//去掉一些賦值和一些判斷卖鲤,如果有問(wèn)題會(huì)拋出路由異常
//判斷客戶端是否啟用明文通信等等
while (true) {
try {
if (route.requiresTunnel()) {
//如果有通道肾扰,去進(jìn)行連接通道 里面還是會(huì)連接socket
connectTunnel(connectTimeout, readTimeout, writeTimeout, call, eventListener);
if (rawSocket == null) {
//成功就跳出
break;
}
} else {
//關(guān)鍵 連接socket
connectSocket(connectTimeout, readTimeout, call, eventListener);
}
//定制協(xié)議
//這里面賦值一下協(xié)議,這時(shí)候socket已經(jīng)建立了
//已經(jīng)知道服務(wù)器用的什么協(xié)議了
establishProtocol(connectionSpecSelector, pingIntervalMillis, call, eventListener);
//listener 回調(diào) 告訴我們 連接完成
//這里在Okhttp創(chuàng)建的時(shí)候 做一些日志操作
eventListener.connectEnd(call, route.socketAddress(), route.proxy(), protocol);
break;
} catch (IOException e) {
//一些關(guān)閉流的操作
}
if (route.requiresTunnel() && rawSocket == null) {
ProtocolException exception = new ProtocolException("Too many tunnel connections attempted: "
+ MAX_TUNNEL_ATTEMPTS);
throw new RouteException(exception);
}
if (http2Connection != null) {
synchronized (connectionPool) {
allocationLimit = http2Connection.maxConcurrentStreams();
}
}
}
//socket連接
connectSocket(connectTimeout, readTimeout, call, eventListener);
private void connectSocket(int connectTimeout, int readTimeout, Call call,
EventListener eventListener) throws IOException {
Proxy proxy = route.proxy();
Address address = route.address();
rawSocket = proxy.type() == Proxy.Type.DIRECT || proxy.type() == Proxy.Type.HTTP
? address.socketFactory().createSocket()
: new Socket(proxy);
//連接開(kāi)始
eventListener.connectStart(call, route.socketAddress(), proxy);
rawSocket.setSoTimeout(readTimeout);
try {
//連接操作
//get判斷是android平臺(tái)還是java平臺(tái),再里面反射了一些SSL的底層實(shí)現(xiàn)類(lèi)
//connectSocket里面就是socket連接了
Platform.get().connectSocket(rawSocket, route.socketAddress(), connectTimeout);
} catch (ConnectException e) {
ConnectException ce = new ConnectException("Failed to connect to " + route.socketAddress());
ce.initCause(e);
throw ce;
}
ConnectInterceptor
連接攔截器,這里很長(zhǎng)蛋逾,做的事情也很明確
1集晚、從連接池取連接
2、如果是新的連接区匣,socket建立連接
其實(shí)這里的握手操作意思是建立Socket操作偷拔,Socket是一個(gè)套接字,是一個(gè)通信連接的對(duì)象亏钩,socket屬于傳輸層莲绰,正真建立三次握手的是在這一層,不是在我們寫(xiě)的引用層姑丑。
5蛤签、CallServerInterceptor 呼叫服務(wù)器攔截器
最后一層,請(qǐng)求網(wǎng)絡(luò)
public final class CallServerInterceptor implements Interceptor {
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Exchange exchange = realChain.exchange();
Request request = realChain.request();
long sentRequestMillis = System.currentTimeMillis();
//向socket頭寫(xiě)入信息
exchange.writeRequestHeaders(request);
boolean responseHeadersStarted = false;
Response.Builder responseBuilder = null;
//這里判斷是否有Body
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
//當(dāng)socket連接服務(wù)器后栅哀,就已經(jīng)有狀態(tài)碼了
//100 該狀態(tài)碼 說(shuō)明服務(wù)器已經(jīng)接收到了 請(qǐng)求的初始部分
if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
exchange.flushRequest();
responseHeadersStarted = true;
exchange.responseHeadersStart();
responseBuilder = exchange.readResponseHeaders(true);
}
if (responseBuilder == null) {
//這里判斷全雙工 默認(rèn)false
if (request.body().isDuplex()) {
// Prepare a duplex body so that the application can send a request body later.
exchange.flushRequest();
BufferedSink bufferedRequestBody = Okio.buffer(
exchange.createRequestBody(request, true));
request.body().writeTo(bufferedRequestBody);
} else {
// Write the request body if the "Expect: 100-continue" expectation was met.
BufferedSink bufferedRequestBody = Okio.buffer(
exchange.createRequestBody(request, false));
request.body().writeTo(bufferedRequestBody);
//
bufferedRequestBody.close();
}
} else {
exchange.noRequestBody();
if (!exchange.connection().isMultiplexed()) {
// If the "Expect: 100-continue" expectation wasn't met, prevent the HTTP/1 connection
// from being reused. Otherwise we're still obligated to transmit the request body to
// leave the connection in a consistent state.
exchange.noNewExchangesOnConnection();
}
}
} else {
exchange.noRequestBody();
}
if (request.body() == null || !request.body().isDuplex()) {
//完成網(wǎng)絡(luò)的寫(xiě)入
exchange.finishRequest();
}
if (!responseHeadersStarted) {
//回調(diào)listener
exchange.responseHeadersStart();
}
if (responseBuilder == null) {
//讀取Response 在這個(gè)里面正真的 調(diào)用他自己的okio 讀取數(shù)據(jù)
responseBuilder = exchange.readResponseHeaders(false);
}
//數(shù)據(jù)已經(jīng)回來(lái)了到這里 后面就是一些小判斷了
Response response = responseBuilder
.request(request)
.handshake(exchange.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
int code = response.code();
if (code == 100) {
// server sent a 100-continue even though we did not request one.
// try again to read the actual response
response = exchange.readResponseHeaders(false)
.request(request)
.handshake(exchange.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
code = response.code();
}
exchange.responseHeadersEnd(response);
if (forWebSocket && code == 101) {
// Connection is upgrading, but we need to ensure interceptors see a non-null response body.
response = response.newBuilder()
.body(Util.EMPTY_RESPONSE)
.build();
} else {
response = response.newBuilder()
.body(exchange.openResponseBody(response))
.build();
}
if ("close".equalsIgnoreCase(response.request().header("Connection"))
|| "close".equalsIgnoreCase(response.header("Connection"))) {
exchange.noNewExchangesOnConnection();
}
if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
throw new ProtocolException(
"HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
}
return response;
}
}
到這里 Response已經(jīng)回來(lái)震肮,數(shù)據(jù)也讀取完畢。最后返回 response
這里5個(gè)攔截器已經(jīng)全部走完
回顧一下5個(gè)攔截器
1昌屉、RetryAndFollowUpInterceptor 重定向攔截器
2钙蒙、BridgeInterceptor 橋攔截器
3、CacheInterceptor 緩存攔截器
4间驮、ConnectInterceptor 連接攔截器
5、CallServerInterceptor 呼叫服務(wù)攔截器
這5個(gè)攔截器依次從上往下執(zhí)行马昨,最后再返回
以上記錄的是 同步請(qǐng)求方法
call.enqueue(new Callback(){..} ) 異步請(qǐng)求
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.callStart();
//創(chuàng)建了一個(gè)AsynCall對(duì)象
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
//調(diào)度器的dispatcher方法
void enqueue(AsyncCall call) {
synchronized (this) {
//鎖住對(duì)象放入 readyAsyncCalls 隊(duì)列中
readyAsyncCalls.add(call);
if (!call.get().forWebSocket) {
AsyncCall existingCall = findExistingCallWithHost(call.host());
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
}
}
//執(zhí)行
promoteAndExecute();
}
//執(zhí)行
private boolean promoteAndExecute() {
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();
//鎖住對(duì)象時(shí)的 臨時(shí)隊(duì)列
executableCalls.add(asyncCall);
//鎖住對(duì)象竞帽,把準(zhǔn)備好的AsyncCall 放到runningAsyncCalls隊(duì)列里
//runningAsyncCalls是正在執(zhí)行的隊(duì)列
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
//循環(huán)這個(gè)執(zhí)行臨時(shí)隊(duì)列的
//根據(jù)安卓的機(jī)制還是需要在子線程里請(qǐng)求網(wǎng)絡(luò)
//executorService()是個(gè)線程池
asyncCall.executeOn(executorService());
}
return isRunning;
}
//看一下AsyncCall結(jié)構(gòu) 是個(gè)內(nèi)部類(lèi)
final class RealCall implements Call {
final class AsyncCall extends NamedRunnable {
}
}
//在看一下NamedRunnable,繼承了Runnable,他的run方法里執(zhí)行了execute()
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();
}
//既然執(zhí)行了execute()方法 打開(kāi)asyncCall.executeOn(executorService());
void executeOn(ExecutorService executorService) {
boolean success = false;
try {
//executorService線程池對(duì)象 執(zhí)行this
//這個(gè)this就是AsyncCall類(lèi)
//也就是線程池執(zhí)行 run方法鸿捧,上面的run方法又執(zhí)行了execute()
executorService.execute(this);
success = true;
} catch (RejectedExecutionException e) {
} finally {
}
}
//所以只要看 AsyncCall 完成的 NamedRunnable的 execute()方法
@Override protected void execute() {
boolean signalledCallback = false;
transmitter.timeoutEnter();
try {
Response response = getResponseWithInterceptorChain();
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
} catch (IOException e) {
} finally {
}
}
最后又執(zhí)行了 getResponseWithInterceptorChain()
方法屹篓,執(zhí)行5個(gè)攔截器,返回
這里代碼很長(zhǎng)匙奴,關(guān)鍵內(nèi)容就在5個(gè)攔截器
OkHttp還有一個(gè)比較關(guān)鍵的內(nèi)容就是連接池堆巧,暫時(shí)不寫(xiě)了。
貼個(gè)圖加深印象泼菌,看源碼不太清晰的時(shí)候谍肤,畫(huà)個(gè)思維導(dǎo)圖或者畫(huà)一個(gè)重要類(lèi)的 類(lèi)圖基本上代碼就很清晰了
我也看到了很多不會(huì)內(nèi)容,我會(huì)繼續(xù)深入的學(xué)習(xí)
如果你看到這里哗伯,覺(jué)得寫(xiě)的還可以荒揣,請(qǐng)給我贊吧~!??
學(xué)藝不精焊刹,如果內(nèi)容有錯(cuò)誤請(qǐng)及時(shí)聯(lián)系我系任,我及時(shí)改正