OKHttp调用流程及源码分析

一、网络框架对比

1、android-async-http

基于HttpClient进行封装的网络请求库,由于Android在6.0的时候已经不再推荐使用HttpClient了,所以这个库也就不适合作为我们网络框架的选择了。

2、volley

13年Google发布的网络框架,是基于HttpUrlConnection进行网络请求的轻量级框架,扩展性好,可支持HttpClient/HttpUrlConnection/OKHttp。缺点有二,其一是不支持同步请求。其二是不支持大数据量操作,比如文件上传下载。
它比较适合轻量级网络交互,网络请求频繁,传输数据量小的场景。
为什么Volley不适合大数量的传输操作呢?
Volley中为了提高请求处理的速度,采用了ByteArrayPool进行内存中的数据存储的,如果下载大量的数据,这个存储空间就会溢出,所以不适合大量的数据,但是由于他的这个存储空间是内存中分配的,当存储的时候优是从ByteArrayPool中取出一块已经分配的内存区域, 不必每次存数据都要进行内存分配,而是先查找缓冲池中有无适合的内存区域,如果有,直接拿来用,从而减少内存分配的次数 ,所以他比较适合大量的数据量少的网络数据交互情况。

3、OKHttp

是高性能的http库,支持同步、异步,而且实现了http2、websocket协议,api很简洁易用,和volley一样实现了http协议的缓存。picasso就是利用okhttp的缓存机制实现其文件缓存,实现的很优雅,很正确,反例就是UIL(universal image loader),自己做的文件缓存,而且不遵守http缓存机制。另外在Android6.0的源码里,已经看到HttpUrlConnection被替换成OKHttp了。

4、Retrofit

OKHttp的再次封装,通过注解配置请求,包括请求方法、请求参数、请求头、返回值等。可以搭配多种Converter将获得的数据解析&序列化。简单易用;代码简化;解耦彻底,职责细分;易与和rxjava结合使用。

二、OKHttp源码分析

分析源码前,从使用入手,追踪调用代码。使用如下:

// 通过Builder模式创建OkHttpClient对象
OkHttpClient client = new OkHttpClient.Builder().build();
// 通过Builder模式创建Request对象
Request request = new Request.Builder().url("").build();
// 创建Call对象
Call call = client.newCall(request);
	try {
		// 同步请求
		call.execute();
	} catch (IOException e) {
	}
	// 异步请求
	call.enqueue(new Callback() {
		@Override
		public void onFailure(Call call, IOException e) {
		}
		
		@Override
		public void onResponse(Call call, Response response) throws IOException {

		}
});
1、创建OKHttpClient的过程
// OKHttpClient类的静态内部类Builder
public static final class Builder {
public Builder() {
      dispatcher = new Dispatcher(); // 调度器
      protocols = DEFAULT_PROTOCOLS;
      connectionSpecs = DEFAULT_CONNECTION_SPECS;
      eventListenerFactory = EventListener.factory(EventListener.NONE);
      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; // 写的超时时间
      pingInterval = 0;
    }
    // build方法
	public OkHttpClient build() {
	  // 创建一个OKHttpClient,并把当前的Builder对象传进去 
      return new OkHttpClient(this);
    }
}

// OkHttpClient的构造方法
// 其实就是把Builder里的值赋值到OkHttpClient的成员变量里
OkHttpClient(Builder builder) {
    this.dispatcher = builder.dispatcher;
    this.proxy = builder.proxy;
    this.protocols = builder.protocols;
    this.connectionSpecs = builder.connectionSpecs;
    this.interceptors = Util.immutableList(builder.interceptors);
    this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
    this.eventListenerFactory = builder.eventListenerFactory;
    this.proxySelector = builder.proxySelector;
    this.cookieJar = builder.cookieJar;
    this.cache = builder.cache;
    this.internalCache = builder.internalCache;
    this.socketFactory = builder.socketFactory;
    this.hostnameVerifier = builder.hostnameVerifier;
    this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
        certificateChainCleaner);
    this.proxyAuthenticator = builder.proxyAuthenticator;
    this.authenticator = builder.authenticator;
    this.connectionPool = builder.connectionPool;
    this.dns = builder.dns;
    this.followSslRedirects = builder.followSslRedirects;
    this.followRedirects = builder.followRedirects;
    this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
    this.connectTimeout = builder.connectTimeout;
    this.readTimeout = builder.readTimeout;
    this.writeTimeout = builder.writeTimeout;
    this.pingInterval = builder.pingInterval;
  }
2、创建Request的过程
// Request类的静态内部类Builder类
// 和OKHttpClient没有什么不同,都是基于构造者模式来设置参数
// Request要设置的参数包括URL、Method、Header、Body请求相关的
public static class Builder {
    HttpUrl url;
    String method;
    Headers.Builder headers;
    RequestBody body;
    Object tag;

    public Builder() {
      this.method = "GET";
      this.headers = new Headers.Builder();
    }
	
    public Builder url(HttpUrl url) {
      if (url == null) throw new NullPointerException("url == null");
      this.url = url;
      return this;
    }
}
3、Call对象创建过程
// OKHttpClient类的newCall方法
@Override public Call newCall(Request request) {
    return new RealCall(this, request, false /* for web socket */);
}
// RealCall类
final class RealCall implements Call {
	RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    	final EventListener.Factory eventListenerFactory = client.eventListenerFactory();

