OkHttp是我们日常开发过程中最常用的第三方库;用来发送网络请求,并读取相应返回数据;
简单的步骤
private final OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(5, TimeUnit.SECONDS) //5秒钟
.callTimeout(5, TimeUnit.SECONDS).build();
Request request = new Request.Builder().get().url(url)
.build();
//异步
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
String string = response.body().string();
Logger.e(string);
}
});
Request:一个Http请求;主要包含url、method、headers、body、tags五部分;
url:统一资源定位器;
method:get、post、 head 、delete、 put、 patch几种类型;
headers:头信息;可根据具体情况添加,一般为通用的信息会加在Headers中,如token,手机相关的信息、Cache-Control(缓存控制)等;
body:get、head 不能有body,其他几种请求方法必须有body,不能为null;
tags:可以为任何object对象作为key;
cacheControl:通过设置设置缓存事件,来决定
OkHttpClient:设置的参数比较多,常用的有:拦截器,缓存,连接时间,超时等;
Response:包含request、code、body、sentRequestAtMillis、receivedResponseAtMillis;
OkHttp的newCall()方法:准备执行网络请求;
@Override
public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
RealCall是Call的实现类,主要方法是enqueue():异步请求方法,execute():同步请求方法;
Callback是回调,只有两个方法onFailure()由于被取消了,超时等情况,onResponse():远程服务器成功返回HTTP响应时调用,可能是200,或者404,500等;
发送请求
异步请求OkHttp的enqueue();
@Override
public void enqueue(Callback responseCallback) {
//只能执行一次;
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
//主要调用方法
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
Dispatcher类:异步请求何时请求的策略;使用线程池(其核心线程数为0,最大线程数为Integer最大值,线程保活时间为60秒)执行call;但是Dispatcher同一时间内允许的最大并发请求数为64;
RealCall的内部类AsyncCall是Runnable,在run()方法中定义了一个抽象方法execute();
Dispatcher的enqueue():将回调加入准备执行的异步回调队列(先进先出);
//准备执行的异步回调(将要执行)
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
//正在执行的异步回调(还没有完成)
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
//正在执行的同步回调(还没有完成)
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
void enqueue(AsyncCall call) {
//加入准备执行的异步回调队列(先进先出);
synchronized (this) {
readyAsyncCalls.add(call);
}
promoteAndExecute();
}
Dispatcher类的promoteAndExecute():遍历readyAsyncCalls队列取出对应的回调,加入到可执行的executableCalls中,依次执行;
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
List<AsyncCall> executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
//遍历readyAsyncCalls队列取出对应的回调
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();
//判断是否达到最大并发请求数;
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
//判断是否达到最大并发主机名(域名)数
if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.
//从readyAsyncCalls队列中删除,加入executableCalls和runningAsyncCalls中;
i.remove();
executableCalls.add(asyncCall);
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
//executorService()获取线程池对象;
asyncCall.executeOn(executorService());
}
return isRunning;
}
RealCall的内部类AsyncCall类的executeOn():线程池执行runnable,执行发送请求的方法,run()方法调用execute()方法;
void executeOn(ExecutorService executorService) {
boolean success = false;
try {
//线程池执行runnable;
executorService.execute(this);
success = true;
} catch (RejectedExecutionException e) {
} finally {
if (!success) {
client.dispatcher().finished(this); // This call is no longer running!
}
}
}
RealCall的内部类AsyncCall类的execute():请求得到响应,回调Callback的方法;
@Override protected void execute() {
boolean signalledCallback = false;
timeout.enter();
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) {
} finally {
client.dispatcher().finished(this);
}
}
}
RealCall类getResponseWithInterceptorChain():获取所有的拦截器,形成链;在下面的这段代码中可以很清晰的看到自定义的拦截器是添加在最前面的;
Response getResponseWithInterceptorChain() throws IOException {
//获取所有的拦截器;
List<Interceptor> interceptors = new ArrayList<>();
//OkHttpClient通过addInterceptor()添加的自定义拦截器;
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类proceed(): 责任链模式;当前处理者持有下一个处理者的引用,发现当前请求不再自己的处理范围,将请求传递给下一个处理者来处理,依次类推;
@Override
public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpCodec, connection);
}
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec, RealConnection connection) throws IOException {
calls++;
//调用下一个拦截器;
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,writeTimeout);
//获取当前index的拦截器,获取顺序和RealCall类getResponseWithInterceptorChain()添加顺序一直;
Interceptor interceptor = interceptors.get(index);
//调用具体拦截器类的intercept(),并且传入下一个拦截,构成责任链;
Response response = interceptor.intercept(next);
return response;
}
拦截器
拦截器可以自定义实现;OKhttp提供了几种拦截器
RetryAndFollowUpInterceptor(重定向拦截器);
BridgeInterceptor(桥梁拦截器);
CacheInterceptor(缓存拦截器);
ConnectInterceptor(拦截拦截器);
CallServerInterceptor(调用服务器拦截器);
RetryAndFollowUpInterceptor
RetryAndFollowUpInterceptor(重定向拦截器)的intercept();
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Call call = realChain.call();
EventListener eventListener = realChain.eventListener();
//StreamAllocation协调Connection、Streams、Calls三个实体的关系;
//client.connectionPool():连接池在ConnectInterceptor会详细说明;
StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),
createAddress(request.url()), call, eventListener, callStackTrace);
this.streamAllocation = streamAllocation;
int followUpCount = 0;
Response priorResponse = null;
while (true) {
Response response;
boolean releaseConnection = true;
try {
//将请求传递到下一个拦截器BridgeInterceptor;最终都会释放资源;
response = realChain.proceed(request, streamAllocation, null, null);
releaseConnection = false;
} finally {
streamAllocation.streamFailed(null);
streamAllocation.release();
}
Request followUp;
try {
//找到Response的Http请求,添加身份验证头、遵循重定向或处理客户端请求超时;
followUp = followUpRequest(response, streamAllocation.route());
} catch (IOException e) {
streamAllocation.release();
throw e;
}
if (followUp == null) {
streamAllocation.release();
return response;
}
}
}
BridgeInterceptor
BridgeInterceptor从应用程序代码到网络代码的桥梁。首先,它从用户请求构建网络请求。然后它继续调用网络。最后从网络响应构建用户响应。
BridgeInterceptor的intercept():主要是在header中加一些属性;
@Override
public Response intercept(Chain chain) throws IOException {
Request userRequest = chain.request();
Request.Builder requestBuilder = userRequest.newBuilder();
RequestBody body = userRequest.body();
//主要是在header中加一些属性;
........
//将请求传递到下一个拦截器CacheInterceptor;
Response networkResponse = chain.proceed(requestBuilder.build());
Response.Builder responseBuilder = networkResponse.newBuilder()
.request(userRequest);
return responseBuilder.build();
}
CacheInterceptor
CacheInterceptor主要的实现在Cache类中,内部采用DiskLruCache保存缓存,根据请求的url获取对应的Response;只有get请求才能缓存response,其他请求不缓存response;
InternalCache:OkHttp的缓存接口;
Cache:缓存对文件系统的HTTP和HTTPS响应,以便可以重用它们;初始化InternalCache接口;以DiskLruCache为原理实现缓存功能;
DiskLruCache:内部以LinkedHashMap实现的,具体可参考LinkedHashMap及其应用LruCache;
CacheControl:分为强制网络响应、强制缓存响应、缓存有效期;
CacheStrategy:给定一个请求和缓存的响应,确定是使用网络、缓存还是两者都使用。
CacheInterceptor的intercept()方法:根据url获取缓存的Response;再根据CacheControl来确定是使用缓存的response还是网络请求;
@Override public Response intercept(Chain chain) throws IOException {
//获取缓存,url对应的response,通过Cache类获取;
Response cacheCandidate = cache != null
? cache.get(chain.request())
: null;
long now = System.currentTimeMillis();
//CacheStrategy:给定一个请求和缓存的响应,决定是使用网络、缓存还是共同使用;
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 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();
}
//不需要网络;返回cacheResponse;
// If we don't need the network, we're done.
if (networkRequest == null) {
return cacheResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.build();
}
//将请求传递到ConnectInterceptor;
Response networkResponse = null;
try {
networkResponse = chain.proceed(networkRequest);
} finally {
// If we're crashing on I/O or otherwise, don't leak the cache body.
}
//如果我们也有缓存响应,那么我们就是在做一个条件get。
// If we have a cache response too, then we're doing a conditional get.
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();
cache.trackConditionalCacheHit();
//更新缓存
cache.update(cacheResponse, response);
return response;
} else {
closeQuietly(cacheResponse.body());
}
}
//返回网络请求的response;
Response response = networkResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
if (cache != null) {
//response中有body,并且是可被缓存的;缓存下当前response;
if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
// Offer this request to the cache.
CacheRequest cacheRequest = cache.put(response);
return cacheWritingResponse(cacheRequest, response);
}
//只有get请求才能缓存response,其他请求不缓存response;
if (HttpMethod.invalidatesCache(networkRequest.method())) {
try {
cache.remove(networkRequest);
} catch (IOException ignored) {
// The cache cannot be written.
}
}
}
return response;
}
ConnectInterceptor
ConnectInterceptor:打开到目标服务器的连接并继续到下一个拦截器;
@Override
public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Request request = realChain.request();
StreamAllocation streamAllocation = realChain.streamAllocation();
//是不是get请求;
boolean doExtensiveHealthChecks = !request.method().equals("GET");
//StreamAllocation协调Connection、Streams、Calls三个实体的关系;
HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
RealConnection connection = streamAllocation.connection();
//最后传递到CallServerInterceptor;
return realChain.proceed(request, streamAllocation, httpCodec, connection);
}
StreamAllocation的newStream():获取一个正常的连接(Connection),返回HttpCodec对象;
public HttpCodec newStream(
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();
try {
//找到正常的Connection;
RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,writeTimeout, pingIntervalMillis, connectionRetryEnabled, doExtensiveHealthChecks);
//返回一个HttpCodec对象;
HttpCodec resultCodec = resultConnection.newCodec(client, chain, this);
synchronized (connectionPool) {
codec = resultCodec;
return resultCodec;
}
} catch (IOException e) {
throw new RouteException(e);
}
}
StreamAllocation的findHealthyConnection():比较简单,不断的通过findConnection()方法获取一个RealConnection对象,判断其是正常可用的,则返回;
RealConnection:Connection接口的具体实现类;HTTP、HTTPS或HTTPS+HTTP/2连接的套接字和流。可用于多个HTTP请求/响应交换。连接可以直接到源服务器或通过代理。RealConnection的实例通常由HTTP客户机自动创建、连接和执行
ConnectionPoll:管理HTTP和HTTP/2连接(RealConnection)的重用,以减少网络延迟;共享相同地址的HTTP请求可以共享一个连接;默认最大容纳5个空闲连接,这些连接在5min内没有被复用,将被清除;
StreamAllocation的findConnection()返回Connection;如果连接池(ConnectionPoll)有对应的连接存在,直接复用连接池中的连接;不存在,就直接创建一个,在保存在连接池中,以备复用;
private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout, int pingIntervalMillis, boolean connectionRetryEnabled) throws IOException {
RealConnection result = null;
synchronized (connectionPool) {
if (this.connection != null) {
//有一个已经分配的连接;
result = this.connection;
releasedConnection = null;
}
if (result == null) {
//尝试从连接池中获取一个连接;具体在OkHttpClient的Internal.instance中;
Internal.instance.get(connectionPool, address, this, null);
if (connection != null) {
foundPooledConnection = true;
result = connection;
} else {
selectedRoute = route;
}
}
}
//找到一个RealConnection,返回;
if (result != null) {
return result;
}
//创建一个routeSelection;
boolean newRouteSelection = false;
if (selectedRoute == null && (routeSelection == null || !routeSelection.hasNext())) {
newRouteSelection = true;
routeSelection = routeSelector.next();
}
synchronized (connectionPool) {
//既然有了一组IP地址,再尝试从池中获取连接复用;
if (newRouteSelection) {
List<Route> routes = routeSelection.getAll();
for (int i = 0, size = routes.size(); i < size; i++) {
Route route = routes.get(i);
Internal.instance.get(connectionPool, address, this, route);
if (connection != null) {
foundPooledConnection = true;
result = connection;
this.route = route;
break;
}
}
}
//如果没有找到,则创建一个;
if (!foundPooledConnection) {
if (selectedRoute == null) {
selectedRoute = routeSelection.next();
}
route = selectedRoute;
refusedStreamCount = 0;
//创建一个Connection对象;
result = new RealConnection(connectionPool, selectedRoute);
acquire(result, false);
}
}
//第二次从连接池中找可复用的连接,返回;
if (foundPooledConnection) {
eventListener.connectionAcquired(call, result);
return result;
}
// TCP + TLS 握手;
result.connect(connectTimeout, readTimeout, writeTimeout, pingIntervalMillis,
connectionRetryEnabled, call, eventListener);
routeDatabase().connected(result.route());
Socket socket = null;
synchronized (connectionPool) {
reportedAcquired = true;
//放入连接池中,以备复用;
Internal.instance.put(connectionPool, result);
}
return result;
}
OkHttpClient的instance变量;
static {
Internal.instance = new Internal() {
//get()方法
@Override
public RealConnection get(ConnectionPool pool, Address address,
StreamAllocation streamAllocation, Route route) {
return pool.get(address, streamAllocation, route);
}
//put()方法
@Override
public void put(ConnectionPool pool, RealConnection connection) {
pool.put(connection);
}
}
- HttpCodec:编码HTTP请求并解码HTTP响应;
- Http1Codec/Http2Codec:都是HttpCodec的具体实现;
- RealResponseBody:ResponseBody的子类;响应体;
CallServerInterceptor
CallServerInterceptor(调用服务的拦截器):是链中的最后一个拦截器,对服务器进行网络调用。将请求的信息发送给服务器,接受并解码响应;
@Override
public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
//HttpCodec 编码HTTP请求并解码HTTP响应。
HttpCodec httpCodec = realChain.httpStream();
StreamAllocation streamAllocation = realChain.streamAllocation();
RealConnection connection = (RealConnection) realChain.connection();
Request request = realChain.request();
//发送请求的时间;
long sentRequestMillis = System.currentTimeMillis();
//编码请求头;
realChain.eventListener().requestHeadersStart(realChain.call());
//httpCodec的具体实现类为Http1Code、Http2Code;
httpCodec.writeRequestHeaders(request);
realChain.eventListener().requestHeadersEnd(realChain.call(), request);
Response.Builder responseBuilder = null;
//允许有body,并且body不为null;
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
if (responseBuilder == null) {
//写入body;
} else if (!connection.isMultiplexed()) {
streamAllocation.noNewStreams();
}
}
//编码请求完成;
httpCodec.finishRequest();
//解析响应头字节;
if (responseBuilder == null) {
realChain.eventListener().responseHeadersStart(realChain.call());
responseBuilder = httpCodec.readResponseHeaders(false);
}
//创建一个Response对象;
Response response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
//response的body为空;
if (forWebSocket && code == 101) {
response = response.newBuilder()
.body(Util.EMPTY_RESPONSE)
.build();
} else {
//把网络请求获取的stream,转换为ResponseBody添加到Response中;
response = response.newBuilder()
.body(httpCodec.openResponseBody(response))
.build();
}
return response;
}
到此,一个网络请求就结束了,获取到了我们需要的内容Response的body;
问题一:那我们如果需要中断某个网络请求,该怎么办呢?
Dispatcher的三个AsyncCall队列,存储准备执行的AsyncCall和将要执行的AsyncCall;通过Requestd的tag值,找到对应的Call取消网络请求;
public void CancelCall(Object tag) {
Dispatcher dispatcher = client.dispatcher();
//准备执行的
for (Call call : dispatcher.queuedCalls()) {
if (tag.equals(call.request().tag())) {
call.cancel();
}
}
//即将执行的
for (Call call : dispatcher.runningCalls()) {
if (tag.equals(call.request().tag())) {
call.cancel();
}
}
}
以上就是OkHttp源码的主要分析,如有问题,请多指教,谢谢!