OkHttp源码分析(一)-----------------整体流程

OkHttp简介这里写图片描述

OkHttp工作的流程图

这里写图片描述
此图片来源:https://blog.piasy.com/2016/07/11/Understand-OkHttp/

OkHttp源码解析

这里以get方式为例说明:

//第一步:创建OkHttpClient对象
OkHttpClient okHttpClient = new OkHttpClient();
//第二步:创建请求
Request request = new Request.Builder().url("url").build();
//第三步:发送请求,同步执行
okHttpClient.newCall(request).execute();

第一步:创建OkHttpClient对象

/**
  点进来查看,显示如下
*/
 public OkHttpClient() {
    this(new Builder());
 }

 OkHttpClient(Builder builder) {
   //分发器
   this.dispatcher = builder.dispatcher;
   this.proxy = builder.proxy;
   //线程池
   this.protocols = builder.protocols;
   this.connectionSpecs = builder.connectionSpecs;
   //应用层截获器
   this.interceptors = Util.immutableList(builder.interceptors);
   //网络截获器
   this.networkInterceptors =    
   Util.immutableList(builder.networkInterceptors);
   //连接池
   this.connectionPool = builder.connectionPool;
   this.eventListenerFactory = builder.eventListenerFactory;
   this.proxySelector = builder.proxySelector;
   this.cookieJar = builder.cookieJar;
   this.cache = builder.cache;
   this.internalCache = builder.internalCache;
   this.socketFactory = builder.socketFactory;
   ......
}

第二步:创建请求

//初始化构建者模式和请求对象,且用URL替换Web套接字URL,支持http和https
public final class Request {
  public Builder() {
    this.method = "GET";
    this.headers = new Headers.Builder();
  }

 public Builder url(String url) {
   ......
   if (url.regionMatches(true, 0, "ws:", 0, 3)) {
      url = "http:" + url.substring(3);
   } else if (url.regionMatches(true, 0, "wss:", 0, 4)) {
      url = "https:" + url.substring(4);
   }

   HttpUrl parsed = HttpUrl.parse(url);
   ......
   return url(parsed);
 }

 public Request build() {
   ......
   return new Request(this);
 }
}

第三步:发送请求,执行请求
okHttpClient调用newCall方法,传入request对象,先来看newCall方法源码

/**
  OkHttpClient 实现了 Call.Factory,负责根据请求创建新的 Call,callFactory 负责创建 HTTP 请求,
  HTTP请求被抽象为了 okhttp3.Call 类,它表示一个已经准备好,可以随时执行的 HTTP 请求
*/
@Override public Call newCall(Request request) {
   return RealCall.newRealCall(this, request, false);
}

再来看newRealCall方法

static RealCall newRealCall(OkHttpClient client, Request  
   originalRequest, boolean forWebSocket) {
   /** 创建请求Call */
  RealCall call = new RealCall(client, originalRequest,   
    forWebSocket);
  /** 将Call安全的添加到事件监听中,使事件的分发和流程控制变得更为简便*/
  call.eventListener = client.eventListenerFactory().create(call);
return call;
}

可以看到主要逻辑在RealCall方法中,我们接着看

private RealCall(OkHttpClient client, Request originalRequest, 
    boolean forWebSocket) {
 this.client = client;
 this.originalRequest = originalRequest;
 this.forWebSocket = forWebSocket;
 /**拦截器,其主要作用是进行请求的重试与重定向*/
 this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}

上述中有 okHttpClient.newCall(request).execute( ) ,所以此处查看RealCall#execute方法

//同步请求方法
@Override
public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already  
          Executed");                               //(1)
      executed = true;
    }
   captureCallStackTrace();
   eventListener.callStart(this);
try {
   //同步,把这次请求添加到分发器中,就是上述中应用层中的分发器
   client.dispatcher().executed(this);              //(2)
   //截获器处理
   Response result = getResponseWithInterceptorChain();   //(3)
  if (result == null) throw new IOException("Canceled");
   return result;
} catch (IOException e) {
  eventListener.callFailed(this, e);
  throw e;
} finally {
  client.dispatcher().finished(this);           //(4)
}
}

(1) 检查这个 call 是否已经被执行了,每个 call 只能被执行一次,如果想要一个完全一样的 call,可以利用call#clone
方法进行克隆
(2) 调用分发器实际执行,进入client.dispatcher().executed(this)方法中查看,详情见于OkHttp源码分析(二)分发器Dispatcher介绍

/**将当前的Call添加到执行队列中*/
synchronized void executed(RealCall call) {
  runningSyncCalls.add(call);
}

(3) 接下来看截获器getResponseWithInterceptorChain()源码,

