okhttp分析

2019-11-01  本文已影响0人  哇楼主

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的执行流程:

上一篇 下一篇

猜你喜欢

热点阅读