okhttp详解之调用流程分析

okhttp调用流程分析

在这里插入图片描述
Android 在6.0之后也将内部的HttpUrlConnection的默认实现替换成了OkHttp
简单调用

OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url("https://www.google.com").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 {
    }
});

步骤分析(上述为异步过程分析)
观察调用流程,分析主要类
1、OkHttpClient:核心类,构建者模式实现,相当于访问门户
2、RealCall:负责请求调度,Call的实现类,同步异步请求都是它实现,其中AsyncCall是它的内部类,五大内部拦截器也在这儿被调用,通过责任链模式组织了拦截器的使用
3、Dispatcher:封装了关于何时执行异步请求的策略,并设置了最大请求数setMaxRequests(int maxRequests),可配置,每个调度程序都使用线程池来完成该任务
4、TheadPoolExecutor:线程池,为任务执行时原动力

一、分析OkHttpClient(专用于发送http请求,并接收返回的一个类)
每个客户端都拥有自己的连接池和线程池。 重用连接和线程可减少延迟并节省内存。 相反,为每个请求创建一个客户端会浪费空闲池上的资源,OkHttpClients should be shared,所以请使用单例模式
OkHttp 还使用守护线程进行 HTTP/2 连接,如果它们保持空闲,它们将自动退出
OkHttpClient默认构造器参数如下:
OkHttpClient client = new OkHttpClient();

public Builder() {
  dispatcher = new Dispatcher();
  protocols = DEFAULT_PROTOCOLS;
  connectionSpecs = DEFAULT_CONNECTION_SPECS;
  eventListenerFactory = EventListener.factory(EventListener.NONE);
  proxySelector = ProxySelector.getDefault();
  if (proxySelector == null) {
    proxySelector = new NullProxySelector();
  }
  cookieJar = CookieJar.NO_COOKIES;
  socketFactory = SocketFactory.getDefault();
  hostnameVerifier = OkHostnameVerifier.INSTANCE;
  certificatePinner = CertificatePinner.DEFAULT;
  proxyAuthenticator = Authenticator.NONE;
  authenticator = Authenticator.NONE;
  connectionPool = new ConnectionPool();
  dns = Dns.SYSTEM;
  followSslRedirects = true;
  followRedirects = true;
  retryOnConnectionFailure = true;
  callTimeout = 0;
  connectTimeout = 10_000;
  readTimeout = 10_000;
  writeTimeout = 10_000;
  pingInterval = 0;
}

采用的是构建者模式,独立,易扩展,对于参数较多的构造器,比较方便,可以选择想要使用的功能,其余可默认,缺点就是通过内部静态类实现,需要有共同的参数,使用范围有限制,而且如果需求变化多端,就需要不同的构造器实现

二、RealCall
Call call = client.newCall(request);

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;
}

主要是把调用放入到eventListener中以此来监听,指标事件的监听器, 扩展此类可用于监视应用程序 HTTP 调用的数量、大小和持续时间,包括(网络请求次数、流量大小、DNS解析时间、请求、响应时间等)
call.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));
}

// Guarded by this.
executed:用于判断当前请求有无被执行,且只能被执行一次
captureCallStackTrace():捕获执行此方法时的堆栈信息,也就是获取Throwable中的信息,用于RetryAndFollowUpInterceptor,从故障中恢复并根据需要遵循重定向
client.dispatcher().enqueue(new AsyncCall(responseCallback)):AsyncCall是RealCall的一个非静态内部类,并且是个Runnable类,Dispatcher将runnable放入了readyAsyncCalls中,按照它们将运行的顺序准备好异步调用 (先看下面的三、Dispatcher如何进行调度)

asyncCallTask:

void executeOn(ExecutorService executorService) {
  assert (!Thread.holdsLock(client.dispatcher()));
  boolean success = false;
  try {
    executorService.execute(this);
    success = true;
  } catch (RejectedExecutionException e) {
    InterruptedIOException ioException = new InterruptedIOException("executor rejected");
    ioException.initCause(e);
    eventListener.callFailed(RealCall.this, ioException);
    responseCallback.onFailure(RealCall.this, ioException);
  } finally {
    if (!success) {
      client.dispatcher().finished(this); // This call is no longer running!
    }
  }
}

**executorService.execute(this);**内部封装线程池,其实现类为ThreadPoolExecutor,先看execute调用,实际调用的是RealCall本身的execute()方法

@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) {
    e = timeoutExit(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();**经过各种拦截器后将结果返回,其中包括
失败和重定向拦截器---------------retryAndFollowUpInterceptor
封装request和response拦截器-------BridgeInterceptor
缓存相关的过滤器负责读取缓存直接返回、更新缓存------CacheInterceptor
连接服务,负责和服务器建立连接拦截器-------ConnectInterceptor
具体执行流操作(写出请求体、获得响应数据) 负责向服务器发送请求数据、从服务器读取响应数据、进行http请求报文的封装与请求报文的解析------------CallServerInterceptor

if (retryAndFollowUpInterceptor.isCanceled()) {
  signalledCallback = true;
  responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
  signalledCallback = true;
  responseCallback.onResponse(RealCall.this, response);
}

分别将返回后的结果判断后回调返回,根据retryAndFollowUpInterceptor.isCanceled()判断,在任务被取消或者异步超时时会被设置为true

三、Dispatcher
client.dispatcher().enqueue(new AsyncCall(responseCallback));

void enqueue(AsyncCall call) {
  synchronized (this) {
    readyAsyncCalls.add(call);
  }
  promoteAndExecute();
}

将call加入到readyAsyncCalls中,一个支持两端元素插入和移除的线性集合,也就是队列结构,实现类是数组形式
promoteAndExecute():将符合条件的调用从 {@link #readyAsyncCalls} 提升到 {@link #runningAsyncCalls} 并在执行程序服务上运行它们。 不得与同步调用,因为执行调用可以调用用户代码

 private boolean promoteAndExecute() {
   assert (!Thread.holdsLock(this));
   
   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 (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.
       
       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);
     asyncCall.executeOn(executorService());
   }
   
   return isRunning;
 }

**assert (!Thread.holdsLock(this));**用于断言观察线程是否持有当前对象的锁,为了保证在执行下面的代码时是未上锁的
if (runningAsyncCalls.size() >= maxRequests) break; 判断异步运行中的请求的最大队列数量,默认值为64,表示能够同时运行的最大调用数量为64
if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; 最大请求的host数量为5个,即共享主机的正在运行的调用数最大数量为5
综合上述这两种判断,将符合条件的调用从准备队列中移除 i.remove(),并将其加入到executableCalls与runningAsyncCalls中,其中executableCalls相当于一个暂存区,用于迭代执行其中保存的异步任务
**asyncCall.executeOn(executorService());**将异步任务加入线程池中执行,跳转到RealCall中的asyncCallTask标签
goto asyncCallTask;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值