    	this.client = client;
    	this.originalRequest = originalRequest;
    	this.forWebSocket = forWebSocket;
    	this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);

    	// TODO(jwilson): this is unsafe publication and not threadsafe.
    	this.eventListener = eventListenerFactory.create(this);
 	 }
}
4、同步的excute方法执行
// RealCall类的excute方法
@Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    try {
      // (1)最终调用Dispatcher类的executed方法
      client.dispatcher().executed(this);
      // (2)拦截器,核心
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } finally {
      // (3)最终调用Dispatcher的finished方法
      client.dispatcher().finished(this);
    }
  }
public final class Dispatcher {
  // 最大并发的请求数
  private int maxRequests = 64;
  // 每个host最大的请求数
  private int maxRequestsPerHost = 5;
  // 线程池
  private @Nullable ExecutorService executorService;

  // 双向队列,存储还未运行的异步队列
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

 // 双向队列,存储正在运行的异步任务
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

  // 双向队列,存储正在运行的同步任务
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

	// 上面(1)处最终调用的是这个方法,没做别的事,
	// 就是把这个任务添加到正在运行的同步任务双向队列里
  	synchronized void executed(RealCall call) {
    	runningSyncCalls.add(call);
  	}
}

(2)和(3)在下面的异步调用源码处统一分析

5、同步的enqueue方法执行
// RealCall类的enqueue方法
@Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    // 最终调用Dispatcher的enqueue方法
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
public final class Dispatcher {
  // 最大并发的请求数
  private int maxRequests = 64;
  // 每个host最大的请求数
  private int maxRequestsPerHost = 5;
  // 线程池
  private @Nullable ExecutorService executorService;

  // 双向队列,存储还未运行的异步队列
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

 // 双向队列,存储正在运行的异步任务
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

  // 双向队列,存储正在运行的同步任务
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
	// 异步调用的方法
	synchronized void enqueue(AsyncCall call) {
		// 运行的异步任务小于最大的并发请求数 
		// 并且,同一个主机的请求数小于5,也就是同时请求同一个域名的最大并发数是5
	    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
	     // 把任务添加到正在运行的异步队列里
	      runningAsyncCalls.add(call);
	      // 调用线程池的execute方法,把call放进去
	      executorService().execute(call);
	    } else {
	    	// 把任务添加到未运行的异步队列里
	      	readyAsyncCalls.add(call);
	    }
 	 }
}
// AsyncCall类实现了Runnable
// 所以线程池回调就是这个execute方法
final class AsyncCall extends NamedRunnable {
	@Override
	protected void execute() {
      boolean signalledCallback = false;
      try {
        // 上面(2)所说的拦截器方法,核心 
        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 {
        // 上面(3)所说的方法
        client.dispatcher().finished(this);
      }
    }
}
// (2)的方法实现
Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    // 我们平常设置的拦截器,就是在这
    interceptors.addAll(client.interceptors());
    // 重试和重定向拦截器,主要负责网络失败重连。
    interceptors.add(retryAndFollowUpInterceptor);
    // 桥拦截器,负责把用户构造的请求转换为发送给服务器的请求,把服务器返回的响应转换为对用户友好的响应
    // 比如在Request阶段配置用户信息,并添加一些请求头。在Response阶段,进行gzip解压
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    // 缓存拦截器,OKHttp有自己的缓存体系,这个拦截器用于读取和更新缓存
    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);
    // 调用RealInterceptorChain的proceed方法
    return chain.proceed(originalRequest);
}

// RealInterceptorChain类
public final class RealInterceptorChain implements Interceptor.Chain {
	// proceed方法
	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.
    // 又创建了下一个的Chain对象,下标的初始值是index+1
    RealInterceptorChain next = new RealInterceptorChain(
        interceptors, streamAllocation, httpCodec, connection, index + 1, request);
    // 获取第index个拦截器,执行这个拦截器的intercept方法
    // 我们假设目前index=0,即将执行retryAndFollowUpInterceptor的intercept方法
    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;
  }
}

// 网络重试重定向的拦截器
public final class RetryAndFollowUpInterceptor implements Interceptor {
	@Override 
	public Response intercept(Chain chain) throws IOException {
	   	   ...
	   	   ...
	      Response response = null;
	      boolean releaseConnection = true;
	      try {
	      // 这里的chain就是上面创建的下一个的Chain对象,因此又回到上面的proceed方法
	      // 责任链模式实现了循环的调用不同的拦截器
	        response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);
	        releaseConnection = false;
	      } catch (RouteException e) {
	      }
	}
}

getResponseWithInterceptorChain方法, 可以看出真正请求执行的就在这一块, 根据责任链的设计思想, 将操作分开进行处理。
拦截器流程

// 接着来看看上面说的(3)
// Dispatcher类
/** Used by {@code AsyncCall#run} to signal completion. */
  void finished(AsyncCall call) {
    finished(runningAsyncCalls, call, true);
}
// finished方法,异步的情况下,promoteCalls=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!");
      // 如果是异步任务,就会执行promoteCalls方法
      if (promoteCalls) promoteCalls();
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }

    if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();
    }
}

// promoteCalls方法,这个方法实际上作用就是从等待队列里拿任务出来去执行
private void promoteCalls() {
    if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
    if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
	// 遍历等待队列
    for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
      AsyncCall call = i.next();
	  // 判断同一个域名的请求数是否小于5
      if (runningCallsForHost(call) < maxRequestsPerHost) {
        // 从等待队列里移除这个任务
        i.remove();
        // 添加到运行中的队列
        runningAsyncCalls.add(call);
        // 放到线程池里执行
        executorService().execute(call);
      }
      if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
    }
}

至此,OKHttp的主流程已分析完毕,盗个图来总结一下流程:
OKHttp流程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值