okhttp源码分析

前言

对于OkHttp我接触的时间其实已经很长了,项目里面一直都是使用Retrofit + OkHttp 来做网络请求的。之前也有粗略看过一点源码,但是理解得不够深。最近一段时间终于闲下来,对okhttp的源码重新阅读了一遍。这里我将看okhttp源码的一些心得记录下来,希望对大家有所帮助。

整体流程

Okhttp网络请求的整个流程为:首先,我们通过OkhttpClient.Builder()构建OkhttpClient对象,然后通过newCall将构建好的Request转换为Call,接着在RealCall里面进行同步execute或异步enqueue任务,最后通过一些的拦截器interceptor发出网络请求和得到返回的response。
在这里插入图片描述
首先我们来看一下GET请求的基本用法:

//HTTP GET
    public String okHttpGet(String url) throws IOException {
        //创建OkHttpClinet对象
        OkHttpClient okHttpClient = new OkHttpClient();
        //创建Request对象
        Request request = new Request.Builder().url(url).build();
        //执行网络请求同步execute任务
        Response response = okHttpClient.newCall(request).execute();
        if(response.isSuccessful()){
            return response.body().toString();
        }else{
            return "请求失败,message:" + response.message();
        }

    }

分析
1.OkHttpClient
从上文可以看出,首先我们需要初始化一个OkhttpClient对象。OkhttpClient有两种构造方式
1.默认方式,空参构造方法,内部调用的是带Builder参数的构造方法。所以基本参数都是默认的。

    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.eventListenerFactory = builder.eventListenerFactory;
    this.proxySelector = builder.proxySelector;
    this.cookieJar = builder.cookieJar;
    this.cache = builder.cache;
    this.internalCache = builder.internalCache;
    this.socketFactory = builder.socketFactory;
    }

2.builder模式,通过Builder来配置参数,最后通过build()方法返回OkhttpClient对象。

public OkHttpClient build() {
      return new OkHttpClient(this);
    }

从上面的构造方法可以看出,使用了builder设计模式。

2.Request
构建完OkhttpClient后,我们又构建了一个Request对象。查看Request源码,我们可以发现,构建Request对象同样使用了 builder设计模式

public Builder() {
      this.method = "GET";
      this.headers = new Headers.Builder();
    }

    Builder(Request request) {
      this.url = request.url;
      this.method = request.method;
      this.body = request.body;
      this.tag = request.tag;
      this.headers = request.headers.newBuilder();
    }
     public Request build() {
      if (url == null) throw new IllegalStateException("url == null");
      return new Request(this);
    }

3.Call
构建完Request对象后,接着我们还需要构建Call对象。通过newCall(request)方法来构建,内部实际上创建了RealCall对象。

 /**
   * Prepares the {@code request} to be executed at some point in the future.
   */
  @Override public Call newCall(Request request) {
    return new RealCall(this, request, false /* for web socket */);
  }
RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    final EventListener.Factory eventListenerFactory = client.eventListenerFactory();

    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);

    // TODO(jwilson): this is unsafe publication and not threadsafe.
    this.eventListener = eventListenerFactory.create(this);
  }

从源码可以看出,在RealCall的构造方法中,除了一些赋值外,默认还会创建一个retryAndFollowUpInterceptor(失败和重定向)过滤器。后续文章会讲到okhttp里面使用到的过滤器。
4.execute()
构建完Call对象,调用RealCall的execute()方法来实现同步任务。所以我们要看一下RealCall的execute方法。

 @Override 
 public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    try {
      client.dispatcher().executed(this);
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } finally {
      client.dispatcher().finished(this);
    }
  }

1.首先利用synchronized加入了对象锁,检查当前的RealCall是否已经被执行。
2. 真正去执行网络请求,返回Response结果的是getResponseWithInterceptorChain
方法。
5.getResponseWithInterceptorChain

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));

    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    return chain.proceed(originalRequest);
  }

从上面的源码可以看出,首先创建了一个Interceptor的ArrayList,然后加入了各种各样的过滤器。
1.client.interceptors():在创建OkhttpClient对象时,会默认给我们实现这些过滤器
2.retryAndFollowUpInterceptor:失败和重定向过滤器
3.BridgeInterceptor:负责将Request和Response进行封装
4.CacheInterceptor:负责读取缓存,更新缓存
5.ConnectInterceptor:负责和服务器建立连接
6.client.networkInterceptors():在创建OkhttpClient对象设置的networkInterceptors
7.CallServerInterceptor:负责向服务器发送请求数据,从服务器读取响应数据

添加完过滤器之后,就是执行过滤器了。

    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    return chain.proceed(originalRequest);
  }

从上面可以看出,这里创建了一个RealInterceptorChain对象,index为0,并且调用了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);
    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;
  }

从上面的源码可以看出,首先判断index是否超过过滤器的数量,如果超过,则抛出异常。后面会再次创建RealInterceptorChain对象,index变为index + 1,接着获取对应的interceptor,调用intercept方法,重复进行操作,直到能够获取到Response就跳出循环。这里利用了递归思想,也就是okHttp最经典的责任链模式。

至此,okhttp同步请求的流程就讲解完毕,下面我们来说一下异步请求的流程:

异步GET请求示例

 /**
   * Prepares the {@code request} to be executed at some point in the future.
   */
  @Override public Call newCall(Request request) {
    return new RealCall(this, request, false /* for web socket */);
  }
 //HTTP GET
    public void okHttpGetAsy(String url) throws IOException {
        //创建OkHttpClinet对象
        OkHttpClient okHttpClient = new OkHttpClient();
        //创建Request对象
        final Request request = new Request.Builder().url(url).build();
        //执行网络请求异步enqueue任务
       okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.e("onFailure",e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if(response.isSuccessful()){
                    Log.d("isSuccessful",response.body().toString());
                }
            }
        });

    }

首先,我们来看RealCall的enqueue()方法

 @Override 
 public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

里面调用了Dispatcher类中的enqueue(Call )方法,接着继续看:

 synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

当运行中的异步请求数量runningAsyncCalls不满并且主机正在运行的呼叫数量runningCallsForHost小于最大数,则将call加入runningAsyncCalls中,并用线程池执行call.否则将call加入readyAsyncCalls。

 /** 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到线程池中执行,接着我们看AsyncCall代码

 final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;

    AsyncCall(Callback responseCallback) {
      super("OkHttp %s", redactedUrl());
      this.responseCallback = responseCallback;
    }

    String host() {
      return originalRequest.url().host();
    }

    Request request() {
      return originalRequest;
    }

    RealCall get() {
      return RealCall.this;
    }

    @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 {
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }

AysncCall中的execute()中的方法,同样是通过Response response = getResponseWithInterceptorChain();来获得response。接下来的流程就跟同步的流程一样。

总结:

以上就是Okhttp同步和异步请求的流程解析。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值