Android之OkHttp源码分析二请求流程

本文深入剖析OkHttp的主流程,从新建OkHttpClient对象、构建Request和RealCall,到异步网络请求的执行过程,包括ConnectionPool的连接管理、DiskLruCache的缓存整理及HTTP2的异步事务线程池。详细讲解了各个关键步骤的源码分析和工作原理。

目录

 

1.OkHttp主流程分析图

2.OkHttp主流程源码分析

2.1.OkHttp完整的请求示例

2.2.新建OkHttpClient对象,new OkHttpClient()

2.2.构建Request请求

2.3.构建RealCall

2.4执行异步网络请求call.enqueue(new Callback() {}

2.4.1.异步网络请求执行成功或者失败都会执行(client.dispatcher().finished(this); //2.4.1)

2.4.2.真正执行网络请求获取响应的调用(Response response = getResponseWithInterceptorChain())

2.5ConnectionPool-清除无用连接管理

2.6缓存整理线程池-DiskLruCache

2.7HTTP2异步事务线程池-OkHttp Http2Connection


1.OkHttp主流程分析图

a.在OkHttp3中,每一个请求任务都封装为一个Call,其实现为RealCall。
b.而所有的策略几乎都可以通过OkHttpClient传入
c.所有全局策略与数据,除了存储在允许上层访问的OkHttpClient实例以外,还有一部分是存储在只允许包可见的Internal.instance中(如连接池、路由黑名单等)
d.OkHttp中用户可传入的interceptor分为两类,一类是全局interceptor,该类interceptor在请求开始之前最早被调用,另外一类为非网页请求的networkInterceptor,这类interceptor只有在非网页请求中会被调用,并且是在组装完成请求之后,真正发起请求之前被调用(这块具体可以参看RealCall#getResponseWithInterceptorChain()方法)
e.整个请求过程通过RealInterceptorChain#proceed来连接,在每个interceptor中调用下一个interceptor来完成整个请求流程,并且在回到当前interceptor后完成响应处理
f.在异步请求中,我们通过Callback来获得简单清晰的请求回调(onFailure、onResponse)
g.在OkHttpClient中,我们可以传入EventListener的工厂方法,为每一个请求创建一个EventListener,来接收非常细的事件回调

2.OkHttp主流程源码分析

2.1.OkHttp完整的请求示例

public void asyncGet() throws IOException {
		//1.创建OkHttpClient客户端
		OkHttpClient okHttpClient = new OkHttpClient();
		//2.创建网络请求
		Request request = new Request.Builder()
				.url(https://blog.csdn.net/"http://www.baidu.com")
				.get()
				.build();
		//3.创建请求调用
		Call call = okHttpClient.newCall(request);
		//4.执行网络调用
		call.enqueue(new Callback() {
			
		public void onResponse(Call call, Response response) throws IOException                      {
				//网络请求成功
			}
			
			public void onFailure(Call call, IOException e) {
				//网络请求失败
			}
		});
	}

2.2.新建OkHttpClient对象,new OkHttpClient()

新建OkHttpClient对象时,内部主要初始化一些配置,支持那些的协议protocols,任务调度器Dispatcher(内部创建一个线程池,执行异步网络请求),连接池ConnectionPool(内部创建线程池,维护connection),连接/读取/写的超时时间等信息;

public OkHttpClient() {
    this(new Builder());
  }
public Builder() {
      dispatcher = new Dispatcher();    //任务调度器
      protocols = DEFAULT_PROTOCOLS;    //支持的那些协议
      connectionSpecs = DEFAULT_CONNECTION_SPECS;
      proxySelector = ProxySelector.getDefault();
      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;
      connectTimeout = 10_000;    //连接超时时间
      readTimeout = 10_000;
      writeTimeout = 10_000;
    }

新建Dispatcher任务调度器,主要初始化了双端队列readyAsyncCalls保存即将运行的异步请求,runningAsyncCalls保存正在运行的异步请求,runningSyncCalls保存正在运行的同步请求,

public final class Dispatcher {
  private int maxRequests = 64;    //支持最大的请求个数
  private int maxRequestsPerHost = 5;    //每台主机最大的请求数量
  private Runnable idleCallback;

  /** 线程池. 懒加载的方式创建. */
  private ExecutorService executorService;

  /** 即将按顺序运行异步调用。 */
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

  /** 保存正在运行的异步调用, 包含没有完成被取消的异步调用。 */
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

  /** 保存正在运行的同步调用。 包含没有完成被取消的调用。 */
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

  public Dispatcher(ExecutorService executorService) {
    this.executorService = executorService;
  }

  public Dispatcher() {
  }
  
  //需要执行的时候调用创建线程池
  public synchronized ExecutorService executorService() {
    if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }

executorService维护一套线程池,我们会发现在在调用enqueue()方法时,程序会把AsyncCall线程加入到线程池中执行,executorService无任务上线,自动回收闲置60s的线程,适合大量较短的异步任务,Dispatcher对线程数有数量上的限制最多64个,每个机器最多的请求数5个;

调用RealCall.enqueue()会调用Dispatcher.enqueue()方法,每次执行请求处理会放在线程池执行,当请求完成以后会等待队列检测是否有未完成的请求任务,有则继续添加到线程池继续执行;

2.2.构建Request请求

public final class Request {
  private final HttpUrl url;    //请求的URL
  private final String method;    //请求方法,在Builder中可以默认值为GET
  private final Headers headers;    //请求Header
  private final RequestBody body;    //请求体中放的请求body,post请求会用到
  private final Object tag;          

  private volatile CacheControl cacheControl; // Lazily initialized.
}

2.3.构建RealCall

通过OkHttpClient和Request创建RealCall,Call call = okHttpClient.newCall(request);

 /**
   * Prepares the {@code request} to be executed at some point in the future.
   */
  @Override public Call newCall(Request request) {
    return new RealCall(this, request);
  }

  protected RealCall(OkHttpClient client, Request originalRequest) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client);
  }

将OkHttpClient和Request对象传入RealCall,同时会创建连接重试和重定向拦截器,拦截器是OkHttp的精髓,它是第一个调用系统拦截器,假如设置了全局拦截器new OkHttpClient.Builder().addInterceptor(interceptor),那么执行网络请求时则先调用全局拦截器,然后调用RetryAndFollowUpInterceptor拦截器,具体的调用顺序可以查看RealCall.getResponseWithInterceptorChain()方法;

2.4执行异步网络请求call.enqueue(new Callback() {}

RealCall只能被执行一次,重复执行的话会抛出异常throw new IllegalStateException("Already Executed");

@Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

client.dispatcher().enqueue(new AsyncCall(responseCallback))回调用Dispatcher.enqueque()方法将异步请求加入到线程池中,

  synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

接下来我们看看异步请求是如何实现的?

AsyncCall继承自NamedRunnable类,NamedRunnable实现了Runnable线程接口,它的作用主要有两个:

a.采用模版的方式将子类具体的执行放到execute()方法中

b.给线程设置线程的名字,方便查看线程的执行状态;

/**
 * Runnable implementation which always sets its thread name.
 */
public abstract class NamedRunnable implements Runnable {
  protected final String name;

  public NamedRunnable(String format, Object... args) {
    this.name = Util.format(format, args);
  }

  @Override public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
        //采用模版的方式将子类具体的执行放到execute()方法中
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }

  protected abstract void execute();
}
final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;
    //构造方法中主要设置响应回调
    private AsyncCall(Callback responseCallback) {
      super("OkHttp %s", redactedUrl().toString());
      this.responseCallback = responseCallback;
    }

    String host() {
      return originalRequest.url().host();
    }

    Request request() {
      return originalRequest;
    }

    RealCall get() {
      return RealCall.this;
    }

    @Override protected void execute() {
      boolean signalledCallback = false;
      try {
        //执行网络请求,返回响应
        Response response = getResponseWithInterceptorChain();    //2.4.2
        //当前请求已取消
        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) {
          // 不能执行回调两次
          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          //网络请求异常,回调返回成功信息和响应  
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        //不管请求成功或者失败,都执行finished()操作
        client.dispatcher().finished(this); //2.4.1
      }
    }
  }

2.4.1.异步网络请求执行成功或者失败都会执行(client.dispatcher().finished(this); //2.4.1)

主要理解finished()方法作用,移除双端队列中正在执行的调用(RealCall),promoteCalls()方法将驱动继续执行下一个调用加入到线程池中执行;

 void finished(AsyncCall call) {
    finished(runningAsyncCalls, call, true);
 } 
 private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
    int runningCallsCount;
    Runnable idleCallback;
    synchronized (this) {
      //正在执行的双端队列中移除刚刚执行的调用
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      //驱动继续执行未执行的调用
      if (promoteCalls) promoteCalls();
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }

    if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();
    }
  }
//驱动继续执行未执行的调用
private void promoteCalls() {
    if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
    if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
    //检查双端队列readyAsyncCalls是否有准备好的调用,有则readyAsyncCalls调用移除,加入到runningAsyncCalls正在执行的双端队列,将调用加入线程池中执行
    for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
      AsyncCall call = i.next();

      if (runningCallsForHost(call) < maxRequestsPerHost) {
        i.remove();
        runningAsyncCalls.add(call);
        executorService().execute(call);
      }

      if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
    }
  }

