OkHttp源码浅析

okhttp官方地址: https://square.github.io/okhttp/
okhttp的使用方法:
官方demo给出 直接new出一个OkHttpClient对象

//初始化OkHttpClient
OkHttpClient okHttpClient = new OkHttpClient();
//初始化Request
Request request = new Request.Builder().url("url").build();
//进行网络请求
//同步请求
Response response = okHttpClient.newCall(request).execute();
//异步请求
okHttpClient.newCall(request).enqueue(new Callback() {
     	@Override
     	public void onFailure(Call call, IOException e) {}
		
		@Override
        public void onResponse(Call call, Response response) throws IOException {}
   });

然后我们查看一下OkHttpClient源码,我们发现OkHttpClient在设计时使用了Builder模式,Builder模式一般用于构建对象时,里面存在很多复杂参数时采用。而在Android源码中AlertDialog就是使用Builder来构建的对象。现在回头来看OkHttp源码:

public OkHttpClient() {
  this(new Builder());
}

public static final class Builder {
   Dispatcher dispatcher;
   Proxy proxy;
   List<Protocol> protocols;
   ····· 省略部分参数
	public Builder() {
      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;
      pingInterval = 0;
    }

其中Builder是OkHttp的静态内部类,在Builder类中初始化话了一堆参数。
接下来初始化Request对象,我们发现其实它也是使用了Builder模式构建的

/**
     * Sets the URL target of this request.
     *
     * @throws IllegalArgumentException if {@code url} is not a valid HTTP or HTTPS URL. Avoid this
     * exception by calling {@link HttpUrl#parse}; it returns null for invalid URLs.
     */
    public Builder url(String url) {
      if (url == null) throw new NullPointerException("url == null");

      // Silently replace web socket URLs with HTTP URLs.
      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);
      }

      return url(HttpUrl.get(url));
    }

这里主要还是进行URL转换,除了添加url还有其他参数的设置,
在这里插入图片描述
接下来我们看看OkHttp的重点:网络请求
不管是同步还是异步都调用了newCall方法,所以来看看newCall到底做了什么。首先newCall通过静态方法创建了一个RealCall对象(不同版本可能不一样,有的是直接new的,Call是一个接口,并提供了一个内部接口Factory和一些请求方法,RealCall是其实现类),然后添加了eventListener参数,而该参数的创建代码已经贴出,具体自行查看。关于EventListener这个类主要还是用来监听网络请求的一些回调方法。

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

public Builder eventListenerFactory(EventListener.Factory eventListenerFactory) {
      if (eventListenerFactory == null) {
        throw new NullPointerException("eventListenerFactory == null");
      }
      this.eventListenerFactory = eventListenerFactory;
      return this;
    }

public Builder eventListener(EventListener eventListener) {
      if (eventListener == null) throw new NullPointerException("eventListener == null");
      this.eventListenerFactory = EventListener.factory(eventListener);
      return this;
    }

static EventListener.Factory factory(final EventListener listener) {
    return new EventListener.Factory() {
      public EventListener create(Call call) {
        return listener;
      }
    };
  }

public abstract class EventListener {
  public static final EventListener NONE = new EventListener() {
  };

  static EventListener.Factory factory(final EventListener listener) {
    return new EventListener.Factory() {
      public EventListener create(Call call) {
        return listener;
      }
    };
  }
  省略部分代码

接下来我们来看看 execute方法和enqueue方法:
首先来看看execute同步方法:内部主要调用了getResponseWithInterceptorChain()方法返回Response,该方法内部主要是构建了一系列的拦截器然后返回请求的结果,当中核心代码就是
responseCallback.onFailure(RealCall.this, new IOException(“Canceled”));和 responseCallback.onResponse(RealCall.this, response);一个是请求失败一个是请求成功。最终调用client.dispatcher().finished(this);

//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 {
        client.dispatcher().finished(this);
      }
    }

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, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
  }

接下来我们看看enqueue方法:
首先RealCall中的enqueue方法当中会通过OkHttpClient获取Dispatcher,而且我们发现不管是异步还是同步都调用了client.dispatcher(),那么这个Dispatcher到底是什么我们先来说说:我们发现当中有个ExecutorService,这个不就是我们经常创建线程池的类么,所以Dispatcher就是线程池的封装类,而且通过executorService()方法创建了一个单例线程池,然后看看Dispatcher中的enqueue方法,首先进行了判断如果正在执行请求的队列的请求数量小于maxRequests并且主机运行调用的数量小于主机的最大请求数量时,那么将该请求添加到正在执行请求的队列中,然后交给线程池处理,否则的话添加到正在准备的队列当中。那么当中的AsyncCall又是个什么鬼呢?下面继续说,

	//RealCall当中enqueue方法
  @Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

	//Dispatcher中的一些参数和enqueue方法
  private int maxRequests = 64;
  private int maxRequestsPerHost = 5;
  /** 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<>();

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

  /** Returns the number of running calls that share a host with {@code call}. */
  private int runningCallsForHost(AsyncCall call) {
    int result = 0;
    for (AsyncCall c : runningAsyncCalls) {
      if (c.get().forWebSocket) continue;
      if (c.host().equals(call.host())) result++;
    }
    return result;
  }


 //Dispatcher中的executorService
  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是RealCall的内部类,继承NamedRunnable,NamedRunnable又实现了Runnable接口,在它的run方法中又调用了execute方法,而这个execute方法跟同步请求的execute方法最终执行的是同一个方法,也就是最终还是通过getResponseWithInterceptorChain()方法返回Response。

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


@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 {
        client.dispatcher().finished(this);
      }
    }

好了,大致的整体流程就是这样,还有就是OkHttpClient中添加一些拦截器什么的,后续有时间在更新。如果文中存在误导性的错误,欢迎大家纠正交流。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值