okhttp请求与响应执行过程

okhttp请求与响应执行过程

前言

不考虑真正的网络请求部分,看一下从一个RequestResponse的过程。

请求

再来看一下上一篇最简单的执行代码

OkHttpClient httpClient = new OkHttpClient.Builder()
        .build();

Request request = new Request.Builder()
        .url("https://wanandroid.com/wxarticle/chapters/json")
        .get()
        .build();

Call call = httpClient.newCall(request);
Response response = call.execute();

System.out.println(response.body().string());

OkHttpClient

Factory for {@linkplain Call calls}, which can be used to send HTTP requests and read their responses.

翻译:Call的工厂类,用于发送HTTP请求,读取响应。

OkHttpClient实现类Call.Factory接口,下面是源码,实际上只构造一个Call实例。

// Call.Factory
interface Factory {
    Call newCall(Request request);
}

// OkHttpClient 实现
@Override
public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
}

OkHttpClient多用于配置,最重要的方法就是Call newCall(Request),在这个方法中,实际上构造了一个RealCall,最后一个参数用于长连接,目前没有用到。并且构造了一个Transmitter

private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
}

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

Bridge between OkHttp’s application and network layers. This class exposes high-level application layer primitives: connections, requests, responses, and streams.

翻译:是OkHttp应用层与网络层的桥梁。这个类向上面应用层暴露基本信息:连接、请求、响应、流。

Transmitter,可以直接翻译成发射器,将网络层的信息如资源、执行过程告诉应用层(即OkHttpClient配置的一些参数如EventListener

RealCall

我们得到了Call实例之后可以使用execute()同步执行,enqueue(Callback)异步执行。下面看看这两个方法的执行。

同步执行

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

前面是一些额外的处理,真正执行的代码在try-finally中。

RealCall.getResponseWithInterceptorChain()

为了不影响结构,先说一下getResponseWithInterceptorChain()方法,这也是最重要的方法。

Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    // 构造Interceptor栈
    List<Interceptor> interceptors = new ArrayList<>();
    // 添加配置的Interceptor
    interceptors.addAll(client.interceptors());
    // 下面添加逻辑处理的的Interceptor
    interceptors.add(new RetryAndFollowUpInterceptor(client));
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    // 添加配置的networkInterceptor,不是长连接才添加
    if (!forWebSocket) &#123;
        interceptors.addAll(client.networkInterceptors());
    &#125;
    // 添加真正执行的网络连接的Interceptor
    interceptors.add(new CallServerInterceptor(forWebSocket));

    // 构造Interceptor链
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
            originalRequest, this, client.connectTimeoutMillis(),
            client.readTimeoutMillis(), client.writeTimeoutMillis());

    // 标记请求是否抛出异常
    boolean calledNoMoreExchanges = false;
    try &#123;
        // 执行Interceptor责任链
        Response response = chain.proceed(originalRequest);
        // 若在执行过程前已经关闭了,则关闭Response并抛出异常
        if (transmitter.isCanceled()) &#123;
            closeQuietly(response);
            throw new IOException("Canceled");
        &#125;
        // 返回结果
        return response;
    &#125; catch (IOException e) &#123;
        // 标记发生了异常,抛出异常,并申请关闭连接
        calledNoMoreExchanges = true;
        throw transmitter.noMoreExchanges(e);
    &#125; finally &#123;
        // 若未发生异常,申请关闭连接
        if (!calledNoMoreExchanges) &#123;
            transmitter.noMoreExchanges(null);
        &#125;
    &#125;
&#125;

这一段代码,将一个Request处理得到Response

1. 构造Interceptor责任链

在知道Interceptor责任链的功能前,先不详说,只需要知道,这个责任链处理了Request得到Response

2. 执行责任链

这个是最重要的代码,这部分后面隐藏着整个OkHttp的核心。

3. 结果处理

若执行过程中已经取消,那么清理资源。

异步执行

@Override
public void enqueue(Callback responseCallback) &#123;
    // 判断是否已经执行,并且只能执行一次
    synchronized (this) &#123;
        if (executed) throw new IllegalStateException("Already Executed");
        executed = true;
    &#125;
    // 发送开始执行的通知
    transmitter.callStart();
    // 加入执行队列中
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
&#125;

没有实际的代码,只是在将一个AsnycCall添加到Dispatcher中的队列。

AsyncCall

AsyncCall是在RealCall的一个内部类,它继承自NamedRunnable,而NamedRunnable实现了Runnable接口,下面是源码,只是将当前线程设置了一个名字,并且将逻辑抽象成了execute()方法。

public abstract class NamedRunnable implements Runnable &#123;
    protected final String name;

    public NamedRunnable(String format, Object... args) &#123;
        this.name = Util.format(format, args);
    &#125;

    @Override
    public final void run() &#123;
        // 设置当前线程的名字
        String oldName = Thread.currentThread().getName();
        Thread.currentThread().setName(name);
        try &#123;
            execute();
        &#125; finally &#123;
            Thread.currentThread().setName(oldName);
        &#125;
    &#125;

    protected abstract void execute();
