OkHttp3使用及原理分析

1. 基本使用

OkHttpClient.Builder clientBuilder = new OkHttpClient().Builder();
clientBuilder.connectTimeout(60,TimeUnit.SECONDS)//链接超时
    		 .readTimneout(15,TimeUnit.SECONDS)//读取超时
    		 .writeTimeout(15,TimeUnit.SECONDS)//写入超时
    		 .interceptors(interceptor)//自定义拦截器
    		 .networkInterceptors(networkInterceptors);//自定义网络连接成功的拦截器
OkHttpClient client = clientBuilder.build();

Request request = new Request().Builder().url(url).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 {}
})

2. 原理分析

2.1 newCall

请求操作的起点从client.newCall(request) (注释一)开始

  //OkHttpClient 初始化Call的函数
  @Override public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false);
  }
  // RealCall 初始化函数
  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;
  }

可以看出,最终构建返回的是RealCall对象,它是真正执行网络请求的类,实现了Call接口,提供同步请求,异步请求

2.2 同步请求
  @Override public Response execute() throws IOException {

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    try {
      client.dispatcher().executed(this);//1
      Response result = getResponseWithInterceptorChain();//2
      if (result == null) throw new IOException("Canceled");
      return result;
    } catch (IOException e) {
      eventListener.callFailed(this, e);
      throw e;
    } finally {
      client.dispatcher().finished(this);
    }
  }

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());//3
    return chain.proceed(originalRequest);//4
  }
  1. Dispatcher OkHttpClient调度器,这里将RealCall实例添加到Dispatcher中
  2. 通过getResponseWithInterceptorChain()获取响应
  3. 获取拦截器集合中第一个拦截器任务
  4. 触发第一个拦截器任务,当任务执行完,会触发下个拦截器。
2.3 异步请求
  @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));//1
  }
  1. Dispatcher内部维护一个线程池去执行异步任务

Dispatcher.enqueue

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

可以看出,实际上是使用线程池去执行AsyncCall

  final class AsyncCall extends NamedRunnable {
    @Override
      public final void run
      {
          ...
              execute();
          ...
      }      
      // ......
    @Override protected void execute() {
      boolean signalledCallback = false;
      try {
        Response response = getResponseWithInterceptorChain();//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) {
          // 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);
      }
    }
  }

同样是通过getResponseWithInterceptorChain()获取服务器响应

2.4 Interceptor拦截器
  1. RetryAndFollowUpInterceptor 重定向拦截器

    承担重新请求新url的作用(服务器返回3XX错误码为重定向,可以通过响应头的Location获取新请求的url);

  2. BridgeInterceptor 桥拦截器

    封装请求头(Content-Type、Connection、Cookie…)与响应头("Content-Encoding…)的信息。

  3. CacheInterceptor 缓存拦截器

    为网络请求提供缓存功能,加快相同请求的访问速度,减少资源消耗

  4. ConnectInterceptor 连接拦截器

    负责建立与服务器之间的连接

  5. CallServerInterceptor 请求服务拦截器

    与服务器进行数据通讯,发送请求,获取响应

CacheInterceptor 缓存拦截器

缓存拦截器主要做了两件事

  • 根据Request获取当前已有的Response缓存,可能为null,并根据缓存创建CacheStrategy对象

    public final class CacheInterceptor implements Interceptor {
      // ....
      @Override public Response intercept(Chain chain) throws IOException {
        // 根据请求内容通过Cache类判断是否已经存在响应的缓存信息
        Response cacheCandidate = cache != null
            ? cache.get(chain.request())
            : null;
        long now = System.currentTimeMillis();
        // 通过请求对象与缓存对象创建缓存策略,
        CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
        Request networkRequest = strategy.networkRequest;
        Response cacheResponse = strategy.cacheResponse;
       // ...
    }
    
  • 通过CacheStrategy判断当前缓存中的Response是否失效,如果可用则直接返回,否则调用chain.proceed()继续执行下一个拦截器

    // 记录请求过程的相关数据(请求次数、缓存次数....)
        if (cache != null) {
          cache.trackResponse(strategy);
        }
        if (cacheCandidate != null && cacheResponse == null) {
          closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
        }
        // 如果缓存无效,且请求为空,直接返回空的Response
        if (networkRequest == null && cacheResponse == null) {
          return new Response.Builder()
              .request(chain.request())
              .protocol(Protocol.HTTP_1_1)
              .code(504)
              .message("Unsatisfiable Request (only-if-cached)")
              .body(Util.EMPTY_RESPONSE)
              .sentRequestAtMillis(-1L)
              .receivedResponseAtMillis(System.currentTimeMillis())
              .build();
        }
        // 缓存有效,直接讲缓存中的Response返回
        if (networkRequest == null) {
          return cacheResponse.newBuilder()
              .cacheResponse(stripBody(cacheResponse))
              .build();
        }
        Response networkResponse = null;
        try {
          // 如果没有缓存,或者缓存失效,则执行下一个拦截器任务,发送网络请求获取Response
          networkResponse = chain.proceed(networkRequest);
        } finally {
          // If we're crashing on I/O or otherwise, don't leak the cache body.
          if (networkResponse == null && cacheCandidate != null) {
            closeQuietly(cacheCandidate.body());
          }
        }
    

CallServerInterceptor请求服务拦截器

请求服务拦截器是OkHttp网络请求部分,其intercept方法如下

  @Override public Response intercept(Chain chain) throws IOException {
      
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    HttpCodec httpCodec = realChain.httpStream();
    StreamAllocation streamAllocation = realChain.streamAllocation();
    RealConnection connection = (RealConnection) realChain.connection();
    Request request = realChain.request();

    long sentRequestMillis = System.currentTimeMillis();

    realChain.eventListener().requestHeadersStart(realChain.call());
    httpCodec.writeRequestHeaders(request);
    realChain.eventListener().requestHeadersEnd(realChain.call(), request);

    Response.Builder responseBuilder = null;
	// ...

    httpCodec.finishRequest();
    // 发送请求数据部分 
    // ...
  }      
if (responseBuilder == null) {
      realChain.eventListener().responseHeadersStart(realChain.call());
      responseBuilder = httpCodec.readResponseHeaders(false);
    }

    Response response = responseBuilder
        .request(request)
        .handshake(streamAllocation.connection().handshake())
        .sentRequestAtMillis(sentRequestMillis)
        .receivedResponseAtMillis(System.currentTimeMillis())
        .build();

    int code = response.code();
    if (code == 100) {
      // server sent a 100-continue even though we did not request one.
      // try again to read the actual response
      responseBuilder = httpCodec.readResponseHeaders(false);

      response = responseBuilder
              .request(request)
              .handshake(streamAllocation.connection().handshake())
              .sentRequestAtMillis(sentRequestMillis)
              .receivedResponseAtMillis(System.currentTimeMillis())
              .build();

      code = response.code();
    }

    realChain.eventListener()
            .responseHeadersEnd(realChain.call(), response);

    if (forWebSocket && code == 101) {
      // Connection is upgrading, but we need to ensure interceptors see a non-null response body.
      response = response.newBuilder()
          .body(Util.EMPTY_RESPONSE)
          .build();
    } else {
      response = response.newBuilder()
          .body(httpCodec.openResponseBody(response))
          .build();
    }
	// ...

    return response;
// 获取请求结果部分

3. 总结

  • OkHttp中的同步,异步请求,最终都是由Dispatcher调度器进行分发执行
  • 网络请求阶段通过责任链模式,链式调用各个拦截器的intercept( )
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值