okhttp使用分为同步请求和异步请求:
异步请求:
String url = "";
Request request = new Request.Builder().get().url(url).build();
OkHttpClient okHttpClient = new OkHttpClient();
public void request(){
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
}
request是一个请求对像,包含了请求url,methord,heard等信息
okhttpclient 主要用于发送http请求以及读取回应
newcall方法主要是用于返回一个realcall对象,并且把请求对象request交给了realcall
@Override public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
接下来看一下realcall的enqueue
方法:
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
首先通过同步,确保call不会被重复执行(如果想要完全相同的call可以通过clone
方法),然后利用dispatcher
调度器来执行enqueue
方法,下面看一下dispatcher.enqueue
方法:
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
dispatcher就是一个异步请求是的策略,它里面包含了能同时进行的最大请求数(默认是64),同时请求相同host的最大数(默认是5),以及维护一个异步任务执行队列和一个异步任务等待队列,然后回来看dispatcher.enqueue
方法,首先会判断当前执行队列是不是超出最大请求数,以及同时访问相同host的数量是不是超过,如果超过就将call放入等待队列,否则放入执行队列,并且交给线程池去执行
执行的为AsyncCall,我们看一下AsyncCall的实现:
final class AsyncCall extends NamedRunnable {
AsyncCall继承自NamedRunnable,NamedRunnable其实是继承自Runnable,在他的run方法中会调用execute();
方法,说到底其实就是会执行AsyncCall的execute();
方法,接下来看一下AsyncCall的execute();
方法:
@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);
}
}
可以看到真正执行请求的是getResponseWithInterceptorChain()
,获取到response后回调给用户,值得注意的是最后finally,会通过调度器移除队列,并且判断如果执行队列没有达到最大值则把等待队列变为执行队列,这样就包证了等待队列的执行
下面我们看一下真正请求的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);
}
我们可以看到方法中首先创建一个拦截器的列表,添加各个拦截器,每个拦截器个自完成自己的任务,并且将不属于自己的任务交给下一个,这就是一种责任链模式,最后的执行是由chain.proceed(originalRequest);
来实现的,责任链中每个拦截器都会执行chain.proceed()方法之前的代码,等责任链最后一个拦截器执行完毕后会返回最终的响应数据,而chain.proceed() 方法会得到最终的响应数据,这时就会执行每个拦截器的chain.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 {
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);
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");
}
return response;
}
简述okhttp的执行流程:
- OkhttpClient 实现了Call.Fctory,负责为Request 创建 Call;
- RealCall 为Call的具体实现,其enqueue() 异步请求接口通过Dispatcher()调度器利用ExcutorService实现,而最终进行网络请求时和同步的execute()接口一致,都是通过 getResponseWithInterceptorChain() 函数实现
- getResponseWithInterceptorChain() 中利用 Interceptor 链条,责任链模式 分层实现缓存、透明压缩、网络 IO 等功能;最终将响应数据返回给用户。
网友评论