超详细Okhttp 源码分析

文章目录

  • 前言
  • 创建OkhttpClient
  • 创建Request
    • build()
    • Request
  • 创建Request
  • 同步请求(单独部分)
    • executed ①
    • runningSyncCalls②
  • 异步请求(单独部分)
    • enqueue①
    • executorService ①①
    • AsyncCall ②
    • run()方法②①
    • execute ②①①
    • finished②①①①
  • Dispatcher(Okhttp核心)分发器
  • 拦截器(Okhttp核心)
    • proceed
      • 5个拦截器的简单总结 :
        • 1. RetryAndFollowUpInterceptor重定向拦截器
        • 2. BridgeInterceptor桥拦截器
        • 3. CacheInterceptor缓存拦截器
        • 4. ConnectInterceptor连接拦截器
        • 5. CallServerInterceptor请求服务器拦截器
  • 总结


前言

通过Okhttp使用流程,一步一步查看源码如何实现!

创建OkhttpClient

  • OkHttpClient client = new OkHttpClient.Builder() 封装Okhttp初始化所需要的参数
  public Builder() {
      //分发器 决定异步请求是直接处理还是缓存等待,同步请求直接放入队列中
      dispatcher = new Dispatcher();
      protocols = DEFAULT_PROTOCOLS;
      connectionSpecs = DEFAULT_CONNECTION_SPECS;
      eventListenerFactory = EventListener.factory(EventListener.NONE);
      proxySelector = ProxySelector.getDefault();
      cookieJar = CookieJar.NO_COOKIES;
      socketFactory = SocketFactory.getDefault();
      hostnameVerifier = OkHostnameVerifier.INSTANCE;
      certificatePinner = CertificatePinner.DEFAULT;
      proxyAuthenticator = Authenticator.NONE;
      authenticator = Authenticator.NONE;
      //连接池  客户端 --服务端 中间的连接 称之为 connection 而 所有的连接都是放在连接池中的即:		//	ConnectionPool
      // 当请求的 URL相同时 可以选择复用 
      connectionPool = new ConnectionPool();
      dns = Dns.SYSTEM;
      followSslRedirects = true;
      followRedirects = true;
      retryOnConnectionFailure = true;
      connectTimeout = 10_000;
      readTimeout = 10_000;
      writeTimeout = 10_000;
      pingInterval = 0;
    }

创建Request

  • Request request = new Request.Builder().url(“http://www.baidu.com”) .get().build();
   public Builder() {
       //默认请求方式
      this.method = "GET";
       //头部信息
      this.headers = new Headers.Builder();
    }

build()

   public Request build() {
      if (url == null) throw new IllegalStateException("url == null");
       //把Builder封装好的 对象传递给 Request
      return new Request(this);
    }

Request

  Request(Builder builder) {
      //初始化 基本信息
    this.url = builder.url;
    this.method = builder.method;
    this.headers = builder.headers.build();
    this.body = builder.body;
    this.tag = builder.tag != null ? builder.tag : this;
  }

创建Request

  • Call call = client.newCall(request);
  private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
      //第一步创建好的OkHttpClient 
    this.client = client;
      //第二步创建好的 Request 
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
      //重定向拦截器 
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
  }

以上步骤 是同步和异步请求相同的部分

同步请求(单独部分)

  • Response response = call.execute(); 开启异步请求
  @Override public Response execute() throws IOException {
      //同步代码块
    synchronized (this) {
        //同一个http请求只能执行一次
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
      //捕捉异常
    captureCallStackTrace();
      //开启请求时开启listener
    eventListener.callStart(this);
    try {
        //通过 OkHttpClient 获得 分发器 ,并调用分发器中的 executed 方法 ①
      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);
    }
  }

executed ①

 /** Used by {@code Call#execute} to signal it is in-flight. */
  synchronized void executed(RealCall call) {
      //加入队列 runningSyncCalls ② 
    runningSyncCalls.add(call);
  }

runningSyncCalls②


  /** Ready async calls in the order they'll be run. */
//异步就绪队列
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
//异步执行队列
  /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
//同步队列
  /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

异步请求(单独部分)

  • call.enqueue() 开启异步请求
  @Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
          //同一个http请求只能执行一次
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
     //通过 OkHttpClient 获得 分发器 ,并调用分发器中的 enqueue 方法 ① 传入 AsyncCall ②
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

enqueue①

synchronized void enqueue(AsyncCall call) {
    //首先判断当前 正在请求的数是否小于 最大请求数   private int maxRequests = 64;
    // 并且 当前网络请求的 Host是否小于 maxRequestsPerHost private int maxRequestsPerHost = 5;
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
        //条件满足 加入到正在执行的异步请求队列当中
      runningAsyncCalls.add(call);
        //通过线程 executorService ①① 池执行 call请求    
      executorService().execute(call);
    } else {
        //如果条件不满足 就把请求加入到 异步就绪队列 等待条件满足执行 call请求
      readyAsyncCalls.add(call);
    }
  }

