OkHttp源码分析

简介

OkHttp是一个高效的HTTP客户端,它有以下默认特性:
·支持HTTP/2,允许所有同一个主机地址的请求共享同一个socket连接
·连接池减少请求延时
·透明的GZIP压缩减少响应数据的大小
·缓存响应内容,避免一些重复的请求

OkHttp官网:https://square.github.io/okhttp/
Github地址 :https://github.com/square/okhttp

使用

implementation 'com.squareup.okhttp3:okhttp:3.9.0'

4.*版本使用的是Kotlin

同步请求
//创建okhttpclient对象
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
//创建Request 对象
Request request = new Request.Builder().get()
                .url("https://api.github.com/")
                .build();
//创建call对象
Call call= okHttpClient .newCall(request );
Response mResponse = call.execute();

异步请求
		//创建okhttpclient对象
        OkHttpClient okHttpClient = new OkHttpClient.Builder().build();

        //创建Request 对象
        Request request = new Request.Builder()
                .url("https://api.github.com/")
                .build();
		
        //创建call对象
        Call call = okHttpClient.newCall(request);
        
		//通过call.enqueue方法来提交异步请求
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                // 异步请求失败的操作

            }

            @Override
            public void onResponse(Call call, Response response) {
                // 异步请求成功的操作

            }
        });
onResponse() 和onFailure()回调方法在子线程执行的

OkHttp的使用比较简单,按照上面的一套流程下来就可以执行一次请求
重点在于分析源码,所以对于OkHttp的使用并不做过多的介绍


OkHttpClient创建

OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
这一个过程到底做了什么
最后调用 OkHttpClient(Builder 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.eventListenerFactory = builder.eventListenerFactory;
    this.proxySelector = builder.proxySelector;
    this.cookieJar = builder.cookieJar;
    this.cache = builder.cache;
    this.internalCache = builder.internalCache;
    this.socketFactory = builder.socketFactory;

    boolean isTLS = false;
    for (ConnectionSpec spec : connectionSpecs) {
      isTLS = isTLS || spec.isTls();
    }

    if (builder.sslSocketFactory != null || !isTLS) {
      this.sslSocketFactory = builder.sslSocketFactory;
      this.certificateChainCleaner = builder.certificateChainCleaner;
    } else {
      X509TrustManager trustManager = systemDefaultTrustManager();
      this.sslSocketFactory = systemDefaultSslSocketFactory(trustManager);
      this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
    }

    this.hostnameVerifier = builder.hostnameVerifier;
    this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
        certificateChainCleaner);
    this.proxyAuthenticator = builder.proxyAuthenticator;
    this.authenticator = builder.authenticator;
    this.connectionPool = builder.connectionPool;
    this.dns = builder.dns;
    this.followSslRedirects = builder.followSslRedirects;
    this.followRedirects = builder.followRedirects;
    this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
    this.connectTimeout = builder.connectTimeout;
    this.readTimeout = builder.readTimeout;
    this.writeTimeout = builder.writeTimeout;
    this.pingInterval = builder.pingInterval;

    if (interceptors.contains(null)) {
      throw new IllegalStateException("Null interceptor: " + interceptors);
    }
    if (networkInterceptors.contains(null)) {
      throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
    }
  }
参数:
  • dispatcher:请求的执行器,负责请求的同步执行、异步执行、取消、以及可以同时执行的最大请求数。
    包含三个请求队列:
    readyAsyncCalls :准备执行的异步请求列队
    runningAsyncCalls:正在执行的异步请求列队
    runningSyncCalls :正在执行的同步请求列队

  • proxy:网络的代理设置,可以通过他给网络请求设置代理

  • protocols:支持的Protocol协议
    java.net.URI.getScheme()返回url的协议(http, https, etc)
    Protocol.get()返回的协议更加具体(http/1.0,http/1.1,h2,etc)

  • connectionSpecs : 支持套接字连接协议.

  • interceptors: 拦截器

  • networkInterceptors : 网络拦截器

  • proxySelector :代理服务器选择器

  • cookieJar :提供cookie可持久化操作。

  • cache:缓存

  • internalCache:okhttp的内部缓存

  • socketFactory :创建套接字的工厂类

  • sslSocketFactory:创建ssl套接字工厂类

  • certificateChainCleaner:证书

  • hostnameVerifier:主机名验证

  • certificatePinner:约束所信任的证书

  • proxyAuthenticator:身份验证代理服务器

  • authenticator:身份验证代理服务器

  • connectionPool:连接池用于回收利用HTTP和HTTPS连接

  • dns:dns服务器;默认使用系统的

  • followSslRedirects:是否支持sslhttp重定向,默认true

  • followRedirects:是否支持http重定向,默认true

  • retryOnConnectionFailure:连接失败时是否重试,默认true

  • connectTimeout:连接超时

  • readTimeout:读取超时

  • writeTimeout:写入超时

参数有点多,大致了解下更容易理清OkHttp整体流程


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;
  }
  • url:请求地址
  • method :请求方法
  • body:请求体
  • headers :请求头
  • tag:请求标记
创建Call

Call call = okHttpClient.newCall(request);

实际上调用了RealCall.newRealCall

public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }
  
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    //添加 retryAndFollowUpInterceptor 拦截器,实现重新请求及取消请求功能
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
  }

call.enqueue(Callback responseCallback);执行请求
	public void enqueue(Callback responseCallback) {
    synchronized (this) {
    //一个 Call 只能请求一次,重复请求抛出异常,一个call只能调一次execute、enqueue
    if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }
client.dispatcher().enqueue(new AsyncCall(responseCallback))
synchronized void enqueue(AsyncCall call) {

 	 private int maxRequests = 64;
	 private int maxRequestsPerHost = 5;
 	
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      //将请求添加到分发器的执行队列,然后直接执行
      runningAsyncCalls.add(call);
      //通过线程池执行AsyncCall
      executorService().execute(call);
    } else {
      //将请求添加到分发器的就绪等待队列
      readyAsyncCalls.add(call);
    }
  }

enqueue方法比较简单,如果当前正在执行的任务数量还没达到64并且当前请求的任务所请求的主机对应的请求数没有超过5,就将当前任务加入runningAsyncCalls队列,并调用线程池执行,否则就将任务加入readyAsyncCalls队列

@Override protected void execute() {
      boolean signalledCallback = false;
      try {
      	//开启请求责任链,请求真正执行的位置
        Response response = getResponseWithInterceptorChain();
         //如果取消的就直接回调onFailure,传入new IOException("Canceled")
        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);
      }
    }

  void finished(AsyncCall call) {
  	//异步时,这里promoteCalls参数为true
    finished(runningAsyncCalls, call, true);
  }
`

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为false,不会调用promoteCalls方法
      //异步时promoteCalls为true,会调用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<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.
    }
  }

与同步请求调用finished方法不同的是,异步任务调用Dispatcher的finished方法时还会执行promoteCalls方法。promoteCalls方法主要就是从待执行的任务队列中取出一个任务加入到正在执行的任务队列,并调用线程池执行任务。

回到execute()中getResponseWithInterceptorChain()方法
Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    //下面是添加一系列拦截器,个人觉得是okhttp的精妙所在
    List<Interceptor> interceptors = new ArrayList<>();
    //将创建okhttpclient时的拦截器添加到interceptors
    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());
	//开启责任链
    return chain.proceed(originalRequest);
  }

最后:附上一张流程图~
OkHttp源码分析_第1张图片

关于拦截器链的源码分析,之后会再分析~

你可能感兴趣的:(【开源框架源码分析】)