/**
  调用 getResponseWithInterceptorChain() 函数获取 HTTP 返回结果,其中会再次经过拦截
*/
Response getResponseWithInterceptorChain() throws IOException {
  List<Interceptor> interceptors = new ArrayList<>();
  /**
     Interceptor 是 OkHttp 最核心的一个东西,它把实际的网络请求、缓存、透明压缩等功能都统一了起来,
     每一个功能都只是一个 Interceptor,它们再连接成一个 Interceptor.Chain,环环相扣,最终圆满完
     成一次网络请求.这个Interceptor链条是典型的“责任链模型”,对于把 Request 变成 Response 这件
     事来说,每个 Interceptor 都可能完成这件事,我们循着链条让每个 Interceptor 自行决定能否完成
     任务以及怎么完成任务(自力更生或者交给下一个Interceptor)。这样一来,完成网络请求这件事就彻底
     从 RealCall 类中剥离了出来,简化了各自的责任和逻辑
  */
  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));
  ........
}

流程图表示:
这里写图片描述

  • interceptors:配置OkHttpClient时设置
  • RetryAndFollowUpInterceptor:失败重试及重定向时使用
  • BridgeInterceptor:负责把用户构造的请求转换为发送到服务器的请求、把服务器返回的响应转换为用户友好的响应
  • CacheInterceptor:负责读取缓存直接返回、更新缓存
  • ConnectInterceptor:负责和服务器建立连接
  • networkInterceptors:配置OkHttpClient时设置
  • CallServerInterceptor:负责向服务器发送请求数据、从服务器读取响应数据

(4)最后通知 dispatcher 自己已经执行完毕

上面设置完所有的截获器之后,最终要串成一个Interceptor.Chain,如下所示

Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);

接着看RealInterceptorChain#proceed()源码,

public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
    RealConnection connection) throws IOException {
  if (index >= interceptors.size()) throw new AssertionError();

  calls++;

    ........

  /**不断的递归遍历判断是否每个拦截器都有对应的处理,若是没有的话先新建RealInterceptorChain,
     并执行当前的intercept方法,拦截器可以用来转换,重试,重写请求的机制
  */
  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);

    .......

  return response;
}


//使用方法
 okHttpClient.newBuilder().addInterceptor(new Interceptor() {
     @Override
     public Response intercept(Chain chain) throws IOException {
          Request request = chain.request()
                  .newBuilder()
                  .addHeader("test","testValue")
                  .build();
          return chain.proceed(request);
        }
 });

以上是同步执行excute的解析,现就异步请求enqueue做简要说明

synchronized void enqueue(AsyncCall call) {
  /**
    maxRequests:最大并发请求数,默认为64
    maxRequestsPerHost:每个主机最大请求数,默认为5
    runningAsyncCalls:正在执行的异步请求,包含已经取消但未执行完的请求
    readyAsyncCalls:准备执行的请求
  */
  if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
    //判断是否超过阈值,若是没有则添加到执行的队列runningAsyncCalls中
    runningAsyncCalls.add(call);
    //线程池中执行这个call
    executorService().execute(call);      //(1)
  } else {
   //若是超过,则添加到等待的队列readyAsyncCalls中
    readyAsyncCalls.add(call);
  }
}

(1)同步请求和异步请求的原理是一样的,现executorService().execute(call)中传入的是AsyncCall,进入查看其源码:

 final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;

    //构造方法传入Callback 类型          ---------------------(2)
    AsyncCall(Callback responseCallback) {
      super("OkHttp %s", redactedUrl());
      this.responseCallback = responseCallback;
    }

    ........

    //执行execute方法
    @Override protected void execute() {   ------------------------(3)
      boolean signalledCallback = false;
      try {
        /**此处我们看到同步和异步都会调用getResponseWithInterceptorChain()函数中通过 Interceptor 链条
           来实现的网络请求逻辑,这就和我们最上面的“OkHttp工作的流程图”中的模型对接上了
        */
        Response response = getResponseWithInterceptorChain();
        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);
      }
    }
  }

(2) AsyncCall构造方法中的参数Callback 源码如下:

//这就是为什么异步执行的时候有回调,同步执行的时候没有回调,原因是异步执行的时候传入了接口
public interface Callback {
   void onFailure(Call call, IOException e);
   void onResponse(Call call, Response response) throws IOException;
}

(3) 由于AsyncCall继承NamedRunnable类,而execute方法是NamedRunnable中的抽象类,所以必须重写:

//可以看出NamedRunnable实现Runnable接口,是一个子线程
public abstract class NamedRunnable implements Runnable {
  protected final String name;

  public NamedRunnable(String format, Object... args) {
    this.name = Util.format(format, args);
  }

  @Override public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
      //抽象方法,必须在外界调用的时候重写
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }

  protected abstract void execute();
}

至此关于OkHttp异步和同步的执行流程分析完毕,其发送请求和接收返回数据的相关分析请见OkHttp源码分析(三)拦截器

猜你喜欢

转载自blog.csdn.net/qq_33768280/article/details/80722124