2.4.2.真正执行网络请求获取响应的调用(Response response = getResponseWithInterceptorChain())

private 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 (!retryAndFollowUpInterceptor.isForWebSocket()) {
      //非网页请求拦截器,可以多个(开发人员自己添加)
      interceptors.addAll(client.networkInterceptors());
    }
    //调用执行网络请求拦截器
    interceptors.add(new CallServerInterceptor(
        retryAndFollowUpInterceptor.isForWebSocket()));
  
    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    //执行拦截
    return chain.proceed(originalRequest);
  }

首先创建interceptors列表,添加全局拦截器,然后添加retryAndFollowUpInterceptor,BridgeInterceptor,CacheInterceptor,ConnectInterceptor,networkInterceptors,CallServerInterceptor一系列拦截器,将拦截器列表放入new RealInterceptorChain(interceptors, null, null, null, 0, originalRequest)类中,调用RealInterceptorChain.proceed()执行网络请求;

  public Response proceed(Request request, StreamAllocation streamAllocation, HttpStream httpStream,
      Connection connection) throws IOException {
    ...
    // 创建即将调用的下一个拦截器链
    RealInterceptorChain next = new RealInterceptorChain(
        interceptors, streamAllocation, httpStream, 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 (httpStream != 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;
  }

//2.4.3.第一个系统拦截器RetryAndFollowUpInterceptor(连接重试和重定向处理)

//2.4.4.第二系统拦截器BridgeInterceptor(桥接连接器,主要处理请求头)

2.5ConnectionPool-清除无用连接管理

ConnectionPool为了缩减网络延时而用于管理复用HTTP和HTTP/2连接;共享一个地址Address的HTTP请求可以共享一个连接Connection;这个类实现了一个策略,保持连接打开状态为了将来使用;

1)线程池

后台线程将被使用去清除过期的连接。每个连接都最多只运行一个线程。线程池执行器允许池本身存在垃圾收集。

private static final Executor executor = new ThreadPoolExecutor(0 /* corePoolSize */,
      Integer.MAX_VALUE /* maximumPoolSize */, 60L /* keepAliveTime */, TimeUnit.SECONDS,
      new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp ConnectionPool", true));

a.该线程池用来清理长时间空闲和泄漏的连接;

b.该线程池无任务上线,线程闲置60s自动回收;

c.虽然任务无上限,但其通过cleanupRunning标记只有一个线程在运行,当连接池没有连接后才会重新设置为false;

2)加入连接

void put(RealConnection connection) {
    assert (Thread.holdsLock(this));
    if (!cleanupRunning) {
      cleanupRunning = true;
      executor.execute(cleanupRunnable);
    }
    connections.add(connection);
  }

a.工作线程会不断地清理,当清理完一遍后超时连接后,根据当前连接池中最近的下一个空闲超时连接计算出一个阻塞时间并阻塞,直到连接池中没有任何连接才结束,并将 cleanupRunning 设为 false;

b.在每次有连接加入连接池时,如果当前没有清理任务执行,会加入一个清理任务到线程池中执行;

2.6缓存整理线程池-DiskLruCache

/** This cache uses a single background thread to evict entries. */
    private final ExecutorService executorService = new ThreadPoolExecutor(0, 1,
            60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());

a.该线程池用于整理本地请求缓存数据;
b.缓存的整理包含: 达到阀值大小的文件,删除最近最少使用的记录,在有关操作达到一定数量以后对记录进行重建;
c.最大运行线程数1,无需考虑线程安全问题,自动回收闲置60s的线程;

2.7HTTP2异步事务线程池-OkHttp Http2Connection

a.HTTP2采用了多路复用,因此需要维护连接有效性,本线程池就是用于维护相关的各类HTTP2事务;
b.线程池本身无任务上限,自动回收闲置60s的线程;
c.每一个HTTP2连接都有这么一个线程池存在;

 

参考:

https://www.jianshu.com/p/9deec36f2759

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值