executorService ①①

//通过  synchronized 保证对象 是单例 
public synchronized ExecutorService executorService() {
    if (executorService == null) {
        //创建线程池
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }

AsyncCall ②

 final class AsyncCall extends NamedRunnable 
 public abstract class NamedRunnable implements Runnable
 //就是 一个 Runnable run()方法②①

run()方法②①

@Override public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
        //真正执行操作的方法  execute ②①①
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }

execute ②①①

    @Override protected void execute() {
      boolean signalledCallback = false;
      try {
          ///拦截器链 方法 获得响应  
        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 {
          //回收请求 finished②①①①
        client.dispatcher().finished(this);
      }
    }

finished②①①①


private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
    int runningCallsCount;
    Runnable idleCallback;
    synchronized (this) {
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
        // promoteCalls() 调整任务队列
      if (promoteCalls) promoteCalls();
        //异步进入此方法 
        //重新赋值 正在执行的请求数  runningCallsCount() == runningAsyncCalls.size() + 				//runningSyncCalls.size();
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }
	//空闲时执行空闲回调 
    if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();
    }
  }

Dispatcher(Okhttp核心)分发器

  • 作用:

为维护请求的状态,并维护一个线程池,用于执行请求

 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();
        runningAsyncCalls.add(call);
        executorService().execute(call);
      }

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

拦截器(Okhttp核心)

  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));
	//创建 Chain 即链 
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());
		// 调用 proceed()发起网络请求
    return chain.proceed(originalRequest); 
  }

proceed

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

    calls++;

    // If we already have a stream, confirm that the incoming request will use it.
    if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must retain the same host and port");
    }

    // If we already have a stream, confirm that this is the only call to chain.proceed().
    if (this.httpCodec != null && calls > 1) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must call proceed() exactly once");
    }

    // Call the next interceptor in the chain.
     创建下一个拦截器 
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    Interceptor interceptor = interceptors.get(index);
     //放入 intercept  实现 这个方法是5个拦截器
     //RetryAndFollowUpInterceptor
     //BridgeInterceptor
     //CacheInterceptor
     //ConnectInterceptor
     //CallServerInterceptor 
    Response response = interceptor.intercept(next);

    // Confirm that the next interceptor made its required call to chain.proceed().
    if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
      throw new IllegalStateException("network interceptor " + interceptor
          + " must call proceed() exactly once");
    }

    // Confirm that the intercepted response isn't null.
    if (response == null) {
      throw new NullPointerException("interceptor " + interceptor + " returned null");
    }

    if (response.body() == null) {
      throw new IllegalStateException(
          "interceptor " + interceptor + " returned a response with no body");
    }

    return response;
  }

5个拦截器的简单总结 :

1. RetryAndFollowUpInterceptor重定向拦截器

RetryAndFollowUpInterceptor负责失败重试以及重定向。

RetryAndFollowUpInterceptor的作用就是处理了一些连接异常以及重定向。

2. BridgeInterceptor桥拦截器

BridgeInterceptor就跟它的名字那样,它是一个连接桥,它负责把用户构造的请求转换为发送给服务器的请求,把服务器返回的响应转换为对用户友好的响应。

转换的过程就是添加一些服务端需要的header信息。

在Request阶段配置用户信息,并添加一些请求头。在Response阶段,进行gzip解压。

3. CacheInterceptor缓存拦截器

1.根据策略,不使用网络,又没有缓存的直接报错,并返回错误码504。

2.根据策略,不使用网络,有缓存的直接返回。

3.前面两个都没有返回,继续执行下一个Interceptor,即ConnectInterceptor。

4.接收到网络结果,如果响应code式304,则使用缓存,返回缓存结果。

5.读取网络结果。

6.对数据进行缓存。

7.返回网络读取的结果。

4. ConnectInterceptor连接拦截器

在RetryAndFollowUpInterceptor里初始化了一个StreamAllocation对象,我们说在这个StreamAllocation对象里初始化了一个Socket对象用来做连接,但是并没有 真正的连接,等到处理完hader和缓存信息之后,才调用ConnectInterceptor来进行真正的连接

5. CallServerInterceptor请求服务器拦截器

这是链中的最后一个拦截器。 它会对服务器进行网络请求
我们通过ConnectInterceptor已经连接到服务器了,接下来我们就是写入请求数据以及读出返回数据了。整个流程:

写入请求头
写入请求体
读取响应头
读取响应体

总结

Okhttp源码实现逻辑还是非常容易理解的,如果不理解,多看几遍就Ok了!设计的非常精妙,从中可以学习到许多编程思想。

你可能感兴趣的:(安卓学习,java,http,android,okhttp)