OkHttp3源码解析(一)——整体框架

好一番春意盎然,暖暖的阳光底下,百合嫩芽破土而出,月季花早已红颜娇滴。

目录

目录

一 、简介及框架

OkHttp是安卓端最火热的轻量级网络框架,由移动支付Square公司开源,用于替代HttpUrlConnection和Apache的HttpClient,事实上,Android4.4开始,google已经开始将源码中的HttpURLConnection替换为OkHttp,Android6.0里已移除HttpClient。由于该框架功能强大,而应用非常简单,越来越多的安卓开发者应用了该框架。
具有如下的功能和特性:
1、支持同步和异步请求,支持get和post请求,支持上传和下载文件,加载图片;
2、支持Https,Http 1.0 1.1 2.0, websocket, SPDY等协议,3.7版本开始剥离SPDY,转而大力支持 http2.0
3、支持Http缓存,避免重复请求;
4、内部维护连接池,支持多路复用,减少连接创建开销;
5、无缝支持Gzip压缩,减少数据流量;
6、内部维护任务队列线程池,友好支持并发访问,最大并发64,单个host最大5个;
7、socket创建支持最佳路由;
8、服务器配置多IP情况下,当前IP请求失败,支持自动切换到其他IP;
9、使用Okio来简化书看的访问和存储,提高性能;
10、OkHttp还处理了代理服务器问题和SSL握手失败问题。

整体框架图

上图是OkHttp的总体架构,大致可以分为以下几层:
Interface——接口层:接受网络访问请求
Protocol——协议层:处理协议逻辑
Connection——连接层:管理网络连接,发送新的请求,接收服务器访问
Cache——缓存层:管理本地缓存
I/O——I/O层:实际数据读写实现
Inteceptor——拦截器层:拦截网络访问,插入拦截逻辑

二 、使用方法

定义网络管理单例,全局只声明一次OkHttpClient 。

private OkHttpClient mClient;
/**
* 异步请求
*
* @param request
* @param callback
*/
public void sendAsyncRequest(Request request, Callback callback) {
     mClient.newCall(request).enqueue(callback);
}
/**
* 同步请求
* @param request
* @return
*/
public Response sendSyncRequest(Request request) {
     Response response = null;
     try {
          response = mClient.newCall(request).execute();
     } catch (Exception e) {
     }
     return response;
}

业务层要发请求调用的示例:

//构建请求对象
Request request = new Request.Builder().url("https://baidu.com").build();
//异步请求
NetManager.getInstance().sendAsyncRequest(request, new Callback() {
      @Override
      public void onFailure(Call call, IOException e) {
      }
      @Override
      public void onResponse(Call call, Response response) throws IOException {
      }
});
//同步请求
Response response = NetManager.getInstance().sendSyncRequest(request);

三、调用流程分析

OkHttp由OkHttpClien对外提供统一接口,支持同步和异步请求,无论哪种请求,都会封装为RealCall对象,再调用RealCall的同步或异步方法,并最终都会调用getResponseWithInterceptorChain执行请求任务,不同的同步的请求会直接调用该方法,而异步请求会再封装为AsynCall,再将其加入Dispatcher的任务队列,Dispatcher则维护任务调度线程池,对异步请求任务进行分发,当任务执行时会在新线程里调用RealCall的getResponseWithInterceptorChain.具体调度流程如下图所示:

调用流程

同步流程:

OkHttpClient:
@Override 
public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
 }

RealCall:
@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);
      //直接发送请求并获取服务器返回
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } catch (IOException e) {
      eventListener.callFailed(this, e);
      throw e;
    } finally {
      //从同步队列移除
      client.dispatcher().finished(this);
    }
}

Dispatcher:
synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
}

异步请求流程:

OkHttpClient:
@Override 
public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
 }

RealCall:
@Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
       if (executed) throw new IllegalStateException("Already Executed");
       executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    //先构造AsyncCall对象,加入分发器的异步任务队列
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

Dispatcher:
synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      //并发请求数在64个内,且单host并发数5个内,加入异步执行队列,放入线程池
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      //已达上限则加入等待队列
      readyAsyncCalls.add(call);
    }
}

无论是同步还是异步请求,完成后都会调用Dispatcher的finish,从队列移除:

Dispatcher:
private  void finished(Deque calls, T call, boolean promoteCalls) {
    int runningCallsCount;
    Runnable idleCallback;
    synchronized (this) {
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      //异步请求调finish后需要执行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 i = readyAsyncCalls.iterator(); i.hasNext(); ) {
      AsyncCall call = i.next();
      if (runningCallsForHost(call) < maxRequestsPerHost) {
        i.remove();
        runningAsyncCalls.add(call);
        executorService().execute(call);
      }
      if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
    }
}

从上面流程可见,真正处理请求的核心方法是getResponseWithInterceptorChain,该方法主要处理一系列的Interceptor,
代码如下:

RealCall:
Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List 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());
    //调用proceed按顺序执行每个拦截器
    return chain.proceed(originalRequest);
  }
}

拦截器处理的流程如下图所示:


一组拦截器

RetryAndFollowUpInterceptor:在网络请求失败后进行重试,当服务器返回重定向时直接发起新的请求,并在允许情况下复用当前连接。
BridgeInterceptor:处理头部协议内容,包括设置请求内容长度,编码格式,gzip压缩,并对响应内容进行解压,添加cookie,还有User-Agent,Host,Keep-Alive等。
CacheInterceptor:负责缓存的管理,如果有符合条件的缓存则直接返回,当服务器返回有改变则更新当前缓存,缓存失效则删除。
ConnectionInterceptor:从连接池中查找合适的连接,如果有合适的则复用已有的连接,没有则新建连接。
CallServerInterceptor:负责向服务器发起真正的请求,并读取返回服务器的响应。

四、拦截器原理

OkHttp的Interceptor是一种典型的责任链模式,将每个处理单独包装为一个个独立的Interceptor,一个完整的请求由执行一组Interceptor来完成。下面分析下Interceptor的具体原理,核心代码如下:

Interceptor:
public interface Interceptor {
   /*
   * 拦截器要处理的逻辑
   * 除了最后一个拦截器,其他的都会调用chain.proceed,继续处理下一个拦截器
   * 等待下一个拦截器返回Response 
   */
  Response intercept(Chain chain) throws IOException;

  interface Chain {
    Request request();
    /*
    * 从下一个拦截器开始构造链,然后执行当前拦截器
    */
    Response proceed(Request request) throws IOException;
    ...
}

以RetryAndFollowUpInterceptor为例,intercept的处理流程是:

RetryAndFollowUpInterceptor:
@Override public Response intercept(Chain chain) throws IOException {
     ...
     try {
        //处理下一个拦截器,等待返回response 
        response = realChain.proceed(request, streamAllocation, null, null);
        releaseConnection = false;
      } catch (RouteException e) {
      }
      ...
}

chain.proceed的核心逻辑如下:

RealInterceptorChain:
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
{
    ...
    //从下一个拦截器开始构造链
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    //执行当前拦截器
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);
    ...
}

拦截器链的执行流程如图:


拦截器链流程

五、总结

本文介绍了okhttp具有的功能特性,简单调用方法,包括异步和同步请求,分析了总体的框架层次,然后从源码角度分析了异步和同步请求任务的调度流程,执行的流程会通过若干个拦截器完成请求各个阶段的逻辑处理,说明了各个拦截器的功能,最后分析了拦截器的源码及原理,通过本文能对okhttp有整体的了解。

你可能感兴趣的:(OkHttp3源码解析(一)——整体框架)