OKHttp源码分析

OkHttp是个目前比较流行的网络请求框架,现在大部分的应用都有在用它,看了很多大佬们写的OKHttp相关的博客,在这里记录下自己的分析过程。由于OkHttp内容比较多,这篇文章主要先简单分析下OkHttp请求的基本流程。
首先,在分析源码之前先看下使用OkHttp请求的示例代码:

val okHttpClient = OkHttpClient.Builder()
    .readTimeout(15, TimeUnit.SECONDS)
    .connectTimeout(10, TimeUnit.SECONDS)
    .build()

val request = Request.Builder()
    .url("https://blog.csdn.net/qq_21612413/article/details/87358000")
    .build()

val call = okHttpClient.newCall(request)
// 同步请求
// val response = call.execute()
// 异步请求
call.enqueue(object : Callback {
    override fun onFailure(call: Call, e: IOException) {
        println("failure")
    }

    override fun onResponse(call: Call, response: Response) {
        println("response:${response.body()?.string()}")
    }
})

可以看到,基本流程是先构建OkHttpClient和Request实例,然后通过调用newCall方法,传入request对象获得一个Call对象,通过这个Call对象来发起同步或异步请求。
OkHttp基本流程

1、获取OkHttpClient实例

通过有两个方式来获取OkHttpClient实例,一种是默认的构造方法,另一种是使用Builder模式来构建对象。

1.1、默认构造

val okHttpClient = OkHttpClient()

其内部构造函数使用了Builder对象,使用的都是默认配置:

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

public Builder() {
    dispatcher = new Dispatcher();
    protocols = DEFAULT_PROTOCOLS;
    connectionSpecs = DEFAULT_CONNECTION_SPECS;
    eventListenerFactory = EventListener.factory(EventListener.NONE);
    ... 省略
    connectTimeout = 10_000;
    readTimeout = 10_000;
    writeTimeout = 10_000;
    pingInterval = 0;
}

1.2、使用Builder模式构建

val okHttpClient = OkHttpClient.Builder()
    .readTimeout(15, TimeUnit.SECONDS)
    .connectTimeout(10, TimeUnit.SECONDS)
    .build()

可使用OkHttpClient.Builder类配置参数,最后调用build方法返回一个OkHttpClient对象。

public OkHttpClient build() {
    return new OkHttpClient(this);
}

2、Request对象的构建

val request = Request.Builder()
    .url("https://blog.csdn.net/qq_21612413/article/details/87358000")
    .build()

构建了一个OkHttpClient对象之后,我们还需要构建一个Request对象,通过查看它的构造函数可以看到,它也需要通过Builder模式来构建。

public static class Builder {
    @Nullable
    HttpUrl url;
    String method;
    Headers.Builder headers;
    RequestBody body;

    public Builder() {
        this.method = "GET";
        this.headers = new Headers.Builder();
    }

    Builder(Request request) {
        this.url = request.url;
        this.method = request.method;
        this.body = request.body;
        this.tags = request.tags.isEmpty()
                ? Collections.emptyMap()
                : new LinkedHashMap<>(request.tags);
        this.headers = request.headers.newBuilder();
    }

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

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

3、请求流程分析

val call = okHttpClient.newCall(request)
val response = call.execute()

通过newCall方法获取到Call对象后,再执行同步或异步请求,先看下newCall方法的内部实现:

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

RealCall类:
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    RealCall call = new RealCall(client, originalRequest, forWebSocket);
    call.eventListener = client.eventListenerFactory().create(call);
    return call;
}

可以看到,Call对象实际是RealCall类型

3.1、异步请求

执行Call的enqueue方法:

public void enqueue(Callback responseCallback) {

    // 判断是否已执行,如果已执行,则抛出异常
    synchronized (this) {
        if (executed) throw new IllegalStateException("Already Executed");
        executed = true;
    }
    // 捕获并设置堆栈信息日志
    captureCallStackTrace();
    eventListener.callStart(this);
    // 执行Dispatcher的enqueue方法
    // AsyncCall对象,该对象继承NamedRunnable
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

可以看到,enqueue方法不能被重复执行,否则会抛出IllegalStateException异常,该方法最后会执行Dispatcher的enqueue方法,传入了一个AsyncCall对象

void enqueue(AsyncCall call) {
    synchronized (this) {
        // 将请求放入异步准备队列
        readyAsyncCalls.add(call);
    }
    promoteAndExecute();
}

private boolean promoteAndExecute() {
    assert (!Thread.holdsLock(this));

    List<AsyncCall> executableCalls = new ArrayList<>();
    boolean isRunning;
    synchronized (this) {
        // 遍历异步准备队列
        for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
            // 取出Call对象
            AsyncCall asyncCall = i.next();

            // 判断异步Running队列的数量是否小于最大请求数量(默认为64)
            if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
            // 判断请求同一主机的个数是否小于maxRequestsPerHost(最大可请求主机个数,默认是5)
            if (runningCallsForHost(asyncCall) >= maxRequestsPerHost)
                continue; // Host max capacity.

            // 将Call对象移出异步准备队列
            i.remove();
            // 添加到执行集合
            executableCalls.add(asyncCall);
            // 添加到异步Running队列
            runningAsyncCalls.add(asyncCall);
        }

        isRunning = runningCallsCount() > 0;
    }

    // 遍历待执行集合
    for (int i = 0, size = executableCalls.size(); i < size; i++) {
        AsyncCall asyncCall = executableCalls.get(i);
        // 调用Call对象的executeOn方法
        // executorService返回一个线程池对象
        asyncCall.executeOn(executorService());
    }

    return isRunning;
}

