前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >源码系列-OkHttp

源码系列-OkHttp

作者头像
用户3112896
发布2020-04-26 22:31:45
9460
发布2020-04-26 22:31:45
举报
文章被收录于专栏:安卓圈安卓圈

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

用法如下:(get请求)

代码语言:javascript
复制
package okhttp3.guide;
import java.io.IOException;import okhttp3.OkHttpClient;import okhttp3.Request;import okhttp3.Response;
public class GetExample {  OkHttpClient client = new OkHttpClient();
  String run(String url) throws IOException {    Request request = new Request.Builder()        .url(url)        .build();
    try (Response response = client.newCall(request).execute()) {      return response.body().string();    }  }
  public static void main(String[] args) throws IOException {    GetExample example = new GetExample();    String response = example.run("https://raw.github.com/square/okhttp/master/README.md");    System.out.println(response);  }}

Github下载源码地址https://github.com/square/okhttp

4.x以上的版本都大部分更新为kotlin了,可以更改分支下载3.x的版本来看

一、先来看第一步构造函数

代码语言:javascript
复制
OkHttpClient client = new OkHttpClient();

源码:

代码语言:javascript
复制
public OkHttpClient() {    this(new Builder());}

Builder()中就是初始化了一堆变量,没啥东西

二、来看get请求

代码语言:javascript
复制
new Request.Builder()

源码:找内部类Builder的构造函数

代码语言:javascript
复制
public Builder() {  this.method = "GET";  this.headers = new Headers.Builder();}

源码:接着找Headers的内部类Builder,暂时构造了一个变量,还没有做什么

三、下面是执行.url方法,当然是Request内部类Builder的url方法,url暂定为String

源码:

代码语言:javascript
复制
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));}

前面是加前缀,后面去到HttpUrl里去

代码语言:javascript
复制
public static HttpUrl get(String url) {    return new Builder().parse(null, url).build();  }

HttpUrl的内部类Builder的构造函数

代码语言:javascript
复制
public Builder() {  encodedPathSegments.add(""); // The default path is '/' which needs a trailing space.}

encodedPathSegments是一个ArrayList

HttpUrl的内部类Builder的parse方法就是一连串的参数解析,大家可以看源码

最后一个build()方法

代码语言:javascript
复制
public HttpUrl build() {  if (scheme == null) throw new IllegalStateException("scheme == null");  if (host == null) throw new IllegalStateException("host == null");  return new HttpUrl(this);}

这个HttpUrl的带参构造函数中也是一堆变量的初始化

回到Request内部类Builder的url方法

代码语言:javascript
复制
public Builder url(HttpUrl url) {  if (url == null) throw new NullPointerException("url == null");  this.url = url;  return this;}

接着是Request内部类Builder的build方法

代码语言:javascript
复制
public Request build() {  if (url == null) throw new IllegalStateException("url == null");  return new Request(this);}

Request的带参构造函数

代码语言:javascript
复制
Request(Builder builder) {  this.url = builder.url;  this.method = builder.method;  this.headers = builder.headers.build();  this.body = builder.body;  this.tags = Util.immutableMap(builder.tags);}

四。接下来很重要了,是执行请求

代码语言:javascript
复制
Response response = client.newCall(request).execute()

OkHttpClient中的newCall方法

代码语言:javascript
复制
@Override public Call newCall(Request request) {  return RealCall.newRealCall(this, request, false /* for web socket */);}

进到RealCall中的newRealCall方法

代码语言:javascript
复制
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.transmitter = new Transmitter(client, call);  return call;}

构造函数不用管,进去Transmitter中的构造函数

代码语言:javascript
复制
public Transmitter(OkHttpClient client, Call call) {  this.client = client;  this.connectionPool = Internal.instance.realConnectionPool(client.connectionPool());  this.call = call;  this.eventListener = client.eventListenerFactory().create(call);  this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);}

其中这个Internal.instance.realConnectionPool(client.connectionPool())可以找到OkHttpClient的static代码块执行后返回了一个RealConnectionPool

代码语言:javascript
复制
private static final Executor executor = new ThreadPoolExecutor(0 /* corePoolSize */,    Integer.MAX_VALUE /* maximumPoolSize */, 60L /* keepAliveTime */, TimeUnit.SECONDS,    new SynchronousQueue<>(), Util.threadFactory("OkHttp ConnectionPool", true));

RealConnectionPool一看就知道是0个核心线程,最大值个非核心线程的线程池;这里还出现了一个Deque双端队列,即队列的升级版,两个端口都可以进出元素,更加灵活

最后就是RealCall的execute方法了,注意RealCall里有个内部类AsyncCall也有execute方法,注意不要搞混了

代码语言:javascript
复制
@Override public Response execute() throws IOException {  synchronized (this) {    if (executed) throw new IllegalStateException("Already Executed");    executed = true;  }  transmitter.timeoutEnter();  transmitter.callStart();  try {    client.dispatcher().executed(this);    return getResponseWithInterceptorChain();  } finally {    client.dispatcher().finished(this);  }}

client.dispatcher().executed(this)执行的是

代码语言:javascript
复制
synchronized void executed(RealCall call) {    runningSyncCalls.add(call);  }

runningSyncCalls就是我们上面提到的Deque双端队列

下面就是最最核心的getResponseWithInterceptorChain方法

代码语言:javascript
复制
Response getResponseWithInterceptorChain() throws IOException {  // Build a full stack of interceptors.  List<Interceptor> interceptors = new ArrayList<>();  interceptors.addAll(client.interceptors());  interceptors.add(new RetryAndFollowUpInterceptor(client));  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, transmitter, null, 0,      originalRequest, this, client.connectTimeoutMillis(),      client.readTimeoutMillis(), client.writeTimeoutMillis());
  boolean calledNoMoreExchanges = false;  try {    Response response = chain.proceed(originalRequest);    if (transmitter.isCanceled()) {      closeQuietly(response);      throw new IOException("Canceled");    }    return response;  } catch (IOException e) {    calledNoMoreExchanges = true;    throw transmitter.noMoreExchanges(e);  } finally {    if (!calledNoMoreExchanges) {      transmitter.noMoreExchanges(null);    }  }}

RetryAndFollowUpInterceptor重试和跳转拦截器

BridgeInterceptor桥接拦截器,即加请求头和去响应头

CacheInterceptor缓存拦截器

ConnectInterceptor连接拦截器

CallServerInterceptor调用服务拦截器

List添加好全部Interceptor之后,执行chain.proceed(originalRequest)来到RealInterceptorChain中的proceed方法

代码语言:javascript
复制
public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)    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.exchange != null && !this.exchange.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.exchange != 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, transmitter, exchange,      index + 1, request, call, connectTimeout, readTimeout, writeTimeout);  Interceptor interceptor = interceptors.get(index);  Response response = interceptor.intercept(next);
  // Confirm that the next interceptor made its required call to chain.proceed().  if (exchange != 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;}
代码语言:javascript
复制
Interceptor interceptor = interceptors.get(index);Response response = interceptor.intercept(next);

一开始传入的index为0,就是从第一个拦截器开始执行每个拦截器的intercept方法,index逐次+1

每个拦截器里都调用chain.proceed,这样所有的拦截器就形成链条。这里每个拦截器的作用就不讲了

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-04-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 安卓圈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档