据说每个怀抱着非同一般梦想的年轻人,都曾经在追梦的路上被狠狠嘲笑过。
简介
Retrofit是一个Restful设计风格的Http网络请求框架,使用了大量设计模式,其本质是通过对Okhttp网络请求的二次封装,简化Okhttp的使用。学习本文不仅学会Retrofit的工作流程,更能掌握设计模式的使用场景。
总结如下:
- Retrofit 是一个 RESTful 的 HTTP 网络请求框架的封装。
- 网络请求的工作本质上是 OkHttp 完成,而Retrofit 仅负责 网络请求接口的封装
- App应用程序通过 Retrofit 请求网络,实际上是使用Retrofit 接口层封装请求参数、Header、Url 等信息,之后由 OkHttp 完成后续的请求操作。
使用步骤
- 定义网络请求接口
- 创建Retrofit实例对象
- 创建网络请求对象
- 执行网络请求
设计模式
- 建造者模式
Retrofit实例使用建造者模式通过Builder类完成创建的。建造者模式可以将Retrofit的构建与表示进行分离,使用者可以不必关心Retrofit内部的创建细节就能直接创建出Retrofit对象,简化了使用流程。
Retrofit构造函数中的每一个参数都可以通过内部的Builder对象进行设置。最终调用Builder中的build函数进行Retrofit对象的创建。
- 代理模式
fun <T>getFlowService(t:Class<T>):T{
return initService().create(t)
}
NetService.getFlowService(MainApi::class.java).getArticle().enqueue()
调用Retrofit的create方法创建请求对象进行网络数据请求时,通过代理模式创建MainApi接口的实例。通过接口实例调用接口中的getArticle()方法进行数据请求。
下面我们一起看看Retrofit是如何进行代理的。
public <T> T create(final Class<T> service) {
//验证接口
validateServiceInterface(service);
return (T) //创建代理对象
Proxy.newProxyInstance(
//获取接口的classLoader
service.getClassLoader(),
//代理的接口
new Class<?>[] {service},
//代理接口的实现
new InvocationHandler() {
//获取当前平台
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
//如果方法是来自Object的方法,则直接正常调用。
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//检查参数
args = args != null ? args : emptyArgs;
//检查是否是平台默认方法,否则解析方法参数,返回代理对象
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
Retrofit通过代理模式中的动态代理模式,动态生成网络请求接口的代理类,并将代理类的实例创建交给InvocationHandler类作为具体的实现,loadServiceMethod(method)解析方法参数,并最终返回一个动态代理对象。
- 单例模式
ServiceMethod<?> loadServiceMethod(Method method) {
//先从缓存中取
ServiceMethod<?> result = serviceMethodCache.get(method);
//如果缓存中有直接返回
if (result != null) return result;
//双重校验锁
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//解析注解参数
result = ServiceMethod.parseAnnotations(this, method);
//缓存结果
serviceMethodCache.put(method, result);
}
}
return result;
}
ServiceMethod的loadServiceMethod方法获取方法对象,不仅使用缓存机制而且采用单例设计模式确保一个ServiceMethod对象对应请求接口中的一个请求方法。
网络请求
- 异步请求
NetService.getFlowService(MainApi::class.java).getArticle().enqueue()
使用Retrofit进行异步请求时,调用Call.enqueue()方法,实际是调用OKhttp.enquque()方法,call是一个静态代理,作用是在Okhttp发送网络请求后进行线程的切换。
- 调用okhttp的call中的enqueue()方法
override fun enqueue(responseCallback: Callback) {
check(executed.compareAndSet(false, true)) { "Already Executed" }
callStart()
//真正的网络请求
client.dispatcher.enqueue(AsyncCall(responseCallback))
}
2 .调用分发器Dispatcher中的enqueue方法
internal fun enqueue(call: AsyncCall) {
synchronized(this) {
//将异步请求加入异步请求队列
readyAsyncCalls.add(call)
//判断是是否是 同一个主机的请求
if (!call.call.forWebSocket) {
val existingCall = findExistingCallWithHost(call.host)
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
}
}
//开始请求数据
promoteAndExecute()
}
- 调用分发器Dispatcher中的promoteAndExecute方法
private fun promoteAndExecute(): Boolean {
...
//定义可执行任务集合
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
}
4.执行线程池executorService的run方法
override fun run() {
try {
//真正的网络请求
val response = getResponseWithInterceptorChain()
signalledCallback = true
responseCallback.onResponse(this@RealCall, response)
} catch (e: IOException) {
} catch (t: Throwable) {
。。。。。。。。。。。。。
} finally {
client.dispatcher.finished(this)
}
}
}
}
5.调用getResponseWithInterceptorChain执行队列中的任务
internal fun getResponseWithInterceptorChain(): Response {
// 添加拦截器
val interceptors = mutableListOf<Interceptor>()
interceptors += client.interceptors
interceptors += RetryAndFollowUpInterceptor(client)
interceptors += BridgeInterceptor(client.cookieJar)
interceptors += CacheInterceptor(client.cache)
interceptors += ConnectInterceptor
if (!forWebSocket) {
interceptors += client.networkInterceptors
}
interceptors += CallServerInterceptor(forWebSocket)
//构建拦截器链条 --责任链模式
val chain = RealInterceptorChain(
call = this,
interceptors = interceptors,
index = 0,
exchange = null,
request = originalRequest,
connectTimeoutMillis = client.connectTimeoutMillis,
readTimeoutMillis = client.readTimeoutMillis,
writeTimeoutMillis = client.writeTimeoutMillis
)
try {
//网络请求
val response = chain.proceed(originalRequest)
return response
}
}
- 同步请求
1.通过Okhtt调用RealCall中的execute()方法
override fun execute(): Response {
check(executed.compareAndSet(false, true)) { "Already Executed" }
timeout.enter()
callStart()
try {
//执行分发器中的executed
client.dispatcher.executed(this)
return getResponseWithInterceptorChain()
} finally {
//最终执行完调用finish方法
client.dispatcher.finished(this)
}
}
- 将同步执行任务加入同步队列中
@Synchronized internal fun executed(call: RealCall) {
runningSyncCalls.add(call)
}
3.调用getResponseWithInterceptorChain执行队列中的任务
internal fun getResponseWithInterceptorChain(): Response {
// 添加拦截器
val interceptors = mutableListOf<Interceptor>()
interceptors += client.interceptors
interceptors += RetryAndFollowUpInterceptor(client)
interceptors += BridgeInterceptor(client.cookieJar)
interceptors += CacheInterceptor(client.cache)
interceptors += ConnectInterceptor
if (!forWebSocket) {
interceptors += client.networkInterceptors
}
interceptors += CallServerInterceptor(forWebSocket)
//构建拦截器链条 --责任链模式
val chain = RealInterceptorChain(
call = this,
interceptors = interceptors,
index = 0,
exchange = null,
request = originalRequest,
connectTimeoutMillis = client.connectTimeoutMillis,
readTimeoutMillis = client.readTimeoutMillis,
writeTimeoutMillis = client.writeTimeoutMillis
)
try {
//网络请求
val response = chain.proceed(originalRequest)
return response
}
}
总结
Retrofit 本质上是一个 RESTful 的HTTP 网络请求框架的封装,其中通过大量的设计模式 封装了 OkHttp ,使得简
洁易用。具体过程如下:
- Retrofit 将 Http请求抽象成 Java 接口
- 在接口里用 注解 描述和配置 网络请求参数
- 用动态代理 的方式,动态将网络请求接口的注解 解析
成HTTP 请求 - 最后执行HTTP 请求