Android 网络框架之okhttp源码解析

768 阅读4分钟

okhttp使用

okhttp则分为Request请求与response响应。

request请求体:每一个HTTP请求中都应该包含一个URL,一个GET或POST方法以及Header或其他参数,当然还可以含特定内容类型的数据流。

response 响应码:响应则包含一个回复代码(200代表成功,404代表未找到),Header和定制可选的body。

封装的okhttp库与okhttp使用:

blog.csdn.net/xjz123456qq…

基本请求(GET POST)

GET

Request.Builder builder = new Request.Builder();
        Request request = builder.get().url(url).build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException error) {
               //响应失败
            }
 
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //响应成功
            }
        });

POST

RequestBody body = RequestBody.create(JSON, jsonObject.toString());
 client.newCall(
                new Request.Builder()
                        .url(url)
                        //      .headers()//添加头
                        .post(body)
                        .build()).enqueue(new Callback() {
 
            @Override
            public void onFailure(Call call, IOException e) {
               
                
            }
 
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                LogUtil.i("http response " + response);
                if (response.isSuccessful()) {
 
                 
                    }
                }else {
                   
                }
            }
        });

okhttp请求流程与源码解析

由上面请求可以看出同步与异步,都是通过newCall()去实现的,那么newCall()到底了实现了什么呢?

//返回了一个Call对象
override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)

同步请求 call.execute()

override fun execute(): Response {
  //先判断一下当前是否请求过
  check(executed.compareAndSet(false, true)) { "Already Executed" }

  timeout.enter()
  callStart()
  try {
    //分发器进行分发
    client.dispatcher.executed(this)
    return getResponseWithInterceptorChain()// 走拦截器
  } finally {
    client.dispatcher.finished(this)//完成后的回调
  }
}


/** Used by [Call.execute] to signal it is in-flight. */
@Synchronized internal fun executed(call: RealCall) {
  runningSyncCalls.add(call)//直接去正在运行的同步队列中取值
}

源码可以看到,同步拦截器,直接去正在执行的同步队列中取值。

异步请求

override fun enqueue(responseCallback: Callback) {
//先判断当前这个call是否已经执行,执行了抛异常
  check(executed.compareAndSet(false, true)) { "Already Executed" }

  callStart()
  client.dispatcher.enqueue(AsyncCall(responseCallback))//走异步的分发
}



internal fun enqueue(call: AsyncCall) {
  synchronized(this) {
    readyAsyncCalls.add(call)//先将任务放到等待队列中

    // Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
    // the same host.
    if (!call.call.forWebSocket) {
      val existingCall = findExistingCallWithHost(call.host)
      if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
    }
  }
  promoteAndExecute()
}


private fun promoteAndExecute(): Boolean {
  this.assertThreadDoesntHoldLock()

  val executableCalls = mutableListOf<AsyncCall>()
  val isRunning: Boolean
  synchronized(this) {

    val i = readyAsyncCalls.iterator()
    //迭代等待执行异步请求
    while (i.hasNext()) {
      val asyncCall = i.next()
      //正在执行异步请求的任务数 不能大于 64个
      if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
      //同一个host的请求数 不能大于5
      if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.

      i.remove()
      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
}

//异步处理任务的源码
override fun run() {
  threadName("OkHttp ${redactedUrl()}") {
    var signalledCallback = false
    timeout.enter()
    try {
      // 执行请求,走拦截器
      val response = getResponseWithInterceptorChain()
      signalledCallback = true
      responseCallback.onResponse(this@RealCall, response)
    } catch (e: IOException) {
      if (signalledCallback) {
        // Do not signal the callback twice!
        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")
        canceledException.addSuppressed(t)
        responseCallback.onFailure(this@RealCall, canceledException)
      }
      throw t
    } finally {
      client.dispatcher.finished(this)//完成之后的回调
    }
  }
}


/** Used by [Call.execute] to signal completion. */
internal fun finished(call: RealCall) {
  finished(runningSyncCalls, call)
}

private fun <T> finished(calls: Deque<T>, call: T) {
  val idleCallback: Runnable?
  synchronized(this) {
    if (!calls.remove(call)) throw AssertionError("Call wasn't in-flight!")
    idleCallback = this.idleCallback
  }

  val isRunning = promoteAndExecute()//完成这次任务请求后,去进行下一次请求

  if (!isRunning && idleCallback != null) {
    idleCallback.run()
  }
}



上面可以看出,RealCall中有三个队列

1、正在执行的同步队列

2、正在执行的异步队列

3、准备执行的异步队列,任务进行排队准备的队列

异步请求流程:

1、enqueue()后,先判断当前任务是否被执行,没有执行走分发器的分发

2、先把任务放到等待执行的异步队列readyAsyncCalls中

3、对等待队列进行一个迭代,判断正在执行的任务数是否大于64 ,相同的host是否大于5

4、正在执行的异步队列中任务数大于64,则不能执行,继续在等待队列等待,如果当前任务的host>5,则进行下一个任务的执行判断

5、将要执行的任务放到正在执行的任务中,并且放到一个临时对列里,调线程池执行

6、线程池执行后,走拦截器,完成后,走回调。

7、拦截器走责任链模式,五大拦截器执行,完成后,回调。

8、完成后,重新触发promoteAndExecute(),进行下一个任务请求

五大拦截器

1、RetryAndFolloeUpInterceptor:重试定向拦截器

判断用户是否取消了拦截器,获得结果后,将状态码去判断是否需要重定向,满足条件重启所有拦截器

2、BrisgeInterceptor:桥接拦截器

对传参后进行的网络处理:Header, Body处理,自动将HTTP协议,请求头,,GZIP压缩,等处理,保存cookie接口去处理

3、CacheInterceptor: 缓存拦截器

请求一个不会改变的资源,读取之前判断当前是否有缓存,有缓存就调缓存直接回调,没有,走连接拦截器

4、Connection:连接拦截器

缓存没有命中, 走连接拦截器,找到与服务器的连接,或者创建一个连接,获取对应的socket流,获取结果后不进行额外处理,直接走请求服务拦截器

5、CallServerInterceptor:请求服务拦截器

拿到连接器后,将数据包装在class发给服务端,得到响应,与服务器通信,向服务器发送数据,解析读取的响应数据,再一步一步返回回去

责任链模式

image.png

类似递归调用,由上往下执行,执行后,结果由下往上返回。

五大拦截器详解

后续实现