3.OkHttp请求流程分析

3.OkHttp请求流程分析

Call和RealCall

经过上面的初始化之后 okhttpClient 调用public Call newCall(Request request) 方法去构建一个Call,

“““java
@Override
public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}

“““

可以看到 真实的Call是RealCall ,get知识点 一般来说,一个组织或者个人的代码风格是差不多的 这里面Call的实现类是RealCall,其他的应该也是Real开头的。

这里我们发现他把OkHttpClient和Reques传了过去,他的构造方法是

““`java
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);

}

““`

这里面比较面生的是的是RetryAndFollowUpInterceptor 按照字面意思重试和跟进拦截器 进去大概看一下

/**
 * This interceptor recovers from failures and follows redirects as necessary. It may throw an
 * {@link IOException} if the call was canceled.
 * 这个拦截器从故障中恢复,并根据需要遵循重定向。如果呼叫被取消,它可能会抛出IOException。
 */
public final class RetryAndFollowUpInterceptor implements Interceptor {
  /**
   * How many redirects and auth challenges should we attempt? Chrome follows 21 redirects; Firefox,
   * curl, and wget follow 20; Safari follows 16; and HTTP/1.0 recommends 5.
   * 我们应该尝试多少次重定向和认证挑战? Chrome遵循21次重定向; Firefox,curl和wget遵循20; Safari遵循16; HTTP / 1.0建议5。
   */
  private static final int MAX_FOLLOW_UPS = 20;

  private final OkHttpClient client;
  private final boolean forWebSocket;
  private StreamAllocation streamAllocation;
  private Object callStackTrace;
  private volatile boolean canceled;

  public RetryAndFollowUpInterceptor(OkHttpClient client, boolean forWebSocket) {
    this.client = client;
    this.forWebSocket = forWebSocket;
  }

