OkHttp解析

来源:互联网 发布:照片打印软件免费版 编辑:程序博客网 时间:2024/05/22 12:14

okhttp正题架构

okhttp源码解析

优点:

1支持HTTP2 ,支持统一主机服务器共享同一socket通信;提高了请求效率

2在http2的情况下通过连接池减少请求的延迟

3gzip压缩减少网络数据的流量

4响应缓存避免同一重复请求

okhttp的两种调用方式

同步直接调用RealCall的execute最终调用的是getResponseWithInterceptorChain(forWevSocket)

 @Override protected void execute() {      boolean signalledCallback = false;      try {        Response response = getResponseWithInterceptorChain(forWebSocket);        if (canceled) {          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 {        client.dispatcher().finished(this);      }    }
而异步调用时:

enqueue中调用Dispatcher的enqueue方法

  synchronized void enqueue(AsyncCall call) {    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {      runningAsyncCalls.add(call);      executorService().execute(call);    } else {      readyAsyncCalls.add(call);    }  }
通过ExecutorService启动线程池开启线程最终调用RealCall的execute还是会调用getResponseWithInterceptorChain(forWevSocket)方法

最终getResponseWithInterceptorChain(forWevSocket)通过一系列的Interceptors完成配置 请求

OkHttp总体架构:

OkHttp整体架构图

大致分为

1、Interface-接口层:接收网络访问请求

2、Protocol-协议层:处理协议逻辑

3、Connection-连接层:管理网络链接,发送新的请求,接收消息响应

4、Cache-缓存层:管理本地缓存

5、I/O层--实际数据读取与实现

6、Interceptor-拦截层:拦截网络访问,插入拦截逻辑

OkHttpClient是OkHttp框架的客户端,更确切的说是一个用户面板。用户使用OkHttp进行各种设置,发起各种网络请求都是通过OkHttpClient完成的。每个OkHttpClient内部都维护了属于自己的任务队列,连接池,Cache,拦截器等,所以在使用OkHttp作为网络框架时应该全局共享一个OkHttpClient实例。

RealCall:OkHttp会为每一个请求创建一个RealCall,每一个RealCall内部有一个AsyncCall(继承NameRunnable  implements

Runnable所以每一个Call就是一个线程 执行其execute()方法

Dispatcher是OkHttp的任务队列,其内部维护了一个线程池(最大限度的复用现有连接),当有接收到一个Call时,Dispatcher负责在线程池中找到空闲的线程并执行其execute方法


拦截层

getResponseWithInterceptorChain方法最终调用ApplicationInterceptorChain中的proceed方法

  private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {    Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);    return chain.proceed(originalRequest);  }
最终调用对应的Interceptor的intercept方法

@Override public Response proceed(Request request) throws IOException {      // If there's another interceptor in the chain, call that.      if (index < client.interceptors().size()) {        Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);        Interceptor interceptor = client.interceptors().get(index);        Response interceptedResponse = interceptor.intercept(chain);        if (interceptedResponse == null) {          throw new NullPointerException("application interceptor " + interceptor              + " returned null");        }        return interceptedResponse;      }      // No more interceptors. Do HTTP.      return getResponse(request, forWebSocket);    }

一下是各种拦截器
RetryAndFollowUpInterceptor
  @Override public Response intercept(Chain chain) throws IOException {    Request request = chain.request();    RealInterceptorChain realChain = (RealInterceptorChain) chain;    Call call = realChain.call();    EventListener eventListener = realChain.eventListener();    streamAllocation = new StreamAllocation(client.connectionPool(), createAddress(request.url()),        call, eventListener, callStackTrace);    int followUpCount = 0;    Response priorResponse = null;    while (true) {      if (canceled) {        streamAllocation.release();        throw new IOException("Canceled");      }      Response response;      boolean releaseConnection = true;      try {        response = realChain.proceed(request, streamAllocation, null, null);        releaseConnection = false;      } catch (RouteException e) {        // The attempt to connect via a route failed. The request will not have been sent.        if (!recover(e.getLastConnectException(), false, request)) {          throw e.getLastConnectException();        }        releaseConnection = false;        continue;      } catch (IOException e) {        // An attempt to communicate with a server failed. The request may have been sent.        boolean requestSendStarted = !(e instanceof ConnectionShutdownException);        if (!recover(e, requestSendStarted, request)) throw e;        releaseConnection = false;        continue;      } finally {        // We're throwing an unchecked exception. Release any resources.        if (releaseConnection) {          streamAllocation.streamFailed(null);          streamAllocation.release();        }      }      // Attach the prior response if it exists. Such responses never have a body.      if (priorResponse != null) {        response = response.newBuilder()            .priorResponse(priorResponse.newBuilder()                    .body(null)                    .build())            .build();      }      Request followUp = followUpRequest(response);      if (followUp == null) {        if (!forWebSocket) {          streamAllocation.release();        }        return response;      }      closeQuietly(response.body());      if (++followUpCount > MAX_FOLLOW_UPS) {        streamAllocation.release();        throw new ProtocolException("Too many follow-up requests: " + followUpCount);      }      if (followUp.body() instanceof UnrepeatableRequestBody) {        streamAllocation.release();        throw new HttpRetryException("Cannot retry streamed HTTP body", response.code());      }      if (!sameConnection(response, followUp.url())) {        streamAllocation.release();        streamAllocation = new StreamAllocation(client.connectionPool(),            createAddress(followUp.url()), call, eventListener, callStackTrace);      } else if (streamAllocation.codec() != null) {        throw new IllegalStateException("Closing the body of " + response            + " didn't close its backing stream. Bad interceptor?");      }      request = followUp;      priorResponse = response;    }  }
 response = realChain.proceed(request, streamAllocation, null, null);

这行代码就是执行下一个拦截器链的proceed方法。而我们知道在下一个拦截器链中又会执行下一个拦截器的intercept方法。所以整个执行链就在拦截器与拦截器链中交替执行,最终完成所有拦截器的操作。这也是OkHttp拦截器的链式执行逻辑。而一个拦截器的intercept方法所执行的逻辑大致分为三部分:

  • 在发起请求前对request进行处理
  • 调用下一个拦截器,获取response
  • 对response进行处理,返回给上一个拦截器

几个核心的拦截器

  • RetryAndFollowUpInterceptor
  • BridgeInterceptor
  • CacheInterceptor
  • ConnectIntercetot
  • CallServerInterceptor
interceptors.png



okhttp的多路复用:

ConnectionPool


okhttp中的坑


原创粉丝点击