前言
网络请求库,目前比较常用的okhttp或retrofit三方请求库。
- okhttp使用起来比较方便:支持GZIP压缩,连接池复用底层TCP,请求自动重试重定向...
目前Google官网将源码中的HttpURLConnection底层实现改成了okhttp了,同时retrofit底层也是okhttp。
OkHttp版本4.0.1
基本使用流程
// 1、创建client
OkHttpClient client = new OkhttpClient().newBuilder()
.cookieJar(CookieJar.NO_COOKIES)
.callTimeOut(10*1000,TimeUnit.MILLISECONDS)
.build();
// 2创建request
Request request = new Request.Builder()
.url("http://192.168.x.x:8088/test");
// 3、构建call对象
Call call = client.newCall(request);
// 4.1 同步请求;response对象中保存返回的相应参数
Response response = Call.execute();
// 4.2 异步请求
call.enqueue(new Callback(){
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e){
// 请求失败
Log.i(TAG,"onFailure");
}
@Override
public void onResponse(@NonNull Call call,@NonNull Respone res){
// 请求成功
Log.i(TAG,"onResponse");
}
})
一次网络请求由OkHttpClient Request Call 三个对象完成。通过建造者模式,根据自己需求简洁配置可选参数。
同步请求和异步请求流程
override fun newCall(request :Request):Call = RealCall(this,request,forWebSocket=false)
RealCall实现了Call接口
interface Call:Cloneable{
// 同步请求方法
@Throws(IOException::class)
fun execute():Response
// 异步请求方法
fun enqueue(responseCallback:Callback)
// OkHttpClient实现的Factory接口,newCall方法
fun interface Factory{
fun newCall(request:Request):Call
}
}
通过newCall得到RealCall对象,通过RealCall中execute和enqueue进行网络请求。
// RealCall.kt
override fun execute():Response{
// 一个Call对象只能执行一次execute方法
// 用CAS思想进行比较,提高效率
check(executed.compareAndSet(false,true)){"Already Executed"}
timeout.enter()
// 监听器,开始进行网络请求了
callStart()
try{
// 通过分发器进行任务分发
// 将当前请求加入到一个同步队列中
client.dispatcher.executed(this)
// 获得相应的结果
return getResponseWithInterceptorChain()
}finally{
// 收尾工作
client.dispatcher.finish(this)
}
}
同步请求分发器:
// Dispatcher.kt
// 正在执行的同步请求队列
private val runningSyncCalls = ArrayDeque<RealCall>()
// 将当前请求加入到同步队列
@Synchronized internal fun executed(call:RealCall){
runningSyncCalls.add(call)
}
// finish方法
internal fun finished(call:RealCall){
finished(runningSyncCalls,call)
}
private fun <T>finished(calls:Deque<T>,call:T){
// 分发器空闲时回调
val idleCallBack:Runnable?
synchronized(this){
// 完成请求的call移除
if(!calls.remove(call)) throw AssertionError("Call wasn't in-flight!)
idleCallback = this.idleCallback
}
// 一般主要体现在异步请求中的用途
val isRunning = promoteAndExecute()
// 空闲回调
if(!isRunning && idleCallback!=null){
idleCallback.run()
}
}
分发器仅仅将当前请求加入到一个同步请求队列中,请求完成后进行移除。在同步请求中finished只有一个回调作用,重点在异步请求回调中。
异步请求流程
// RealCall.kt
override fun enqueue(responseCallback:Callback){
// 一个call对象只能执行一次execute方法
check(executed.compareAndSet(false,true)){"Already Executed"}
// 监听
callStart()
// 构建AsyncCall对象,交给dispatcher进行分发
client.dispatcher.enqueue(AsyncCall(responseCallback))
}
AsyncCall 是RealCall的内部类,实现了Runnable接口,在线程池执行run方法
// RealCall.kt
internal inner class AsyncCall(private val responseCallback:Callback):Runnable{
// callPersHost连接同一个host的连接数
@Volatile var callsPerHost = AtomicInteger(0)
priate set
fun reuseCallsPerHostFrom(other:AsyncCall){
// 连接数必须小于5
this.callsPerHost = other.callsPerHost
}
val host:String get()=originalRequest.url.host
val request:Request get()=originalRequest
val call:RealCall get()=this@RealCall
// 将asyncCall 添加到线程池中去执行的方法
fun executerOn(executorService:ExecutorService){
client.dispatcher.assertThreadDoesntHoldLock()
var success = false
try{
// 线程池去执行当前AsyncCall对象的run方法
executorService.execute(this)
success = true
}catch(e:RejectedExcutionException){
val ioException = InterruptedIOException("executor rejected")
ioException.initCause(e)
noMoreExcahges(ioException)
responseCallback.onFilure(this@RealCall,ioException)
}finally{
if(!success){
// 收尾;内部调用promoteAndExcute()
client.dispatcher.finished(this)
}
}
}
override fun run(){
threadName("OkHttp ${redactedUrl()}")
var signalledCallback = false
timeout.enter()
try{
// 获取请求的相应结果
val response= getResponseWithIntrceptorChain()
signalledCallback = true
// 请求成功回调
responseCallback.onResponse(this@RealCall,response)
}catch(e:IOException){
if(signalledCallback){
Platform.get().log("Callback failure for ${toLoggableString}",Platform.INFO,e)
}else{
responseCallback.onFailure(this@RealCall,e)
}
}catch(t:Throwable){
cancel()
if(!signalledCallback){
val canceledException = IOException("canceled due to $t")
caceledException.addSuppressed(t)
// 请求失败回调
responseCallback.onFailure(this@RealCall,canceledException)
}
throw t
}finally{
// 收尾
client.dispatcher.finish(this)
}
}
}
Dispatcher中
// 准备执行的异步请求队列
private val readyAsyncCalls = ArrayDeque<AsyncCall>()
// 正在执行的异步请求
private val runnningAsynCalls = ArrayDeque<AsyncCall>()
internal fun enqueue(call:AsyncCall){
synchronized(this){
// asyncCall加到准备执行的异步请求队列
readyAsyncCalls.add(call)
if(!call.call.forWebSocket){
// 连接同一个host的请求数
val existingCall = findExistingCallWithHost(call.host)
if(existingCall!=null)call.reuseCallsPerHostForm(existingCall)
}
}
// dispatcher进行分发call任务的方法
promoteAndExecute()
}
// dispatch进行任务分发的方法
private fun promoteAndExecute():Boolean{
this.assertThreadDoesntHoldLock()
// 需要开始执行的任务集合
val executableCalls = mutableListOf<AsyncCall>()
val isRunning:Boolean
synchronized(this){
val i = readSyncCalls.iterator()
// 迭代等待执行异步请求
while(i.hasNext()){
val asyncCall = i.next()
// 正在执行异步请求的总任务不能大于64个,否则直接退出这个循环,不再将请求加到异步请求队列中
if(runningAsyncCalls.size>=this.maxRequests) break;
// 同一个host的请求不能大于5,否则直接跳过此call对象的添加,去遍历下一个asyncCall对象
if(asyncCall.callsPerHost.get()>=this.maxRequestsPerHost)continue
i.remove()
// callsPerHost加一
asyncCall.callsPerHost.incrementAndGet()
// 加到开始执行的任务集合中
executableCalls.add(asyncCall)
// 加到正在执行的任务队列中
runningAsyncCalls.add(asyncCall)
}
isRunning = runningCallsCount()>0
}
for(i in 0 until executableCalls.size){
val asyncCall = executableCalls[i]
asyncCall.executeOn(executorService)
}
return isRunning
}
通过Dispatcher将AsyncCall对象哦通过挑选,加到线程池中
- 当前执行德总请求数要小于64个
- 连接同一个host请求,要保证数量小于5
五大拦截器
okhttp内置五大拦截器,通过责任链模式将请求逐层下发,最后往上返回结果。
- RetryAndFollowUpIntercepter:请求失败自动重试,如果DNS设置了多个ip地址会自动重试其余ip地址。
- BridgeIntercepter:补全请求中的请求头,Host Cookie Accept-Encoding等
- CacheIntercepter:选择性将响应结果进行保存,便下次直接读取,不再向服务器拿数据。
- ConnectIntercepter:建立连接并得到对应的socket;管理连接池,从中读取连接,达到连接复用的目的。
- CallServerInterceptor:与服务器建立连接,具体进行网络请求,将结果逐层返回的地方。
通过addInterceptor()加入拦截器。将所有拦截器包括用户自定义的蓝机器全部放到一个集合中,构建出RealIntercepterChain对象,调用proceed拦截器逐层分发工作。