OkHttp源码分析

本文详细介绍了OkHttp的基本使用方法及内部执行流程,包括构建OkHttpClient和Request对象,通过RealCall发起异步请求,以及AsyncCall任务的调度与执行。深入解析了OkHttp的拦截器机制,区分应用拦截器与网络拦截器的功能与调用时机。

一、OkHttp的基本使用

//构建OkHttpClient对象
OkHttpClient okHttpClient = new OkHttpClient.Builder()
        .addInterceptor(new RequestIntercept())
        .readTimeout(5, TimeUnit.SECONDS)
        .writeTimeout(5, TimeUnit.SECONDS)
        .connectTimeout(5, TimeUnit.SECONDS)
        .build();

//构建Request对象
Request request = new Request.Builder()
        .get()
        .url("http://www.test.com")
        .build();

//根据request对象创建RealCall对象
Call call = okHttpClient.newCall(request);

//通过RealCall发起异步请求
call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {

    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {

    }
});

上述代码是okhttp的基本使用,下面简述下其流程:

  1. 第一步先构建OkHttpClient对象,通过builder模式构建配置参数,包括自定义拦截器、连接和读写超时时间等一些配置
  2. 构建Request请求对象,也是通过builder模式构建请求参数,包括请求方式(get/post)、请求url、请求体参数(post请求需要)
  3. 根据Request请求对象创建能够发起请求的对应的RealCall对象,RealCall的构造方法中传入了OkHttpClient对象和Request对象,这样RealCall就持有了这两个对象的所有信息
  4. 通过RealCall的enqueue方法发起异步请求,并设置请求监听回调

二、OkHttp的执行流程

通过OkHttp的基本使用可以知道,先构建出OkHttpClient对象和Request对象,通过这两个对象配置请求需要的参数数据,然后根据这两个对象构建出RealCall,然后通过RealCall的enqueue方法发起异步请求,下面看下enqueue方法的源码:

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

  //注释1
  client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

在注释1处,调用了调度器dispatcher的enqueue方法,并向调度器中添加了一个AsyncCall任务对象(AsyncCall是一个Runnable),跟着查看下dispatcher的enqueue方法:

private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
  
synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
}

在这个方法中可以看到有两个队列readyAsyncCalls和runningAsyncCalls,runningAsyncCalls是正在执行请求的队列,readyAsyncCalls是准备进行请求的队列,当正在执行的请求队列的长度大于最大请求数maxRequests时,就会将该请求任务添加到缓存队列readyAsyncCalls中,当请求数和域名都满足最大值要求时,就会将请求任务添加到runningAsyncCalls中,并通过线程池执行该任务,由于AsyncCall是一个Ruannable对象,所以放到线程池中执行时,会调用其run方法,AsyncCall的直接父类是NamedRunnable,这个类中重写了run方法,最终AsyncCall的执行代码是在其execute方法中进行的,所以查看下AsyncCall的execute方法:

@Override protected void execute() {
    boolean signalledCallback = false;
    try {
		
	  //注释2
      Response response = getResponseWithInterceptorChain();
      if (retryAndFollowUpInterceptor.isCanceled()) {
        signalledCallback = true;
	
		 //注释3
        responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
      } else {
        signalledCallback = true;
        
		//注释4
        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 {
        eventListener.callFailed(RealCall.this, e);

		//注释5
        responseCallback.onFailure(RealCall.this, e);
      }
    } finally {
      //注释6
      client.dispatcher().finished(this);
    }
}

在注释2处进行了拦截器链的调用最终返回一个Response响应,注释3和5回调响应失败,注释4回调响应成功,在注释6处的finished方法中,会从runningAsyncCalls执行队列中移除该任务,然后将readyAsyncCalls的任务取出来添加到runningAsyncCalls中,这个过程在调用链的promoteCalls方法中,下面看下dispatcher的finished方法和promoteCalls方法:

void finished(AsyncCall call) {
  //runningAsyncCalls正在执的任务队列
  finished(runningAsyncCalls, call, true);
}

private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
  int runningCallsCount;
  Runnable idleCallback;
  synchronized (this) {
	//calls.remove(call))从runningAsyncCalls中移除该任务
    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();
  }
}
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();

    if (runningCallsForHost(call) < maxRequestsPerHost) {
      i.remove();

	  //将readyAsyncCalls中的任务取出添加到正在执行的队列中
      runningAsyncCalls.add(call);

	  //通过线程池执行从readyAsyncCalls中刚取出的任务
      executorService().execute(call);
    }

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

在注释2处的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, this, eventListener, client.connectTimeoutMillis(),
      client.readTimeoutMillis(), client.writeTimeoutMillis());

  return chain.proceed(originalRequest);
}

拦截器是典型的责任链模式,从上述方法中可以看出,所有的拦截器都按照顺序存放到一个list中,按照添加顺序进行递归调用,先添加的是用户自定义的拦截器,其次是重试和重定向处理拦截器retryAndFollowUpInterceptor、补全请求信息的拦截器BridgeInterceptor(添加一些基础的请求头信息)、缓存处理拦截器CacheInterceptor、con连接拦截器ConnectInterceptor,然后是网络拦截器,最后是向服务端进行I/O读写处理的拦截器CallServerInterceptor,每个拦截器只负责自己对应的职责,这些拦截器层层处理,最终返回一个用户需要的Response响应数据,其实okhttp的请求过程,可以看成是各个拦截器处理的过程

上面的拦截器中可以分为两类,一类是应用拦截器,另一类是网络拦截器networkInterceptor,网络拦截器和应用拦截器有什么区别呢,主要是调用时机的问题,用户自定义的应用拦截器调用的最早,在应用拦截器中只能拿到原始的请求信息并且获取不到connection对象,不能操作中间响应,只能操作最终的响应信息,而网络拦截器是在请求补全、缓存、connection处理之后进行调用的,所以网络拦截器能够拿到完整的网络请求,能够对重定向和重试等中间响应进行操作,可以获取到connection对象

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值