Okhttp3 源码解析(异步同步请求)
2018-01-23 15:14
821 查看
Okhttp3 源码解析(异步同步请求)
本篇主要通过代码流程对Okhttp3的请求流程进行分析。相信okhttp3使用大家都已经掌握,这里就不再赘述。基于okhttp3.9.1。
同步请求实例:
OkHttpClient client=new OkHttpClient(); //实例化一个OkHttpClient //Request request= new Request.Builder().build(); Request request = new Request.Builder() //实例化Request ,同时加入请求参数 .url("https://api.github.com/repos/square/okhttp/issues") .header("User-Agent", "OkHttp Headers.java") .addHeader("Accept", "application/json; q=0.5") .addHeader("Accept", "application/vnd.github.v3+json") .build(); Response response = null; try { response = client.newCall(request).execute(); //获取Response } catch (IOException e) { e.printStackTrace(); }
OkHttpClient 所有流程的总的控制者
我们打开OkHttpClient ,查看一下官方对其的描述Factory for {@linkplain Call calls}, which can be used to send HTTP requests and read their responses.
calls/call的工厂,它可以用来发送HTTP请求和读取他们的响应。
每一个call的创建都需要实例化OkHttpClient,同时OkHttpClient对请求的流程进行总的控制。
Request request = new Request.Builder()
这里是request 的请求集合,其中封装了我们请求的各种信息。response = client.newCall(request).execute();
关键代码response = client.newCall(request).execute();我们一步一步来分析,这里进行了一个同步的请求,execute()将会直接返回一个response 信息。
上面说过了client是总的流程的控制者,这里通过client创建了一个newCall
newCall
newCall又是什么?打开代码看一下。
@Override public Call newCall(Request request) { return RealCall.newRealCall(this, request, false /* for web socket */); }
在client中通过newCall(Request request)创建了一个call对象,其通过
RealCall.newRealCall(this, request, false /* for web socket */);进行创建,所以这个流程又到了RealCall中
RealCall 请求的实际调用者
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) { // Safely publish the Call instance to the EventListener. RealCall call = new RealCall(client, originalRequest, forWebSocket); //返回一个RealCall call.eventListener = client.eventListenerFactory().create(call); //???? return call; }
可以看到newRealCall是一个静态方法,仅限于包内访问,所以我们不能够直接调用newRealCall(),可以看到这里通过调用自身的构造函数返回了一个RealCall对象,因为RealCall对象实现了Call接口,所以可以进行转换。
call.eventListener = client.eventListenerFactory().create(call);
接着这段代码就让人摸不着头脑了,既然已经返回了RealCall了,这个函数又是什么意思。
观看代码,发现这个eventListener 还是通过client进行调用的,不然怎么会是流程总的控制者嘛。
来到eventListenerFactory()这个工厂中来看一下。
public EventListener.Factory eventListenerFactory() { return eventListenerFactory; }
直接返回了一个eventListenerFactory,???这个eventListenerFactory我们又没有初始化过,怎么实现的?
搜索eventListenerFactory ,发现在Builder中有如下的代码。
public Builder() { ... eventListenerFactory = EventListener.factory(EventListener.NONE); ... }
EventListener
EventListener.NONE??什么鬼,传入一个空的类干什么。点开EventListener
Listener for metrics events. Extend this class to monitor the quantity, size, and duration of your application's HTTP calls.
看一下官方对其的描述,一个事件的监听器,扩展这个类以监视应用程序的HTTP调用的数量、大小和持续时间。
瞬间释然了,原来就是一个没有定义的空类,我们可以根据具体的场合对事件进行监听,通过继承这个类实现其中的方法。
好了现在client也初始化了,realcall也拿到了,requst也封装了,那接下来干嘛,进行同步请求呀
response = client.newCall(request).execute();
execute()方法,实际也就是RealCall中的execute()方法,上面已经对其进行了描述。
那就愉快的来到了execute()方法中。
@Override public Response execute() throws IOException { synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } captureCallStackTrace(); eventListener.callStart(this); try { client.dispatcher().executed(this); Response result = getResponseWithInterceptorChain(); if (result == null) throw new IOException("Canceled"); return result; } catch (IOException e) { eventListener.callFailed(this, e); throw e; } finally { client.dispatcher().finished(this); } }
execute()
同样的,一步一步的分析。synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; }
executed是一个boolean变量,当进行executed请求后,会将其置为true,所以一个RealCall只能够发起一次executed()请求。
captureCallStackTrace();
看到这个函数先从语义对其进行分析,捕获call的异常栈。private void captureCallStackTrace() { Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()"); retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace); }
retryAndFollowUpInterceptor是一个负责定位失败和重定向的Interceptor,这里通过Platform平台得到”response.body().close()”的异常栈,关于Interceptor下面会进行介绍。
eventListener.callStart(this);
eventListener?感觉好像似曾相识,对的就是我们上面的那个空的类,通过继承这个类可以实现请求事件的监听,这里因为默认的是none,所以并不会有什么效果。client.dispatcher().executed(this);
client,果然什么都离不开你,clirent.dispatcher(),这里又到了 dispatcher类的介绍。dispatcher会在okHttpCilent中的builder初始化,也就是一个OkhttpClient会持有一个dispatcher,dispacher通过表面意思就是分发者的意思。这里通过分发者执行同步executed()方法。
Dispatcher
Policy on when async requests are executed.
官方对其的描述是执行异步管理的策略,也就是一个异步请求的执行类。
其中有如下变量。
/** Ready async calls in the order they'll be run. */ private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>(); //异步请求就绪的队列 /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */ private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>(); //异步请求正在执行的队列 /** Running synchronous calls. Includes canceled calls that haven't finished yet. */ private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>(); //同步请求的队列
executed()方法
接着上面看一下他的executed方法。
synchronized void executed(RealCall call) { runningSyncCalls.add(call); //将call加入同步请求队列 }
try { client.dispatcher().executed(this); //刚刚讨论的方法。 Response result = getResponseWithInterceptorChain(); if (result == null) throw new IOException("Canceled"); //如果经过一圈的获取还是空的,报错 return result; //请求已经完成 } catch (IOException e) { eventListener.callFailed(this, e); //捕获异常,请求失败 throw e; } finally { client.dispatcher().finished(this); }
既然执行到了executed()方法,那么接下来就是得到Response 的方法,getResponseWithInterceptorChain();
Response getResponseWithInterceptorChain() throws IOException { //获得各种的拦截器 // Build a full stack of interceptors. List<Interceptor> 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, this, eventListener, client.connectTimeoutMillis(), client.readTimeoutMillis(), client.writeTimeoutMillis()); return chain.proceed(originalRequest); }
上面的方法其实就是通过各种的拦截器,通过传入的originalRequest,依次迭代进行处理,这里用到了责任链的处理模式,同时也将整个代码解耦,类似RecycleView的处理,每个模块仅仅关注于自己的部分。
在配置 OkHttpClient 时设置的 interceptors,也就是自定义的interceptors。
负责失败重试以及重定向的 RetryAndFollowUpInterceptor。
负责把用户构造的请求转换为发送到服务器的请求、把服务器返回的响应转换为用户友好的响应的BridgeInterceptor。
负责读取缓存直接返回、更新缓存的 CacheInterceptor。
负责和服务器建立连接的 ConnectInterceptor。
配置 OkHttpClient 时设置的 networkInterceptors。
负责向服务器发送请求数据、从服务器读取响应数据的 CallServerInterceptor。
最后会发现调用了chain.proceed(originalRequest);每一个拦截器的proceed()方法中都会不断的调用这个方法,从而达到遍历所有的拦截器的作用
最后finaly中会有如下的方法
client.dispatcher().finished(this); 这个是整个请求的收尾阶段,代码如下
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) { int runningCallsCount; Runnable idleCallback; synchronized (this) { if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!"); if (promoteCalls) promoteCalls(); runningCallsCount = runningCallsCount(); idleCallback = this.idleCallback; } if (runningCallsCount == 0 && idleCallback != null) { idleCallback.run(); } }
可以发现这是一个泛型函数,通过传入的calls的deque,因为已经完成了这个操作,所以直接将call移除掉,
这里又出现了一个新的接口Runnable idleCallback;
这又是什么东西,来到类里面看一下。
public synchronized void setIdleCallback(@Nullable Runnable idleCallback) { this.idleCallback = idleCallback; }
仅仅有一个函数用于传入这个接口,idleCallback同样的是一个提供的空接口,用于在当前没有任务执行的时候调用的方法。上面的runningCallsCount = runningCallsCount();用来判断是否还有任务在进行,当当前同步任务执行完了的时候,会调用这个接口中的函数,用来进行一些收尾的处理。
同步请求大致就这样,接下来看一下异步请求
异步请求
OkHttpClient client=new OkHttpClient(); //Request request= new Request.Builder().build(); Request request = new Request.Builder() .url("https://api.github.com/repos/square/okhttp/issues") .header("User-Agent", "OkHttp Headers.java") .addHeader("Accept", "application/json; q=0.5") .addHeader("Accept", "application/vnd.github.v3+json") .build(); client.newCall(request).enqueue(new Callback() { //进行异步请求 @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { } });
同样的进行一个异步请求,由于不能直接返回结果,所以需要对其传入一个call接口,用于接受是否完成或者失败。
同样的,我们直接来到RealCall中的enqueue方法中。
@Override public void enqueue(Callback responseCallback) {
synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; }
captureCallStackTrace();
eventListener.callStart(this); //回调接口的调用,请求事件开始了
client.dispatcher().enqueue(new AsyncCall(responseCallback)); //直接入队
同样的还是通过client的dispatcher进行请求的分发。
来到dispatcher的enqueue方法。
synchronized void enqueue(AsyncCall call) { if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) { runningAsyncCalls.add(call); executorService().execute(call); } else { readyAsyncCalls.add(call); } }
dispatcher中维护了一个executorService线程池,上面也说到了,同时有异步请求的runningAsyncCalls()和readyAsyncCalls(),首先需要对线程池中的数量进行判断,如果当前的正在运行的线程比最大的请求数小,同时每个主机最大请求数大于这个时候主机请求的数目 说明当前主机还可以进行请求,直接将call加入正在进行的队列中,通过executorService().execute(call)执行call中的方法。 如果目前没有空闲的位置,所以必须等待,所以将其加入readyAsyncCalls中,等待下一次的调用。
相关文章推荐
- Okhttp3源码(1)---同步异步请求流程解析
- OKHttp网络框架源码解析(一)okHttp框架同步异步请求流程和源码分析
- okhttp源码分析之同步、异步请求
- OkHttp源码解读总结(二)--->OkHttp同步/异步请求
- OkHttp源码解读总结(三)--->OkHttp同步请求源码解析
- [置顶] 【Android okhttp源码解析 二】同步请求流程和源码分析
- [置顶] 【Android okhttp源码解析 三】异步请求流程和源码分析
- OkHttp 的基本数据请求 步骤 模板 (同时包裹异步请求和同步请求)
- OkHttp3源码解析01-请求
- 同步异步网络请求封装以及数据JSON解析
- 全面解析iOS中同步请求、异步请求、GET请求、POST请求
- Android网络编程(四)源码解析OkHttp前篇[请求网络]
- ajax同步异步请求与JSON数据解析
- OkHttp同步异步请求
- OkHttp框架的RetryAndFollowUpInterceptor请求重定向源码解析
- OkHttp学习(1)-->>同步和异步(get、post键值对、post带map、请求头体封装json)
- Android网络编程(七)源码解析OkHttp前篇[请求网络]
- OKHttp异步get,post请求和同步请求
- okhttp 一 概述及同步和异步请求的实现
- OkHttp的同步和异步请求的实现