--- title: OkHTTP3 同步基本流程 date: 2020-06-08 16:15:55 tags: [kotlin] categories: [kotlin] author: Karl --- # Okhttp3 同步基本流程 ## 流程分析 ### OkhttpClient 使用Okhttp,首先需要实例化一个OkhttpClient对象。支持2种构造方式 1. 默认方式 ~~~ val client = OkhttpClient() ~~~ 2.使用建造者方式 ~~~ val client = OkhttpClient.Builder() .build() ~~~ 他们的具体实现为 ~~~ public OkhttpClient() { this(new Builder()); } ~~~ 可以看到这种方式,不需要配置任何参数,也就是说基本参数都是默认的,调用的是下面的构造函数。 ~~~ OkHttpClient(Builder builder) { 。。。。 } ~~~ 建造者返回一个OkhttpClient实例 ~~~ public OkHttpClient build() { return new OkHttpClient(this); } ~~~ 我们查看源码发现默认方式其实是使用了2种设计模式: 1.外观模式 2.建造者模式 ### Request OkhttpClient完成后就需要构建一个Request对象,我们查看Requests对象找不到过多的构造函数,唯一的构造函数是这样的 ~~~ 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); } ~~~ 这就是在告诉我们,创建Requests实例需要使用Builder模式进行构建 ~~~ public Builder newBuilder() { return new Builder(this); } public static class Builder { @Nullable HttpUrl url; String method; Headers.Builder headers; @Nullable RequestBody body; Map, Object> tags = Collections.emptyMap(); 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., Object>emptyMap() : new LinkedHashMap<>(request.tags); this.headers = request.headers.newBuilder(); 。。。 } ~~~ 查看其他的对象发现也是基本使用Builder模式进行构建,所以此处就不在继续查看 ### 同步请求 我们需要构建一个call,一般使用 val call = okhttpClient.newCall(request)构建,去查看OkHttpClient源码 ~~~ @Override public Call newCall(Request request) { return RealCall.newRealCall(this, request, false /* for web socket */); } ~~~ @Override 看到这个注解我们就要意识到,这个方法不是继承就是实现接口 我们继续往源码翻,发现他是实现了Call.Factory接口 ~~~ interface Factory { Call newCall(Request request); } ~~~ 这里又使用了新的设计模式,工厂设计模式,具体的实例由其子类产生。 将构建的细节交给具体实现,顶层只需要拿到Call对象即可。 我们继续查看RealCall中的newRealCall方法 ~~~ 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.eventListener = client.eventListenerFactory().create(call); return call; } ~~~ 这里是一个静态方法, 创建了一个EventListener对象,名字可以看出,这是一个监听事件的对象从构造方法看出,这里使用了工厂设计创建的eventListener 继续查看RealCall的构造函数 ~~~ private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) { this.client = client; this.originalRequest = originalRequest; this.forWebSocket = forWebSocket; //添加了RetryAndFollowUpInterceptor拦截器 this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket); this.timeout = new AsyncTimeout() { @Override protected void timedOut() { cancel(); } }; this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS); } ~~~ 核心来了,执行请求 我们首先看的是同步请求 ~~~ Response execute() throws IOException; /*** Schedules the request to be executed at some point in the future. * *

The {@link OkHttpClient#dispatcher dispatcher} defines when the request will run: usually * immediately unless there are several other requests currently being executed. * *

This client will later call back {@code responseCallback} with either an HTTP response or a * failure exception. * * @throws IllegalStateException when the call has already been executed. */ //异步请求方法 void enqueue(Callback responseCallback); ~~~ 我们查看具体的实现,在RealCall中实现了这个方法 ~~~ @Override public Response execute() throws IOException { synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } captureCallStackTrace(); timeout.enter(); eventListener.callStart(this); try { client.dispatcher().executed(this); 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); } } ~~~ synchronized加入了对象锁,防止多线程同时调用,这里先判断一下executed是否为true判断当前call是否被执行了,如果为ture,则抛出异常,没有则设置为true captureCallStackTrace() ~~~ private void captureCallStackTrace() { Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()"); retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace); } ~~~ 源码来看是为了前文添加的过滤器添加一系列的堆栈信息 timeout.enter(); 这里应该是进行超时之类的校验,不深究继续往下看 eventListener.callStart(this); 可以看到前面构建的eventListener起到作用了,这里先回调callStart方法。 client.dispatcher().executed(this); 这里出现一个新的东东: dispatcher,所以我们回到OkhttpClient代码中去查看这个到底是什么东西 ~~~ public Dispatcher dispatcher() { return dispatcher;} ~~~ 看到是返回了一个Dispathcer对象,没有其他任何东西,我们继续点进去看看Dispatcher是什么 先对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. */ public final class Dispatcher { private int maxRequests = 64; private int maxRequestsPerHost = 5; private @Nullable Runnable idleCallback; private @Nullable ExecutorService executorService; private final Deque readyAsyncCalls = new ArrayDeque<>(); private final Deque runningAsyncCalls = new ArrayDeque<>(); private final Deque runningSyncCalls = new ArrayDeque<>(); } ~~~ 从注释中我们可以知道这是一个关于何时执行异步请求的策略 可以看到,最大请求数64,同一个host请求5,这里用三个队列ArrayDeque用于保存Call对象,分为三种状态异步等待,同步running,异步running。 前方使用的client.dispatcher().executed(this); executed在Dispatcher中为 ~~~ synchronized void executed(RealCall call) { runningSyncCalls.add(call);} ~~~ 将当前call塞入同步running队列中 Response result = getResponseWithInterceptorChain(); getResponseWithInterceptorChain() 这个方法就是OkHtpp中的核心 我们点开这个方法 ~~~ Response getResponseWithInterceptorChain() throws IOException { // Build a full stack of interceptors. List 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) { //配置 OkHttpClient 时设置的 networkInterceptors 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); } ~~~ 注意Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0, originalRequest, this, eventListener, client.connectTimeoutMillis(), client.readTimeoutMillis(), client.writeTimeoutMillis());中的0 我们看到这个方法是添加拦截器,然后调用chian中的proceed方法,我们继续查看proceed方法 ~~~ public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec, RealConnection connection) throws IOException { 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. RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec, connection, index + 1, request, call, eventListener, connectTimeout, readTimeout, writeTimeout); Interceptor interceptor = interceptors.get(index); 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; } ~~~ 初看很乱但核心在这几行代码 ~~~ RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec, connection, index + 1, request, call, eventListener, connectTimeout, readTimeout, writeTimeout); Interceptor interceptor = interceptors.get(index); Response response = interceptor.intercept(next); ~~~ 这样就很清晰了,这里index就是我们刚才的0,也就是从0开始,如果index超过了过滤器的个数抛出异常,后面会再new一个RealInterceptorChain,而且会将参数传递,并且index+1了,接着获取index的interceptor,并调用intercept方法,传入新new的next对象,这里用了递归的思想来完成遍历。这里也就是okhttp最经典的责任链模式。在这里找不到退出的地方,我们往前getResponseWithInterceptorChain()方法interceptors.add(new CallServerInterceptor(forWebSocket));这是最后加载的一个拦截器,我们进去查看 ~~~ @Override public Response intercept(Chain chain) throws IOException { ... return response; } ~~~ 篇幅太长,我们省略一下 看见这个拦截器并没有继续调用链中intercept方法,而是直接返回的response对象 同步的我们就分析到这里 Author: Karl