Android框架原始碼解析之(二)OKhttp
原始碼在:https://github.com/square/okhttp
包實在是太多了,OKhttp核心在這塊https://github.com/square/okhttp/tree/master/okhttp
直接匯入Android Studio中即可。
基本使用:
//1、建立OkHttpClient
OkHttpClient mOkHttpClient = new OkHttpClient();
//2、建立Request
final Request request = new Request.Builder()
.url("https://www.jianshu.com/u/b4e69e85aef6" )
.addHeader("user_agent","22222")
.build();
//3、建立Call
Call call = mOkHttpClient.newCall(request);
//4、執行call.enqueue
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if(response != null )
Log.i(TAG, "返回服務端資料:"+ String.valueOf(response.body().string()));
}
});
原始碼解析:
1、建立OkHttpClient
//OkHttpClient.java
public OkHttpClient() {
this(new Builder());
}
OkHttpClient(Builder builder) {
//排程器
this.dispatcher = builder.dispatcher;
this.proxy = builder.proxy;
//預設支援的Http協議版本 -- Protocol.HTTP_2, Protocol.HTTP_1_1;
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;
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;
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;
if (interceptors.contains(null)) {
throw new IllegalStateException("Null interceptor: " + interceptors);
}
if (networkInterceptors.contains(null)) {
throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
}
}
通過建造者模式為我們設定預設的OKhttpClient
2、建立Request
//Request.java
Request(Builder builder) {
//請求的url
this.url = builder.url;
//請求的方式
this.method = builder.method;
//請求頭
this.headers = builder.headers.build();
//請求體
this.body = builder.body;
this.tags = Util.immutableMap(builder.tags);
}
//具體的設定我就不貼了,可以看出通過建造者模式建立Request
public Builder newBuilder() {
return new Builder(this);
}
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);
}
通過建造者模式建立Request
3、建立Call
Call call = mOkHttpClient.newCall(request);
原始碼:
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
可以看出,呼叫了RealCall.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.eventListener = client.eventListenerFactory().create(call);
return call;
}
實際上是建立了RealCall物件
4、執行RealCall.enqueue方法,非同步請求
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
//為保證執行緒安全,若已經執行,丟擲IllegalStateException
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
//重點在這裡
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
可以看出最終的請求是dispatcher來完成的
看一下同步請求程式碼:
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
//同步請求
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);
}
}
在這裡可以看出
非同步請求呼叫了dispatcher().enqueue
同步請求呼叫了dispatcher().executed
接下來分析dispatcher
5、Dispatcher
Dispatcher主要用於控制併發的請求,主要維護了以下變數
//最大併發請求數
private int maxRequests = 64;
//每個主機的最大請求數
private int maxRequestsPerHost = 5;
private @Nullable Runnable idleCallback;
/** Executes calls. Created lazily. */
//消費者執行緒池
private @Nullable ExecutorService executorService;
/** Ready async calls in the order they'll be run. */
//將要執行的非同步請求佇列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
//正在執行的非同步請求佇列
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
//正在執行的同步請求佇列
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
接下來看看Dispatche的構造方法
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
public Dispatcher() {
}
public synchronized ExecutorService executorService() {
if (executorService == null) {
//如果使用者沒有設定自己的執行緒池,自OKhttp初始化預設的執行緒池
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
Dispatcher有兩個構造方法,可以使用自己的執行緒池。如果沒有設定自己的執行緒池,則會設定預設的執行緒池。這個執行緒池類類似於CachedThreadPool,比較適合執行大量的耗時比較少的任務。
接下來看看Dispatcher的同步執行方法
/** Used by {@code Call#execute} to signal it is in-flight. */
synchronized void executed(RealCall call) {
//將請求新增到同步執行佇列
runningSyncCalls.add(call);
}
Dispatcher的非同步執行方法
synchronized void enqueue(AsyncCall call) {
/*當正在執行的非同步請求佇列中的數量小於64並且正在執行的請求主機數小於5時
把請求新增到runningAsyncCalls
否則,將請求新增到readyAsyncCalls
*/
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
接下來呼叫executorService().execute(call);,實際呼叫的是AsyncCall的execute方法,接下來分析
6、AsyncCal的execute方法
AsyncCall是RealCall的內部類,其內部也實現了execute方法,如下:
@Override protected void execute() {
boolean signalledCallback = false;
try {
//在這塊實現了網路請求,並返回Response
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);
}
}
}
可以看出,網路請求操作在Response response = getResponseWithInterceptorChain();
中執行
下面分析getResponseWithInterceptorChain()
7、RealCall.getResponseWithInterceptorChain()
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
//新增各種Interceptor
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, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
可以看出建立了RealInterceptorChain它是一個攔截器鏈,這個類也是RealCall的內部類,接下來執行它的proceed方法
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// If we already have a stream, confirm that the incoming request will use it.
if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must retain the same host and port");
}
// If we already have a stream, confirm that this is the only call to chain.proceed().
if (this.httpCodec != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
}
// Call the next interceptor in the chain.
//從攔截器中取出攔截器
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
// Confirm that the next interceptor made its required call to chain.proceed().
if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor
+ " must call proceed() exactly once");
}
// Confirm that the intercepted response isn't null.
if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
}
if (response.body() == null) {
throw new IllegalStateException(
"interceptor " + interceptor + " returned a response with no body");
}
return response;
}
攔截器的作用
來自官網的英文原文:
Interceptors are a powerful mechanism that can monitor, rewrite, and retry calls.
意思大概是,攔截器是一個強有力的機制,,它可以實現網路監聽、請求以及響應重寫、請求失敗重試等功能。
這裡不做過多分析,具體詳情可以看看這篇文章
https://blog.csdn.net/lepaitianshi/article/details/72457928
具體的網路請求已經在攔截器中實現
* CacheInterceptor實現快取管理*
@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.
}
// If we're forbidden from using the network and the cache is insufficient, fail.
//不進行網路請求,並且快取不存在,則返回504錯誤
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();
}
// If we don't need the network, we're done.
//如果不進行網路請求,而且快取可用,則直接返回快取
if (networkRequest == null) {
return cacheResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.build();
}
//請求網路
Response networkResponse = null;
try {
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.
//如果存在快取,並且伺服器沒有修改資料(networkResponse.code() == HTTP_NOT_MODIFIED),則返回快取
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());
}
}
//f否則進行網路請求
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;
}
如果快取存在而且沒有過期(伺服器返回資料為304),則返回響應,否則請求網路
這裡的快取均基於Map,key是請求中url的md5,value是檔案中查詢到的快取,頁面置換基於LRU演算法。
至此原始碼就分析到這,主要是攔截器鏈起作用,具體的話,可以看看這篇文章
https://blog.csdn.net/lepaitianshi/article/details/72457928