欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

OkHttp 源码分析

程序员文章站 2022-07-13 10:58:36
...

OkHttp 使用代码实例

private static final MediaType JSON
        = MediaType.parse("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();

String post(String url, String json) throws IOException {
    RequestBody body = RequestBody.create(JSON, json);
    Request request = new Request.Builder()
            .url(url)
            .post(body)
            .build();
    // 同步调用
    Response response = client.newCall(request).execute();
    // 异步调用
    client.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {

        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {

        }
    });
    return response.body().string();
}

源码分析

先来看 new OkHttpClient()

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

public Builder() {
    // 创建了 Dispatcher 对象
    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;
}

然后 clien.newCall(request) 创建了 RealCall 对象,这也是 OkHttp 中一个重要的类,先来分析异步执行的源码吧,因为同步执行跟异步的后半段没什么区别了。

@Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
        if (executed) throw new IllegalStateException("Already Executed");
        executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    // 执行 dispatcher 的 enqueue 方法,dispatcher 是在创建 HttpClient 对象时 new 的。注意这里传过去是的 new AsyncCall(responseCallback)
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

AsyncCall 是实现了 NamedRunnable

public abstract class NamedRunnable implements Runnable {
    // ...
    @Override public final void run() {
        // ...
        try {
            execute();
        } finally {
            Thread.currentThread().setName(oldName);
        }
    }

    protected abstract void execute();
}

可以看到就是实现的 Runnable 接口,如果在一个线程里执行,执行的就是 execute 方法。再接着看 dispatcher 的 enqueue 方法

    synchronized void enqueue(AsyncCall call) {
        if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
            // 添加到执行队列
            runningAsyncCalls.add(call);
            // 在子线程执行方法,executorService 就是创建了线程池。
            executorService().execute(call);
        } else {
            // 添加到等待队列
            readyAsyncCalls.add(call);
        }
    }

AsyncCall 执行的是 execute 方法,下面接着看这里

@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 {
            eventListener.callFailed(RealCall.this, e);
            // 返回回调失败
            responseCallback.onFailure(RealCall.this, e);
        }
    } finally {
        // 从 dispatcher 的运行队列中清除该 Runnable
        client.dispatcher().finished(this);
    }
}

Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    // 添加自己定义的 interceptor
    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, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());
    return chain.proceed(originalRequest);
}

来一个链式调用的例子吧,

// 实际执行
public static void main(String[] args) {
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.add(new Interceptor1());
    interceptors.add(new Interceptor2());
    InterceptorChain chain = new InterceptorChain(interceptors, 0);
    chain.proceed();
}

// 执行链
public class InterceptorChain {

    private List<Interceptor> interceptors;
    private int index;

    public InterceptorChain(List<Interceptor> interceptors, int index) {
        this.interceptors = interceptors;
        this.index = index;
    }

    public void proceed() {
        if (index >= interceptors.size()) {
            System.out.println("调用完");
            return;
        }
        InterceptorChain chain = new InterceptorChain(interceptors, index+1);
        Interceptor interceptor = interceptors.get(index);
        interceptor.proceed(chain);
    }
}

// Interceptor
public interface Interceptor {
    String proceed(InterceptorChain chain);
}

public class Interceptor1 implements Interceptor {

    @Override
    public String proceed(InterceptorChain chain) {
        System.out.println("Interceptor1 start");
        chain.proceed();
        System.out.println("Interceptor1 end");
        return "Interceptor1";
    }
}

public class Interceptor2 implements Interceptor {

    @Override
    public String proceed(InterceptorChain chain) {
        System.out.println("Interceptor2 start");
        chain.proceed();
        System.out.println("Interceptor2 end");
        return "Interceptor2";
    }
}

最终的执行结果是:
Interceptor1 start
Interceptor2 start
调用完
Interceptor2 end
Interceptor1 end

可以看到 1 先执行,在 1 里面调 2 的执行,2 执行完的返回结果,1 可以再进行处理。
来一张图解释下吧
OkHttp 源码分析

OkHttp 的调用过程用下面的图来简介一下
OkHttp 源码分析

相关标签: OkHttp