  (....此处省略以后的代码)

果然和字面意思一样,这面看参数的话最大支持20次的重定向。后面的暂时不需要看 等用到的时候再看也不迟,避免陷入之间树木不见森林的坑

后面又用工厂方法创建了一个EventListener 的类,看字面意思就是时间的监听类看里面的方法

Factory
fetchStart
dnsStart
dnsEnd
connectStart
secureConnectStart
secureConnectEnd
connectEnd
requestHeadersStart
requestHeadersEnd
requestBodyStart
requestBodyEnd
responseHeadersStart
responseHeadersEnd
responseBodyStart
responseBodyEnd
fetchEnd

通过这个事件我们大致能看出来OkHttp请求的流程,然后回到RealCall ,之后调用的是一个execute或者是enqueue 我们在Android项目里由于主线程是不允许有网络请求的,所以我们先来搞enqueue,话不多说,进去看

java
@Override
public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
//捕获呼叫堆栈跟踪
captureCallStackTrace();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

Already Executed 这个异常大家在平时用的时候应该偶尔会碰到,原因看到了吧。当你的这个请求应在运行的时候你在去调用的时候就异常了

然后第二个是捕获呼叫堆栈跟踪器,这个就忽略掉,看真正的重头戏

前方高能预警,提起精神看

Dispatcher

调用的OkHttpClient 的dispatcher的enqueue方法,dispatcher的初始化是在OkHttpClient的Builder里面 看上面的代码 是直接new 了一个 Dispatcher ,我们去dispatcher里看

““`java
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 readyAsyncCalls = new ArrayDeque<>();

/* Running asynchronous calls. Includes canceled calls that haven’t finished yet. 运行异步调用包括尚未完成的取消请求/
private final Deque runningAsyncCalls = new ArrayDeque<>();

/* Running synchronous calls. Includes canceled calls that haven’t finished yet. 运行同步调用包括尚未完成的取消呼叫/
private final Deque runningSyncCalls = new ArrayDeque<>();

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

public Dispatcher() {
}

(….此处省略N行代码)

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

我们看到他的构造函数就是一个空的 然后全局变量的话有个线程池,和三个双端队列 有可能有同学不知道Deque是什么,deque 即双端队列。是一种具有队列和栈的性质的数据结构。双端队列中的元素可以从两端弹出,其限定插入和删除操作在表的两端进行。

我们看到enqueue里面就是操作运行异步调用包括尚未完成的取消请求的runningAsyncCalls,他的判断条件是:

1.当前队列里面的请求数量小于最大请求数也就是64

2.当前队列里面的链接的总host数量小于最大请求Host数

如果条件成立就添加到这个队列里面,否则的话就添加到readyAsyncCalls里,也就是按照他们将要运行的顺序进行准备就绪的异步调用的队列

加入到运行队列里后,执行executorService().execute(call);方法这个方法就是个new出了一个线程池,然后执行

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

可能关于线程池的一些东西大家不是特别清楚 这里稍微解释一下,首先是他的构造函数

java
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler)
corePoolSize: 线程池维护线程的最少数量
maximumPoolSize:线程池维护线程的最大数量
keepAliveTime: 线程池维护线程所允许的空闲时间
unit: 线程池维护线程所允许的空闲时间的单位
workQueue: 线程池所使用的缓冲队列
handler: 线程池对拒绝任务的处理策略

上面的SynchronousQueue可能一般同学看的不是特别熟悉这里解释一下:

SynchronousQueue是一个没有数据缓冲的BlockingQueue,生产者线程对其的插入操作put必须等待消费者的移除操作take,反过来也一样。

SynchronousQueue的一个使用场景的典型就是在线程池里。Executors.newCachedThreadPool()就使用了SynchronousQueue,这个线程池根据需要(新任务到来时)创建新的线程,如果有空闲线程则会重复使用,线程空闲了60秒后会被回收。执行是调用execute方法。

峰回路转 ,回到ReallCall的enqueue里面

这里执行的正式AsyncCall,new AsyncCall(responseCallback) AsyncCalls是RealCall的一个内部类,继承NamedRunnable,NamedRunnable是一个实现了Runnable接口的抽象类,

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

这里他做了两件事

  1. 给当前线程设设置了个名字
  2. 新增了一个抽象方法execute

把握住这两个 再来看AsyncCall

AsyncCall

“““java
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;

AsyncCall(Callback responseCallback) {
  //命名规则 OkHttp+协议名+域名
  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 {
    //调用dispatcer的finshed方法,(重要,在下文的请求调度分析会将)
    client.dispatcher().finished(this);
  }
}

}
“““

上面比较重要的是这一句

java
Response response = getResponseWithInterceptorChain();

如果重试和跟进拦截器没有被取消的话,返回请求成功调用 responseCallback.onResponse,如果中间有什么异常的话调用responseCallback.onFailure(RealCall.this, e);

getResponseWithInterceptorChain() 这个方法非常重要,是整个OkHttp请求的核心,他是组装了一系列的拦截链,进行链式调用,最后返回组装的请求结果

“““java
/*一共五个拦截器 包括
* RetryAndFollowUpInterceptor 重试和跟进拦截器
* BridgeInterceptor 桥拦截器
* CacheInterceptor 缓存拦截器
* ConnectInterceptor 链接拦截器
* CallServerInterceptor 呼叫服务拦截器
*
* RealInterceptorChain 实际拦截链
* */
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
//建立一个完整的拦截器堆栈。
List 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);

}
“““

接下来 我们来走进这些请求链的世界,去分析整个OkHttp请求的具体

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: com.squareup.okhttp3是一个开源的Java HTTP客户端库,它提供了简单易用的API,可以用于发送HTTP请求和处理响应。它支持HTTP/1.1和HTTP/2协议,并提供了连接池、缓存、压缩、重定向等功能,可以帮助开发者更高效地处理HTTP请求。 ### 回答2: com.squareup.okhttp3是一个针对Java语言的HTTP客户端库,由Square公司开发维护。它提供了一组强大的API,用于处理各种HTTP请求。com.squareup.okhttp3利用异步I/O和流来保证高效的请求和响应处理,同时支持HTTP/1.1和HTTP/2协议,可以进行简单的认证、重定向、缓存和重试。 com.squareup.okhttp3具有许多优点。首先,它是一个轻量级库,只需要简单的配置即可开始使用,没有复杂的依赖关系。其次,它提供了对各种网络协议的高级支持,支持TLS加密、GZIP压缩、websocket等。此外,它还可以通过拦截器等方式扩展其功能,以满足不同场景下的需要。 com.squareup.okhttp3还提供了丰富的文档和示例,帮助用户快速上手,解决常见的问题。它的社区活跃,在Stack Overflow等社区中有大量的解决方案和技术支持,方便用户进行技术交流和分享。 在实际应用中,com.squareup.okhttp3被广泛应用于移动应用、Web服务、大型企业级系统等场景,其稳定性和性能受到了广泛的认可。对于需要高效、优雅的网络请求处理的项目,com.squareup.okhttp3是一个不可或缺的工具。 ### 回答3: com.squareup.okhttp3是一个面向Java语言开发者的开源HTTP客户端库。它具有高效、稳定、简洁易用等优点,被广泛应用于Android、Kotlin和Java等语言的Android应用、Web应用和后台开发中。 com.squareup.okhttp3提供了一套完整的HTTP客户端操作与封装方案,涵盖了HTTP请求的发送、响应的解析、请求缓存的管理、单向/两向TLS握手协议的支持、HTTP2/HTTP1.1协议的切换、异步/同步请求等众多功能,提供了RESTfulAPI开发与HTTP服务通信所需要的基础、核心和扩展功能库。 相比传统的HttpUrlConnection类、Apache HttpComponents和HttpClient等HTTP客户端库,com.squareup.okhttp3具有更高的性能、更好的线程安全性和更完善的功能支持,基本能够满足各种HTTP客户端场景的需求。 除此之外,com.squareup.okhttp3还可以与RxJava、Guava、Jackson、Logging Interceptor、MockWebServer等其他开源库配合使用,提供更多API、工具类和自定义功能支持,可以扩展出更加丰富的应用场景和业务逻辑。 总之,com.squareup.okhttp3是一个优秀的HTTP客户端库,无论是在性能方面、功能方面还是在生态方面都表现优秀,它的出现为Java语言开发者带来了更多HTTP通信和RESTful API开发的便捷和高效。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值