Okhttp3的源码分析_小白看源码

2 篇文章 0 订阅
1 篇文章 0 订阅

开发项目很久了,一直在用Okhttp,今天下午时间充裕,却发现对okhttp理解少之又少。对它说不出什么所以然来。那就战吧,苦一下自己看源码去咯。
绝对以小白视角看源码,我会你会大家都会,都能懂源码的。以后去面试。照着说准没错!

首先我们看一下Okhttp的正常请求流程,以便我们在源码中找到入口

 mOkHttpClient=new OkHttpClient();
        Request.Builder requestBuilder = new Request.Builder().url("http://www.baidu.com");
        //可以省略,默认是GET请求
        requestBuilder.method("GET",null);
        Request request = requestBuilder.build();
        Call mcall= mOkHttpClient.newCall(request);
        mcall.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (null != response.cacheResponse()) {
                    String str = response.cacheResponse().toString();
                    Log.i("wangshu", "cache---" + str);
                } else {
                    response.body().string();
                    String str = response.networkResponse().toString();
                    Log.i("wangshu", "network---" + str);
                }
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(getApplicationContext(), "请求成功", Toast.LENGTH_SHORT).show();
                    }
                });
            }
        });
    }

1,入口处我们看到 – mOkHttpClien = new OkhttpClient(); 初始化一系列数据,暂且不管,后面哪些在我们看源码的进程上的话我们再分析。

  public OkHttpClient() {
    this(new Builder());
  }
      //Builder 是okhttpClient 中的一个内部类
      public Builder() {
      //一会我们将会用到dispatcher
      dispatcher = new Dispatcher();
      protocols = DEFAULT_PROTOCOLS;
      connectionSpecs = DEFAULT_CONNECTION_SPECS;
      proxySelector = ProxySelector.getDefault();
      cookieJar = CookieJar.NO_COOKIES;
      socketFactory = SocketFactory.getDefault();
      hostnameVerifier = OkHostnameVerifier.INSTANCE;
      certificatePinner = CertificatePinner.DEFAULT;
      proxyAuthenticator = Authenticator.NONE;
      authenticator = Authenticator.NONE;
      connectionPool = new ConnectionPool();
      dns = Dns.SYSTEM;
      followSslRedirects = true;
      followRedirects = true;
      retryOnConnectionFailure = true;
      connectTimeout = 10_000;
      readTimeout = 10_000;
      writeTimeout = 10_000;
    }

2, 初始化了一个RequestBuilder reBuilder = new Request.Builder().url(“http://www.baidu.com“);

  public Builder() {
      //默认的就是get,因此前面你能省略get请求
      this.method = "GET";
      this.headers = new Headers.Builder();
    }

    public Builder url(HttpUrl url) {
      if (url == null) throw new NullPointerException("url == null");
      this.url = url;
      return this;
    }

3,Url准备就绪,那就开始进入正文了

Request request = requestBuilder.build();
Call mcall= mOkHttpClient.newCall(request);
重要的部分在newCall();

@Override 
public Call newCall(Request request) {
    //返回一个RealCall,Call是个interface
    return new RealCall(this, request);
  }
protected RealCall(OkHttpClient client, Request originalRequest) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client);
  }

4,走到这,我们看出来了,调用enquene的是readcall,那就继续看他的方法是怎么回事

 @Override 
 public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
//1,这里又将问题抛回到OkHttpClient的对象了
//2.执行了一个异步的call
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }
  // 这个异步的call也暂时只记录这个请求回调,无关大事,我们继续走
 private AsyncCall(Callback responseCallback) {
      super("OkHttp %s", redactedUrl().toString());
      this.responseCallback = responseCallback;
    }

5,我们看到有dispatcher来执行enquene了,感觉好麻烦,传到okhttp初始化的时候了

public final class Dispatcher {
  //最大并发请求数
  private int maxRequests = 64;
  //每个主机最大请求数
  private int maxRequestsPerHost = 5;
  private Runnable idleCallback;

  /** Executes calls. Created lazily. */
   //消费者线程池 每次进来要么传进来一个,要么自己进行初始化,保证了此对象一直存在 
  private ExecutorService executorService;

  /** 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<>();

  public Dispatcher(ExecutorService executorService) {
    this.executorService = executorService;
  }

  public Dispatcher() {
  }
   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;
  }

6,再继续看他的enqueue

  synchronized void enqueue(AsyncCall call) {
  //当前运行的异步请求队列数小于64 运行的请求主机数小于5
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      // 这里保证了 线程池绝对初始化了
      executorService().execute(call);
    } else {
    // 否则的话再把请求增加到 准备请求队列
      readyAsyncCalls.add(call);
    }
  }

7,这里我们看到将call放到线程池去执行了,还记得吧,放入的是AsyncCall,那我们去看AsyncCall执行的方法

 @Override protected void execute() {
      boolean signalledCallback = false;
      try {
      // 得到Response了!! 那我就看这一步了,到底做了什么,就返回给我们数据了
        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 {
         // 回调了。。。。失败
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }

8,这个方法好像很麻烦啊,好吧我们先看最后简单,调用的这个finsh这个方法是什么意思

 synchronized void finished(AsyncCall call) {
 //运行的请求队列移除这个请求,失败的话抛异常
    if (!runningAsyncCalls.remove(call)) throw new AssertionError("AsyncCall wasn't running!");
    promoteCalls();
  }
   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.
    }
  }

9,NO! NO! NO! 访问网络的的流程我们走完了,但是怎么会偶去到数据的过程,我们也还是能看下最好。当然,你只为了了解okhttp的访问流程就不太需要后面的细节了。

// 这里它凭什么就能得到Response
  private 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 (!retryAndFollowUpInterceptor.isForWebSocket()) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(
        retryAndFollowUpInterceptor.isForWebSocket()));
//一大堆的拦截者  产生了一个拦截的Chain ,它看来是关键咯,执行了请求
    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    return chain.proceed(originalRequest);
  }

10,哎,看到这里我们发觉其实明白表层逻辑真没什么难度,就是麻烦,学习思想嘛,慢慢看下去。 进入到 RealInterceptorChain的proceed方法中去了

 public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      Connection 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 && !sameConnection(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);
        // 关键的在这里了 从拦截集合中取出当前请求的拦截,去执行方法了! 这里可能取出多个拦截器,还记得前面一直向一个集合放拦截器吗,对就是那里 报应来了,放的多也就取得多了!
    Interceptor interceptor = interceptors.get(index);
    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");
    }

    return response;
  }
  //有个疑问是不,要是拦截器太多会怎么办, 这里会阻塞的,当前拦截器会等待下一个拦截器执行完毕再返回!拦截器嘛,大多都是移除或者转换请求或者响应的头部信息。

11,这就麻烦了,拦截这里源码可是很多的

这里写图片描述
暂时先看到这里吧,后面这留个一个个讲的话太长了,本篇也够了!下回的话分第二篇吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值