源码解析之Retrofit代理网络请求过程解析

242 阅读5分钟

据说每个怀抱着非同一般梦想的年轻人,都曾经在追梦的路上被狠狠嘲笑过。

简介

  Retrofit是一个Restful设计风格的Http网络请求框架,使用了大量设计模式,其本质是通过对Okhttp网络请求的二次封装,简化Okhttp的使用。学习本文不仅学会Retrofit的工作流程,更能掌握设计模式的使用场景。

总结如下:

  • Retrofit 是一个 RESTful 的 HTTP 网络请求框架的封装。
  • 网络请求的工作本质上是 OkHttp 完成,而Retrofit 仅负责 网络请求接口的封装
  • App应用程序通过 Retrofit 请求网络,实际上是使用Retrofit 接口层封装请求参数、Header、Url 等信息,之后由 OkHttp 完成后续的请求操作。

使用步骤

  1. 定义网络请求接口

  1. 创建Retrofit实例对象

  1. 创建网络请求对象

  1. 执行网络请求

设计模式

  • 建造者模式

  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发送网络请求后进行线程的切换。

  1. 调用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()
  }
  1. 调用分发器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)
    }
  }
  1. 将同步执行任务加入同步队列中

    @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 ,使得简
洁易用。具体过程如下:

  1. Retrofit 将 Http请求抽象成 Java 接口
  2. 在接口里用 注解 描述和配置 网络请求参数
  3. 用动态代理 的方式,动态将网络请求接口的注解 解析
    成HTTP 请求
  4. 最后执行HTTP 请求