&#125;

下面是AsyncCall.execute()实现

@Override
protected void execute() &#123;
    boolean signalledCallback = false;
    transmitter.timeoutEnter();
    try &#123;
        Response response = getResponseWithInterceptorChain();
        signalledCallback = true;
        responseCallback.onResponse(RealCall.this, response);
    &#125; catch (IOException e) &#123;
        if (signalledCallback) &#123;
            // Do not signal the callback twice!
            Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        &#125; else &#123;
            responseCallback.onFailure(RealCall.this, e);
        &#125;
    &#125; finally &#123;
        client.dispatcher().finished(this);
    &#125;
&#125;

这里也是调用了RealCall.getResponseWithInterceptorChain()方法,并且处理了回调。所以只需要将AsyncCall作为Runnable使用ExecutorService执行,就自然而然执行了。

Dispatcher

Policy on when async requests are executed.
Each dispatcher uses an {@link ExecutorService} to run calls internally. If you supply your own executor, it should be able to run {@linkplain #getMaxRequests the configured maximum} number of calls concurrently.

翻译:异步执行时的策略。每个Dispatcher在内部使用一个ExecutorService去执行Call。如果你提供自己的执行器,应该能够保证getMaxRequests得到的配置最大数量的请求。

查看源码,实际上内部有三个ArrayDeque双向队列用于管理Call,其中一个用于管理同步执行的RealCall,另外两个用于管理异步执行的AsyncCall

先看一下在RealCall.execute()方法Dispatcher做了什么:

/**
 * Used by &#123;@code Call#execute&#125; to signal it is in-flight.
 * 用于标记Call正在执行
 */
synchronized void executed(RealCall call) &#123;
    runningSyncCalls.add(call);
&#125;
/**
 * Used by &#123;@code Call#execute&#125; to signal completion.
 * 用于标记同步执行完毕
 */
void finished(RealCall call) &#123;
    finished(runningSyncCalls, call);
&#125;
private <T> void finished(Deque<T> calls, T call) &#123;
    Runnable idleCallback;
    synchronized (this) &#123;
        // 判断错误
        if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
        // Dispatcher空闲时的回调接口
        idleCallback = this.idleCallback;
    &#125;

    // 判断Dispatcher是否有在执行的任务,并推动队列执行
    boolean isRunning = promoteAndExecute();

    // 当Dispatcher没有在执行代码时,执行空闲借口回调
    if (!isRunning && idleCallback != null) &#123;
        idleCallback.run();
    &#125;
&#125;

实际上只是先将RealCall添加到了这个双向队列中,标记它正在被执行,执行结束后,做移除它。

当然它还做了一些额外的工作,如回调空闲接口、通知其他在排队执行的任务开始执行。

下面看看enqueue()做了什么

void enqueue(AsyncCall call) &#123;
    synchronized (this) &#123;
        // 添加到准备执行的双向队列中
        readyAsyncCalls.add(call);

        // Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
        // the same host.
        // 转换AsyncCall,便于在多个运行同一host的Call中分享AtomicInteger,这个AtomicInteger标记在同一host上同时运行的数量
        if (!call.get().forWebSocket) &#123;
            AsyncCall existingCall = findExistingCallWithHost(call.host());
            if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
        &#125;
    &#125;
    // 推动队列执行
    promoteAndExecute();
&#125;

关于promoteAndExecute()方法的执行,可以在详解Dispatcher时深入,先看下这个方法的注释:

Promotes eligible calls from {@link #readyAsyncCalls} to {@link #runningAsyncCalls} and runs them on the executor service. Must not be called with synchronization because executing calls can call into user code.

翻译:将符合条件的Call从准备队列readyAsyncCalls移动到执行中队列runningAsyncCalls,然后使用ExecutorService执行。禁止同步执行,因为正在执行的Call能够会调用到使用者的代码。

意思是如果满足条件(如未达到最大执行数、同一host上的请求没有达到最大数)时,启动那些等待执行的Call。这个方法间接使用ExecutorService启动了AsyncCall.

总结

无论是同步执行,还是异步执行,核心代码都是RealCall.getResponseWithInterceptorChain(),除开一些额外的配置,最重要的是Interceptor责任链,这个责任链将一个Request转换成了一个Response。所以要明白OkHttp,就是理解Interceptor责任链。


   转载规则


《okhttp请求与响应执行过程》 Mycroft Wong 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
okhttp Interceptor责任链 okhttp Interceptor责任链
okhttp Interceptor责任链责任链 责任链模式将处理用户请求的对象形成一个链,责任链上的每个处理者要么处理用户的请求,要么把请求传递给责任链上的下一个处理者 实例: 请求 处理者:处理请求的对象 链:处理者形成的链表 说
下一篇 
okhttp基本概念 okhttp基本概念
okhttp基本概念okhttp官网 An HTTP client for Android, Kotlin, and Java. 官方介绍:Android, Kotlin, Java的HTTP客户端 基本类在使用okhttp时,我们一
  目录