Okhttp网络框架源码解析(一)

一、OKhttp请求简单用法

1、OKhttp请求图示

在这里插入图片描述

2、同步请求和异步请求实现步骤

1、创建OKhttpClient和Request对象。(均使用了build模式)
2、将Request封装成Call对象。
3、调用Call的execute(同步)/enqueue(异步)发送同步或异步请求。
注意:同步请求发送后就会进入阻塞状态,直到收到响应为止。

3、同步/异步请求代码简单实现

OKhttp的同步请求:

OkHttpClient client = new OkHttpClient.Builder().readTimeout(5, TimeUnit.SECONDS).build();
//同步请求
public void synRequest(){
    Request request = new Request.Builder().url("http://www.baidu.com").get().build();
    Call call = client.newCall(request);
    try {
       Response response =  call.execute();
        Log.e(TAG, "synRequest: "+response.body().string() );
    } catch (IOException e) {
        e.printStackTrace();
    }
}
//异步请求(onFailure和onResponse均在工作线程回调)
public void asyRequest(){
    Request request = new Request.Builder().url("http://www.baidu.com").get().build();
    Call call = client.newCall(request);
    call.enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {

        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            Log.e(TAG, "asyRequest: "+response.body().string() );
        }
    });
}

二、OKhttp请求源码分析

1、创建OKhttpClient对象

OKhttpClient的Builder方法源码分析:
Builder为OKhttpClient中的静态内部类

 public Builder() {
  dispatcher = new Dispatcher();
  protocols = DEFAULT_PROTOCOLS;
  connectionSpecs = DEFAULT_CONNECTION_SPECS;
  eventListenerFactory = EventListener.factory(EventListener.NONE);
  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;
}
  • dispatcher是OKhttp中比较核心的一个类,是分发器类,可以决定异步请求是缓存还是执行,把同步请求放入请求队列。
    同步请求中dispatch需要做的主要两个保存同步请求、移除同步请求,dispatch同步请求如下图所示:
    同步请求dispatch图示
  • connectionPool:连接池,可以把每一个客户端和服务端的连接抽象为connection,connectionPool中就是客户端和服务端所有的连接,可以决定某个连接是否复用。

2、构建携带请求信息的Request对象

Request的builder方法源码分析:

public Builder() {
  this.method = "GET";//定义请求方式为get
  this.headers = new Headers.Builder(); //创建Header用于保存请求头部信息
}

build()方法源码,就是把之前配置好的请求方法、头部信息、URL传给Request对象:

public Request build() {
  if (url == null) throw new IllegalStateException("url == null");
  return new Request(this);
}

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

3、call的newCall实际调用的RealCall

RealCall的构造方法:

private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client; //之前创建的client对象
this.originalRequest = originalRequest; //之前的request请求
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket); //维护了重定向拦截器
}
RealCall 的execute方法实现:
@Override public Response execute() throws IOException {
synchronized (this) {
 //同一个http请求只能执行一次,如果没有就把executed设为true,如果执行过则抛出异常
  if (executed) throw new IllegalStateException("Already Executed");
  executed = true;
}
//捕捉http请求的异常堆栈信息
captureCallStackTrace();
//监听方法,每当http请求开启execute或enqueue都会开启此监听方法
eventListener.callStart(this);
try {
 //
  client.dispatcher().executed(this);
  Response result = getResponseWithInterceptorChain(); //拦截器链方法
  if (result == null) throw new IOException("Canceled");
  return result;
} catch (IOException e) {
  eventListener.callFailed(this, e);
  throw e;
} finally {
  client.dispatcher().finished(this);//主动回收同步请求
}
}

client.dispatcher().executed(),dispatcher的同步请求将请求添加到队列之中

synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}

runningSyncCalls队列在dispatch中定义:

/** 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<>(); //同步执行队列

同步请求中dispatch的finish方法源码:

 void finished(RealCall call) {
finished(runningSyncCalls, call, false);
}

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!");
  //同步请求此方法以下方法不会被调用
  if (promoteCalls) promoteCalls();
  //runningCallsCount计算执行的异步和同步请求
  runningCallsCount = runningCallsCount();
  idleCallback = this.idleCallback;
}

if (runningCallsCount == 0 && idleCallback != null) {
  idleCallback.run();
}
}

runningCallsCount源码:

public synchronized int runningCallsCount() {
   //正在执行的异步请求和同步请求之和
   return runningAsyncCalls.size() + runningSyncCalls.size();
}
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));
}

AsyncCall源码:

//AsyncCall 继承NamedRunnable
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
......
}

NamedRunnable源码:

//NamedRunnable实际实现了Runnable接口
public abstract class NamedRunnable implements Runnable {
protected final String name;
......
}

继续分析dispatch的enqueue方法:

private int maxRequests = 64;
private int maxRequestsPerHost = 5;
......
synchronized void enqueue(AsyncCall call) {
//判断正在运行的异步请求数是否小于最大请求数,每台主机的运行请求数是否小于每台主机的最大请求数
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
  runningAsyncCalls.add(call);
  executorService().execute(call);
} else {
  readyAsyncCalls.add(call);
}
}

异步请求会先判断运行的异步请求数是否小于64,每台主机的运行请求数是否小于5,才会把请求添加到请求队列中,然后由线程池去执行请求。如果不是就会把该请求加到等待队列中。

线程池对象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;
}

executorService的execute方法的实现在AsyncCall的execute方法中,源码如下:

 @Override protected void execute() {
  boolean signalledCallback = false;
  try {
    Response response = getResponseWithInterceptorChain();
    //当重试拦截器被取消,会调用onFailure方法,否则会调用onResponse方法
    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);
  }
}

异步的dispatch的finished方法:

void finished(AsyncCall call) {
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!");
  if (promoteCalls) promoteCalls();
  runningCallsCount = runningCallsCount();
  idleCallback = this.idleCallback;
}

if (runningCallsCount == 0 && idleCallback != null) {
  idleCallback.run();
}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值