Okhttp3源码浅析

发起一个简单的Okhttp请求:

OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
        
Request request = new Request
                .Builder()
                .url("https://www.baidu.com")
                .build();
okhttp3.Call call = okHttpClient.newCall(request);
 
同步请求
//call.execute();

//异步请求
 call.enqueue(new Callback() {
      @Override
       public void onFailure(Call call, IOException e) {
           Log.e("tag", "请求失败");
           e.printStackTrace();
       }

       @Override
       public void onResponse(Call call, Response response) {
           Log.e("tag", "请求成功");
       }
 });

构建Okhttp的几个基础类:
Request:请求方法、请求头、参数、请求体等基础参数的封装类
OkhttpClient:用于构建Call请求的工厂类,用于配置请求如超时时间、缓存、https证书验证、拦截器等,内部还封装了用于分发请求的Dispatcher类、Socket工厂类、Socket连接池等。
Call:请求的发起、取消、结果返回、状态回调,是Okhttp请求的控制类

Okhttp请求执行的基本流程如下图:
在这里插入图片描述

同步请求

Call的实现类RealCall调用execute()发起同步请求,接着调用getResponseWithInterceptorChain()方法获取同步响应结果,此方法的具体实现后面统一分析

 @Override
 public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    transmitter.timeoutEnter();
    transmitter.callStart();
    try {
      client.dispatcher().executed(this);
      return getResponseWithInterceptorChain();
    } finally {
      client.dispatcher().finished(this);
    }
  }
异步请求

RealCall调用enqueue()方法发起异步请求,实际上是通过其内部保存的OkhttpClient引用,获取到请求分发器Dispacher,创建RealCall的内部类AsyncCall对象(其实是一个Runnable对象),添加到请求队列中

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

接下来看一下Dispatcher中的实现,它内部封装了线程池、待执行的、执行中的同步/异步请求队列以及请求数量的限制条件

public final class Dispatcher {
	  private int maxRequests = 64;
	  private int maxRequestsPerHost = 5;
	  private @Nullable Runnable idleCallback;
	
	  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<>();
	
	  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<>(), Util.threadFactory("OkHttp Dispatcher", false));
	    }
	    return executorService;
	  }
	  
	  //添加请求到待执行队列
	  void enqueue(AsyncCall call) {
	    synchronized (this) {
	      readyAsyncCalls.add(call);
	
	      // Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
	      // the same host.
	      if (!call.get().forWebSocket) {
	        AsyncCall existingCall = findExistingCallWithHost(call.host());
	        if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
	      }
	    }
	    promoteAndExecute();
	  }

	  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();
		        //最大支持同时64个异步请求
		        if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
		        //同一host下最大支持同时5个异步请求
		        if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
		
		        i.remove();
		        //统计同一host下同时请求个数
		        asyncCall.callsPerHost().incrementAndGet();
		        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;
	  }
	 ......
 }

接着看异步请求的执行流程,上述代码第30行Dispatcher调用enqueue()方法将AsyncCall添加到待执行的请求队列,第41行调用promoteAndExecute()真正将请求添加到线程池执行。

从方法内部可以看到Okhttp对于并发数量是有限制的,最大同时执行的请求数量为64个,同一host下最多可以同时执行5个请求。

最后遍历可执行的请求,逻辑从Dispatcher类中切换到AsyncCall中,AsyncCall本身又是一个Runnable,它的最终执行逻辑一定是在run()方法中实现的,跟踪代码可以看到它的逻辑切换流程executeOn(executorService) --> run() --> execute()

@Override
protected void execute() {
      boolean signalledCallback = false;
      transmitter.timeoutEnter();
      try {
        //发起请求返回响应结果
        Response response = getResponseWithInterceptorChain();
        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);
      }
 }

这里的代码和同步请求RealCall中execute()非常相似,同样是调用getResponseWithInterceptorChain()获取响应结果,只不过异步请求的Response回调执行在子线程中。

拦截器(Interceptor)

无论是同步请求还是异步请求都是调用getResponseWithInterceptorChain()获取响应结果,方法命名很直观,通过拦截器链来获取响应。

  Response getResponseWithInterceptorChain() throws IOException {
    //将各种拦截器添加到集合
    List<Interceptor> interceptors = new ArrayList<>();
    //添加自定义的请求拦截器
    interceptors.addAll(client.interceptors());
    //添加失败重试和重定向拦截器
    interceptors.add(new RetryAndFollowUpInterceptor(client));
    //添加网络桥拦截器,用户添加默认的请求头等信息
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    //添加缓存拦截器
    interceptors.add(new CacheInterceptor(client.internalCache()));
    //添加连接拦截器,给当前请求创建或者从缓存里获取一个可用连接(建立socket连接)
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      //添加自定义的网络拦截器
      interceptors.addAll(client.networkInterceptors());
    }
    //添加请求服务拦截器,真正发起请求通过io流获取响应信息(通过socket连接发送数据以及接受响应)
    interceptors.add(new CallServerInterceptor(forWebSocket));

    //构建拦截器链的头节点
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
        originalRequest, this, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    boolean calledNoMoreExchanges = false;
    try {
      /*
       * 开始拦截器链的执行,根据index获取拦截器执行intercept()方法,intercept()内部通过自增的index参数构建新的拦截器链节点,
       * 通过其调用proceed()又开启下一个拦截器的处理,这样就构成了一个完整的循环遍历执行拦截器的过程
       */
      Response response = chain.proceed(originalRequest);
      if (transmitter.isCanceled()) {
        closeQuietly(response);
        throw new IOException("Canceled");
      }
      return response;
    } catch (IOException e) {
      calledNoMoreExchanges = true;
      throw transmitter.noMoreExchanges(e);
    } finally {
      if (!calledNoMoreExchanges) {
        transmitter.noMoreExchanges(null);
      }
    }
  }
}

方法内部定义了Interceptor集合依次将以下拦截器添加到集合中:
自定义Interceptor:我们自己实现的拦截器,比如我们有时候想要在请求前统一添加公共参数或者添加请求、响应的日志都可以自定义拦截器来实现;
RetryAndFollowUpInterceptor:实现了失败重试和重定向的一些策略;
BridgeInterceptor:处理我们添加的请求头以及添加一些默认请求头信息如gzip透明压缩等;
CacheInterceptor:处理缓存策略的一些逻辑;
ConnectInterceptor:创建Socket和服务器进行连接,维护Socket连接池;有兴趣的朋友可以跟以下这个拦截器的代码它最终创建Socket连接实在RealConnection类中实现的
自定义NetworkInterceptor:通常用于监听Socket连接内容,如Facebook出品的Stetho,可以很方便的让我们通过浏览器调试接口
CallServerInterceptor:向Socket连接发送请求数据并且获取响应数据,它底层用Okio库替代了Java原生的io流操作。

getResponseWithInterceptorChain()方法内部创建了一个重要的对象RealInterceptorChain,它的构造函数会传入一个index,这个index正是下一个所要执行的拦截器在集合中的下标,process()方法每调用依次index都会随之递增,而每个Interceptor的intercept()方法中又会调用RealInterceptorChain的process()方法,这样就达到了遍历执行Intercepter的目的

public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
      throws IOException {
    ......
    // 执行下一个拦截器的代码
    RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
        index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);
    ......

    return response;
  }

在这里插入图片描述
如上图所示,拦截器链在遍历执行的过程中,依次对Request进行拦截处理最后获取到响应后又沿着相反的方向将Response返回,在返回的过程中拦截器又可以逐层最Response进行处理,将最终结果返回给Call对象,这样就完成一个完整的Okhttp请求流程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值