该方法的作用主要是把任务放入readyAsyncCalls(异步准备队列),然后再遍历该队列判断任务是否可以被执行,如果可以,则将任务放入一个待执行对象集合中,最后遍历待执行对象集合将任务逐个放入线程池中执行,接下来看下AsyncCall的executeOn方法(传入的参数是个线程池对象):

void executeOn(ExecutorService executorService) {
        assert (!Thread.holdsLock(client.dispatcher()));
        boolean success = false;
        try {
            // 放入线程池中执行,AsyncCall继承了NamedRunnable对象,NamedRunnable的run方法执行了execute方法
            executorService.execute(this);
            success = true;
        } catch (RejectedExecutionException e) {
            InterruptedIOException ioException = new InterruptedIOException("executor rejected");
            ioException.initCause(e);
            eventListener.callFailed(RealCall.this, ioException);
            responseCallback.onFailure(RealCall.this, ioException);
        } finally {
            if (!success) {
                client.dispatcher().finished(this); // This call is no longer running!
            }
        }
    }

可以看到,由于AsyncCall继承自NamedRunnable类(实现了Runnable 接口),所以executorService.execute(this)会去执行NamedRunnable的run方法:

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() {
    // 在执行之前把当前线程的名字改为由构造生成的name,执行完execute方法后再把线程名字改回去
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
      execute(); // 执行
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }

  protected abstract void execute();
}

最后执行了execute方法:

protected void execute() {
    boolean signalledCallback = false;
    timeout.enter();
    try {
        // 调用拦截器,最终返回Response对象
        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) {
        e = timeoutExit(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);
    }
}

在execute方法中,会通过getResponseWithInterceptorChain方法(拦截器处理)返回Response对象,如果请求被取消了,则返回onFailure失败回调,否则,返回onResponse成功回调。这里需要注意的是,请求被取消,会回调到onFailure方法。接下来我们再来看下同步请求的流程:

3.2、同步请求

public Response execute() throws IOException {
    synchronized (this) {
        if (executed) throw new IllegalStateException("Already Executed");
        executed = true;
    }
    // 堆栈信息跟踪
    captureCallStackTrace();
    timeout.enter();
    eventListener.callStart(this);
    try {
        // 调用Dispatcher的executed方法,将Call对象添加进同步运行队列中
        client.dispatcher().executed(this);
        // 经过各种拦截器处理后最终返回Response对象
        Response result = getResponseWithInterceptorChain();
        if (result == null) throw new IOException("Canceled");
        return result;
    } catch (IOException e) {
        e = timeoutExit(e);
        eventListener.callFailed(this, e);
        throw e;
    } finally {
        client.dispatcher().finished(this);
    }
}

// Dispatcher的executed方法
synchronized void executed(RealCall call) {
    this.runningSyncCalls.add(call);
}

同步请求相对简单,在该方法中把Call对象放入了runningSyncCalls(同步运行队列)中,最终也调用getResponseWithInterceptorChain方法返回Response对象

3.3、拦截器处理返回Response

Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    // 构建个拦截器的集合
    List<Interceptor> interceptors = new ArrayList<>();
    // 添加自定义的拦截器
    interceptors.addAll(client.interceptors());
    // 添加错误处理和重定向拦截器
    interceptors.add(retryAndFollowUpInterceptor);
    // 封装request和response过滤器
    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));

    // 构建RealInterceptorChain,传入拦截器集合,request对象等,注意index为0这个参数
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
            originalRequest, this, eventListener, client.connectTimeoutMillis(),
            client.readTimeoutMillis(), client.writeTimeoutMillis());

    // 调用proceed方法
    return chain.proceed(originalRequest);
}

构建了个拦截器的集合,将它传入RealInterceptorChain对象,通过该对象来完成拦截器的链式调用。

public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
                            RealConnection connection) throws IOException {

    // 如果index大于或等于拦截器集合个数,则抛出异常
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;

    // If we already have a stream, confirm that the incoming request will use it.
    if (this.httpCodec != null && !this.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.httpCodec != null && calls > 1) {
        throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
                + " must call proceed() exactly once");
    }

    // Call the next interceptor in the chain.
    // 构建一个next的RealInterceptorChain,index+1
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
            connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
            writeTimeout);
    // 取出拦截器
    Interceptor interceptor = interceptors.get(index);
    // 调用拦截器的intercept方法,传入next对象,拿个拦截器看下里面具体的实现是怎样的
    Response response = interceptor.intercept(next);

    // Confirm that the next interceptor made its required call to chain.proceed().
    if (httpCodec != 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;
}

注意index这个参数,默认传入是为0,当构建一个next的RealInterceptorChain时,此时index+1了。执行流程是当前拦截器链会根据index取出对应位置的拦截器,调用拦截器的intercept方法,传入next对象。接着在拦截器中又会调用next对象的proceed方法,重新进入这个方法,然后又调用下一个拦截器的intercept方法(此时index+1),形成链式调用,直到最后一个拦截器(CallServerInterceptor)不调用next对象的proceed方法为止,最后逐级返回response对象。

@Override public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();
    //1 Request阶段,该拦截器在Request阶段负责做的事情

    //2 调用RealInterceptorChain.proceed(),其实是在递归调用下一个拦截器的intercept()方法
    response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);

    //3 Response阶段,完成了该拦截器在Response阶段负责做的事情,然后返回到上一层的拦截器。
    return response;     
    }
}

用下图来表示拦截器的执行流程:
拦截器执行流程

总结

这篇文章主要分析了下OKHttp的基本流程,还有很多细节还没有分析,例如拦截器等,在对整体有了清晰认识之后,再单独进行深入分析理解起来会相对简单点。最后用一张图(图来源于拆轮子系列:拆 OkHttp,感谢作者)来回顾下基本的请求流程:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值