OkHttp使用的很多,我们先来分析一下OkHttp的简单使用以及涉及到的几个基本类。
使用
OkHttp的使用非常简单
- 创建一个OkHttpClient 对像
- 创建一个Request对象
- 用 OkHttpClient对象 和 Request 对象创建一个 Call 对象
- 调用同步请求方法 execute() 或者 异步请求方法 enqueue() 来获取 Reponse
java
public class OkHttpRequest {
private final OkHttpClient client = new OkHttpClient();
public void request() {
Request request = new Request.Builder().url("https://www.baidu.com/").build();
Call call = client.newCall(request);
try {
// 同步请求
Response response = call.execute();
} catch (IOException e) {
throw new RuntimeException(e);
}
// 异步请求
call.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
}
});
}
}
基本类介绍
OkHttpClient
这个类主要是请求的各种配置,采用建造者模式,方便配置一些请求参数
kotlin
open class OkHttpClient internal constructor(
builder: Builder
) : Cloneable, Call.Factory, WebSocket.Factory {
constructor() : this(Builder())
class Builder constructor() {
//调度器
internal var dispatcher: Dispatcher = Dispatcher()
//连接池
internal var connectionPool: ConnectionPool = ConnectionPool()
//整体流程拦截器
internal val interceptors: MutableList<Interceptor> = mutableListOf()
//网络流程拦截器
internal val networkInterceptors: MutableList<Interceptor> = mutableListOf()
//流程监听器
internal var eventListenerFactory: EventListener.Factory = EventListener.NONE.asFactory()
//连接失败时是否重连
internal var retryOnConnectionFailure = true
//服务器认证设置
internal var authenticator: Authenticator = Authenticator.NONE
//是否重定向
internal var followRedirects = true
//是否从HTTP重定向到HTTPS
internal var followSslRedirects = true
//cookie设置
internal var cookieJar: CookieJar = CookieJar.NO_COOKIES
//缓存设置
internal var cache: Cache? = null
//DNS设置
internal var dns: Dns = Dns.SYSTEM
//代理设置
internal var proxy: Proxy? = null
//代理选择器设置
internal var proxySelector: ProxySelector? = null
//代理服务器认证设置
internal var proxyAuthenticator: Authenticator = Authenticator.NONE
//socket配置
internal var socketFactory: SocketFactory = SocketFactory.getDefault()
//https socket配置
internal var sslSocketFactoryOrNull: SSLSocketFactory? = null
internal var x509TrustManagerOrNull: X509TrustManager? = null
internal var connectionSpecs: List<ConnectionSpec> = DEFAULT_CONNECTION_SPECS
//协议
internal var protocols: List<Protocol> = DEFAULT_PROTOCOLS
//域名校验
internal var hostnameVerifier: HostnameVerifier = OkHostnameVerifier
internal var certificatePinner: CertificatePinner = CertificatePinner.DEFAULT
internal var certificateChainCleaner: CertificateChainCleaner? = null
//请求超时
internal var callTimeout = 0
//连接超时
internal var connectTimeout = 10_000
//读取超时
internal var readTimeout = 10_000
//写入超时
internal var writeTimeout = 10_000
internal var pingInterval = 0
internal var minWebSocketMessageToCompress = RealWebSocket.DEFAULT_MINIMUM_DEFLATE_SIZE
internal var routeDatabase: RouteDatabase? = null
···省略代码···
}
}
Request
也是请求参数配置类,采用了建造者模式,主要是 请求URL、请求方法、请求头、请求体
kotlin
class Request internal constructor(
@get:JvmName("url") val url: HttpUrl,
@get:JvmName("method") val method: String,
@get:JvmName("headers") val headers: Headers,
@get:JvmName("body") val body: RequestBody?,
internal val tags: Map<Class<*>, Any>
) {
open class Builder {
//请求的URL
internal var url: HttpUrl? = null
//请求方法,如:GET、POST..
internal var method: String
//请求头
internal var headers: Headers.Builder
//请求体
internal var body: RequestBody? = null
···省略代码···
}
}
Call
请求调用接口,可以执行请求,也可以取消,只能执行一次
kotlin
interface Call : Cloneable {
// 返回发起此调用的原始请求
fun request(): Request
// 同步请求,立即执行
// 抛出两种异常
// 1.请求失败抛出 IOException
// 2.如果在执行过一回的前提下再次执行抛出 IllegalStateException
@Throws(IOException::class)
fun execute(): Response
// 异步请求,将请求安排在将来的某个时间点执行
// 如果在执行过一回的前提下再次执行抛出 IllegalStateException
fun enqueue(responseCallback: Callback)
// 取消请求。已经完成的请求不能被取消
fun cancel()
// 是否已经被执行
fun isExecuted(): Boolean
// 是否被取消
fun isCanceled(): Boolean
// 一个完整Call请求流程的超时时间配置
fun timeout(): Timeout
// 克隆这个Call,创建一个新的相同的Call
public override fun clone(): Call
// 利用工厂模式来让 OkHttpClient 来创建 Call对象
// 这个方法是在OkHttpClient中实现的
fun interface Factory {
fun newCall(request: Request): Call
}
}
RealCall
从Call接口中我们可以知道,OkHttpClient 对象 通过 newCall 方法来创建一个Call 对象。 OkHttpClient.kt
java
override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)
从代码可以看到,newCall 方法返回的是一个 RealCall 对象。 RealCall 是 Call 接口的实现。创建RealCall对象后,就要调用同步或异步请求方法,所以它里面还包含同步请求 execute() 与异步请求 enqueue()方法。
AsyncCall
realCall在执行异步请求的时候,是一个 AsyncCall 对象 被调度器中的线程池所执行
kotlin
override fun enqueue(responseCallback: Callback) {
check(executed.compareAndSet(false, true)) { "Already Executed" }
callStart()
client.dispatcher.enqueue(AsyncCall(responseCallback))
}
AsyncCall 本质上是个 Runnable
kotlin
internal inner class AsyncCall(
// 用户传入的响应回调的方法
private val responseCallback: Callback
) : Runnable {
// 同一个域名的请求次数,volatile + AtomicInteger 保证在多线程下及时可见性与原子性
@Volatile var callsPerHost = AtomicInteger(0)
private set
fun reuseCallsPerHostFrom(other: AsyncCall) {
this.callsPerHost = other.callsPerHost
}
val host: String
get() = originalRequest.url.host
val request: Request
get() = originalRequest
val call: RealCall
get() = this@RealCall
/**
* Attempt to enqueue this async call on [executorService]. This will attempt to clean up
* if the executor has been shut down by reporting the call as failed.
*/
fun executeOn(executorService: ExecutorService) {
client.dispatcher.assertThreadDoesntHoldLock()
var success = false
try {
// 调用线程池执行
executorService.execute(this)
success = true
} catch (e: RejectedExecutionException) {
val ioException = InterruptedIOException("executor rejected")
ioException.initCause(e)
noMoreExchanges(ioException)
// 请求失败,调用 Callback 的 onFailure 方法
responseCallback.onFailure(this@RealCall, ioException)
} finally {
if (!success) {
client.dispatcher.finished(this) // This call is no longer running!
}
}
}
override fun run() {
threadName("OkHttp ${redactedUrl()}") {
var signalledCallback = false
timeout.enter()
try {
val response = getResponseWithInterceptorChain()
signalledCallback = true
// 请求成功,获取到服务器返回的 response
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 取消请求
cancel()
if (!signalledCallback) {
val canceledException = IOException("canceled due to $t")
canceledException.addSuppressed(t)
responseCallback.onFailure(this@RealCall, canceledException)
}
throw t
} finally {
// 请求结束,调用调度器的 finished
client.dispatcher.finished(this)
}
}
}
}
Dispatcher
调度器,用来调度 Call 对象,包含线程池,异步请求队列和同步请求队列
kotlin
class Dispatcher constructor() {
// 默认的最大并发请求量
@get:Synchronized var maxRequests = 64
set(maxRequests) {
require(maxRequests >= 1) { "max < 1: $maxRequests" }
synchronized(this) {
field = maxRequests
}
promoteAndExecute()
}
// 单个host支持的最大并发量
@get:Synchronized var maxRequestsPerHost = 5
set(maxRequestsPerHost) {
require(maxRequestsPerHost >= 1) { "max < 1: $maxRequestsPerHost" }
synchronized(this) {
field = maxRequestsPerHost
}
promoteAndExecute()
}
@set:Synchronized
@get:Synchronized
var idleCallback: Runnable? = null
private var executorServiceOrNull: ExecutorService? = null
// 线程池,处理请求调用
@get:Synchronized
@get:JvmName("executorService") val executorService: ExecutorService
get() {
if (executorServiceOrNull == null) {
executorServiceOrNull = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS,
SynchronousQueue(), threadFactory("$okHttpName Dispatcher", false))
}
return executorServiceOrNull!!
}
// 已经准备好的异步请求队列
private val readyAsyncCalls = ArrayDeque<AsyncCall>()
// 正在运行的异步请求队列,包含取消但是还未 finish 的 AsyncCall
private val runningAsyncCalls = ArrayDeque<AsyncCall>()
// 正在运行的同步请求队列,包含取消但是还未 finish 的 RealCall
private val runningSyncCalls = ArrayDeque<RealCall>()
}
以上是OkHttp的简单使用 以及 使用过程中涉及到的部分类的介绍,后续我们从一个请求的整个流程来分析OkHttp的源码。