Retrofit源码解析

本文分析的源码基于retrofit:2.9.0

前言

Retrofit基于OkHttp,网络请求的工作本质上是 OkHttp 完成,而 Retrofit 仅负责 网络请求接口的封装,它们的关系示意图如下:

image-20211223125633592

基本使用

首先添加依赖

    // Retrofit
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    // Retrofit的Gson转换器
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'

封装一个工具类

object ServiceCreator {
    private const val BASE_URL = "https://api.github.com"

    private val httpClient = OkHttpClient.Builder()

    private val builder = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .client(httpClient.build())
        .addConverterFactory(GsonConverterFactory.create())

    private val retrofit = builder.build()

    fun <T> create(serviceClass: Class<T>): T = retrofit.create(serviceClass)
}

写一个Retrofit的接口

interface IUser {
    @GET("/users/{nickname}")
    fun getUser(@Path("nickname") nickname: String): Call<User>
}

@GET中所填写的valueBaseUrl组成完整的路径,BaseUrl在构造Retrofit对象时已给出。

其中User类如下

data class User(var id: Long? = null, var name: String? = null)

网络请求代码如下

        val netRequestBn: Button = findViewById(R.id.net_request)
        netRequestBn.setOnClickListener {
            val iUser = ServiceCreator.create(IUser::class.java)
            iUser.getUser("giagor").enqueue(object : Callback<User> {
                override fun onResponse(call: Call<User>, response: Response<User>) {
                    val user = response.body()
                    Log.d(TAG, "$user")
                }

                override fun onFailure(call: Call<User>, t: Throwable) {
                    Log.d(TAG, "网络请求失败")
                }
            })
        }

进行网络请求后,我们可以看到下面的日志信息

D/MainActivity: User(id=57672520, name=Giagor)

上面展示了异步请求的方式。如果想要进行同步请求,则需要调用iUser.getUser("giagor").execute(),同步请求的情况下,要记得自己处理异常,比如使用try...catch包住上面的...execute()代码。

@Header注解的使用:

@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call<List<Widget>> widgetList();

@Headers({
    "Accept: application/vnd.github.v3.full+json",
    "User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call<User> getUser(@Path("username") String username)

Headers不会互相覆盖,也就是有相同名字的Headers会一并被包含到请求中。也可以给方法的参数使用@Header注解,达到动态设置的目的,如下

@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)

如果authorizationnull@Header("Authorization")注解会被忽略,并不会被提交,否则会调用authorizationtoString方法作为@Header("Authorization")的值。

对于复杂的Header组合,也可以使用Map

@GET("user")
Call<User> getUser(@HeaderMap Map<String, String> headers)

如果有的Header需要添加到每个请求上面,就使用OkHttp的拦截器添加。

更多使用参考:

  1. Retrofit (square.github.io)
  2. Retrofit2 完全解析 探索与okhttp之间的关系_Hongyang-CSDN博客

Retrofit对象创建

Retrofit采用Builder模式构建,其中 Retrofit的变量定义和构造方法如下:

public final class Retrofit {
  private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();

  // 网络请求的工厂,作用是产生网络的请求器(Call)  
  final okhttp3.Call.Factory callFactory;
  // 网络请求的BaseUrl  
  final HttpUrl baseUrl;
  // 数据转换器工厂的集合  
  final List<Converter.Factory> converterFactories;
  // 网络请求适配器工厂的集合  
  final List<CallAdapter.Factory> callAdapterFactories;
  // 回调方法执行器  
  final @Nullable Executor callbackExecutor;
  // 是否提前对业务接口中的注解进行验证转换的标志位  
  final boolean validateEagerly;

  Retrofit(
      okhttp3.Call.Factory callFactory,
      HttpUrl baseUrl,
      List<Converter.Factory> converterFactories,
      List<CallAdapter.Factory> callAdapterFactories,
      @Nullable Executor callbackExecutor,
      boolean validateEagerly) {
    this.callFactory = callFactory;
    this.baseUrl = baseUrl;
    this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
    this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
    this.callbackExecutor = callbackExecutor;
    this.validateEagerly = validateEagerly;
  }
  ...	
}

看下Retrofit.Builder

  public static final class Builder {
    ... 
        
    Builder(Platform platform) {
      this.platform = platform;
    }
      
    public Builder() {
      this(Platform.get());
    }
    ... 
        
    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories =
          new ArrayList<>(
              1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

      // Add the built-in converter factory first. This prevents overriding its behavior but also
      // ensures correct behavior when using converters that consume all types.
      converterFactories.add(new BuiltInConverters());
      converterFactories.addAll(this.converterFactories);
      converterFactories.addAll(platform.defaultConverterFactories());

      return new Retrofit(
          callFactory,
          baseUrl,
          unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories),
          callbackExecutor,
          validateEagerly);
    }        
  }

Builder构造方法:

  • 需要有一个Platform参数,表示当前的平台,这里当然是Android平台。

build方法:

  • baseUrl必须指定,否则抛异常。

  • 如果没有指定callFactory,则默认为OkHttpClient;如果需要对OkHttpClient进行详细的设置,就需要自己构建并传入OkHttpClient对象。

  • 如果没有指定callbackExecutor,就获取platformAndroid平台)的defaultCallbackExecutor,最终获取到的是一个MainThreadExecutor,它里面有一个主线程的Handler,调用MainThreadExecutorexecute就可以使用Handler向主线程post一个任务。

  • 接着会构建callAdapterFactories,其中的CallAdapter.Factory主要用于对retrofit.Call对象进行转化,其中的优先级顺序为:

    • 外界传入的callAdapterFactories
    • platform.defaultCallAdapterFactories(...)

    后面介绍CallAdapter的时候会再进行一些讲解

  • 接着构建converterFactories,其中的Converter.Factory主要用于转化数据,例如将返回的ResponseBody转化为对象等。其中的优先级顺序:

    • BuiltInConverters
    • 外界传入的converterFactories
    • platform.defaultConverterFactories()

    后面介绍Converter的时候会再进行一些讲解

接口实例的创建

我们在使用Retrofit进行网络请求的时候,需要先定义一个接口,然后调用retrofit.create(serviceClass)生成接口的一个实例,例如在「基本使用」的例子里,就是通过这种方式生成了一个IUser实例,那么这是如何做到的呢?答案是动态代理

动态代理的例子

我们先通过一个例子,简单地了解一下动态代理:

我们先定义一个注解

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class TIP(val value : String = "")

在定义一个接口

interface IMath {
    @TIP("加法运算")
    fun add(num1 : Int,num2 : Int) : Int    
}

动态代理的实现:

val proxyBn: Button = findViewById(R.id.proxy_test)
proxyBn.setOnClickListener {
    val iMath: IMath = Proxy.newProxyInstance(
        IMath::class.java.classLoader,
        arrayOf(IMath::class.java),
        object : InvocationHandler {
            override fun invoke(proxy: Any?, method: Method, args: Array<out Any>): Any {
                val num1: Int = args[0] as Int
                val num2: Int = args[1] as Int
                Log.d(TAG, "方法名字: ${method.name}")
                Log.d(TAG, "方法参数: num1为$num1,num2为$num2")

                val tip: TIP? = method.getAnnotation(TIP::class.java)
                tip?.let {
                    Log.d(TAG, "注解的值: ${it.value}")
                }
                return num1 + num2
            }
        }) as IMath

    Log.d(TAG, "调用结果: ${iMath.add(2, 3)}")
}

打印的输出信息为:

D/MainActivity: 方法名字: add
D/MainActivity: 方法参数: num1为2,num2为3
D/MainActivity: 注解的值: 加法运算
D/MainActivity: 调用结果: 5

我们调用实例iMath的方法,实际会调用到InvocationHandlerinvoke方法,在该方法可以拿到方法名字、参数、注解等,从而实现代理的功能。

Retrofit::create

Retrofit::create方法如下:

  public <T> T create(final Class<T> service) {
    // 对 Service 的接口进行检测
    validateServiceInterface(service);
    // 创建了网络请求接口的动态代理对象,即通过动态代理创建网络请求接口的实例并返回
    return (T)
        Proxy.newProxyInstance(
            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 {
                // If the method is a method from Object then defer to normal invocation.
                // 如果调用的方法是Object类中的,则正常调用Object类中的方法  
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                // 方法参数  
                args = args != null ? args : emptyArgs;
                // 如果method是java8接口的default方法,则直接执行。否则会通过loadServiceMethod  
                // 方法获取一个ServiceMethod对象,然后调用它的invoke方法。 
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }

该方法主要做了两件事情:

  1. 调用validateServiceInterface方法对 Service 的接口进行检测。
  2. 创建并返回一个代理对象。在InvocationHandlerinvoke方法里面,调用了loadServiceMethod方法获取一个ServiceMethod对象,一个ServiceMethod对象就代表网络请求接口里的一个方法,例如它可以代表我们IUser里的getUser请求方法,获取到ServiceMethod后,就调用它的invoke方法进行网络请求。

Retrofit::validateServiceInterface

  private void validateServiceInterface(Class<?> service) {
    // 若service不是接口,则抛出异常  
    if (!service.isInterface()) {
      throw new IllegalArgumentException("API declarations must be interfaces.");
    }

    // 判断service接口及其继承的所有接口是否包含了泛型参数,若包含则抛出异常
    // 例如这样的接口会抛出异常:interface IUser<T,E> {...}  
    Deque<Class<?>> check = new ArrayDeque<>(1);
    // 将service添加到双端队列中  
    check.add(service);
    while (!check.isEmpty()) {
      // 取出队列的第一个元素  
      Class<?> candidate = check.removeFirst();
       // 不合法则抛出异常 
      if (candidate.getTypeParameters().length != 0) {
        StringBuilder message =
            new StringBuilder("Type parameters are unsupported on ").append(candidate.getName());
        if (candidate != service) {
          message.append(" which is an interface of ").append(service.getName());
        }
        throw new IllegalArgumentException(message.toString());
      }
      // 将candidate继承的接口全添加到双端队列中  
      Collections.addAll(check, candidate.getInterfaces());
    }

    // 是否急切地对Service接口的方法进行处理,该值默认为false,可以在Retrofit.Builder中设置  
    if (validateEagerly) {
      Platform platform = Platform.get();
      for (Method method : service.getDeclaredMethods()) {
        // method不是default方法,并且不是static修饰的,则使用loadServiceMethod加载该方法  
        if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
          loadServiceMethod(method);
        }
      }
    }
  }

该方法会对service进行检测,主要做了下面几件事情:

  1. 若service不是接口,则抛出异常
  2. 判断service接口及其继承的所有接口是否包含了泛型参数,若包含则抛出异常
  3. 若validateEagerly为true,则提前对service声明的所有方法提前进行检测,也就是对service每个声明的方法都调用loadServiceMethod方法进行加载,loadServiceMethod会加载出ServiceMethod并进行缓存(缓存的目的是为了复用),调用loadServiceMethod加载方法的时候,因为使用了反射所以会有一定的性能损耗一般情况下是业务层调用到接口的某个方法(第一次调用该方法),才会使用loadServiceMethod进行相应的ServiceMethod的加载,这样的加载在时间上相对分散,因此此时的性能损耗不会很明显。而validateEagerly为true时对ServiceMethod的集中加载,性能损耗会比较明显,但是这样就可以尽早地检测开发者写的接口方法是否有问题,写的有问题会报错,这样可以尽早发现存在的问题,因此「validateEagerly为true」更多的是用在测试的时候

代理对象的执行

获取ServiceMethod

我们查看Retrofit::loadServiceMethod

  ServiceMethod<?> loadServiceMethod(Method method) {
    // 判断是否有method对应的ServiceMethod对象,有则直接返回  
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    // 利用serviceMethodCache加锁同步  
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      // 创建一个ServiceMethod对象并将其加入缓存中  
      if (result == null) {
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    // 返回ServiceMethod对象  
    return result;
  }

serviceMethodCache是一个ConcurrentHashMap实例,ConcurrentHashMap是线程安全的HashMap。这里先从serviceMethodCache查看method是否有对应的ServiceMethod,有则直接返回,没有则调用ServiceMethod.parseAnnotations方法对method的注解进行处理,并将得到的ServiceMethod对象加入到ServiceMethodCache里面。

我们从中看出了Retrofit的缓存思想:serviceMethodCache是一个缓存,我们在调用Retrofit::create方法的时候传入的是一个class对象,而class对象在进程内是单例的,所以获取到它的同一个Method也是单例的,这里将Method作为ConcurrentHashMapKey,从而实现了对ServiceMethod的缓存与复用

ServiceMethod的构建

我们查看ServiceMethod类的定义:

abstract class ServiceMethod<T> {
  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) {
      throw methodError(
          method,
          "Method return type must not include a type variable or wildcard: %s",
          returnType);
    }
    if (returnType == void.class) {
      throw methodError(method, "Service methods cannot return void.");
    }

    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

  abstract @Nullable T invoke(Object[] args);
}

ServiceMethodparseAnnotations方法就为我们构建了一个ServiceMethod,主要分为下面两步:

  1. 调用RequestFactory.parseAnnotations方法创建RequestFactory,这里主要是获取注解信息并且解析注解
  2. 调用HttpServiceMethod.parseAnnotations方法(传入前面获取的requestFactory),继续进行注解的解析,最终获取并返回一个HttpServiceMethod对象。

创建RequestFactory

获取注解信息

RequestFactory::parseAnnotations是一个静态方法

  static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    return new Builder(retrofit, method).build();
  }

这是一个建造者模式。它将method传入RequestFactory.Builder,再调用Builderbuild方法创建了一个RequestFactory对象。

查看RequestFactory::Builder的构造方法:

    Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      // 方法注解  
      this.methodAnnotations = method.getAnnotations();
      // 方法参数类型(带泛型)  
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

Builder中通过反射获取了方法的注解、方法参数类型(带泛型)、方法参数的注解。

小插曲:一些实验

Method::getParameterTypesMethod::getGenericParameterTypes有什么区别?这里我做了个实验,对于下面的这个类

public class Test {
    public Long test(List<String> strs, List<Integer> nums,float num) {
        return 0L;
    }
	...
}

如果我们使用getParameterTypes方法:

Test test = new Test();
Class<?> testClass = test.getClass();
Method testMethod = testClass.getMethod("test", List.class, List.class, float.class);
System.out.println(testMethod.getName());
System.out.println(Arrays.toString(testMethod.getParameterTypes()));

输出如下:

test
[interface java.util.List, interface java.util.List, float]

如果我们使用getGenericParameterTypes方法:

Test test = new Test();
Class<?> testClass = test.getClass();
Method testMethod = testClass.getMethod("test", List.class, List.class,float.class);
System.out.println(testMethod.getName());
System.out.println(Arrays.toString(testMethod.getGenericParameterTypes()));

输出如下:

test
[java.util.List<java.lang.String>, java.util.List<java.lang.Integer>, float]

可以看出它们的区别是getGenericParameterTypes获取方法参数类型的时候会带上泛型,而getParameterTypes不会带上泛型。

另外,Method::getParameterAnnotations也有需要注意的点,我们先定义两个注解

@Retention(RetentionPolicy.RUNTIME)
public @interface Anno1 {
}

@Retention(RetentionPolicy.RUNTIME)
public @interface Anno2 {
}

然后将Test::test的方法参数使用注解修饰

public class Test {
    public Long test(@Anno1 @Anno2 List<String> strs, @Anno2 List<Integer> nums, 
                     float num) {
        return 0L;
    }
}

通过getParameterAnnotations方法去获取test方法参数的注解

Test test = new Test();
Class<?> testClass = test.getClass();
Method testMethod = testClass.getMethod("test", List.class, List.class, float.class);
System.out.println(testMethod.getName());
Annotation[][] paramAnnotations = testMethod.getParameterAnnotations();
for (Annotation[] paramAnnotation : paramAnnotations) {
    for (Annotation annotation : paramAnnotation) {
        System.out.print(annotation.toString() + " ");
    }
    System.out.println();
}    

输出信息:

test
@Anno1() @Anno2() 
@Anno2() 

注意,这里之所以可以获取到Anno1Anno2,是因为这两个注解的存活期到RetentionPolicy.RUNTIME,如果Anno1Anno2的存活期到RetentionPolicy.CLASSRetentionPolicy.SOURCE,那么在这里将获取不到Anno1Anno2注解,因为反射是在运行期执行的。

另外,paramAnnotations是二维数组,方法有多少个参数,二维数组的大小就是多少,其中的每个一维数组分别对应着每个参数上的注解

注解解析

再查看RequestFactory.Builderbuild方法

    RequestFactory build() {
      // 遍历方法的注解,对每个注解进行解析  
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }

      ...// 一些异常处理  

      // 方法参数的个数  
      int parameterCount = parameterAnnotationsArray.length;
      // 每个参数都创建一个ParameterHandler 
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
        parameterHandlers[p] =
            parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
      }

      ...// 一些异常处理  
	    
      return new RequestFactory(this);
    }

build方法做了三件事情:

  1. 方法的每个注解调用parseMethodAnnotation方法进行解析
  2. 方法的每个参数调用了parseParameter解析,生成ParameterHandler对象
  3. 根据Builder创建并返回RequestFactory对象
方法注解的解析

RequestFactory.Builder::parseMethodAnnotation方法:

    private void parseMethodAnnotation(Annotation annotation) {
      if (annotation instanceof DELETE) {
        parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
      } else if (annotation instanceof GET) {
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
      } else if (annotation instanceof HEAD) {
        parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
      } else if (annotation instanceof PATCH) {
        parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
      } else if (annotation instanceof POST) {
        parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
      } else if (annotation instanceof PUT) {
        parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
      } else if (annotation instanceof OPTIONS) {
        parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
      } else if (annotation instanceof HTTP) {
        HTTP http = (HTTP) annotation;
        parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
      } else if (annotation instanceof retrofit2.http.Headers) {
        String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
        if (headersToParse.length == 0) {
          throw methodError(method, "@Headers annotation is empty.");
        }
        headers = parseHeaders(headersToParse);
      } else if (annotation instanceof Multipart) {
        if (isFormEncoded) {
          throw methodError(method, "Only one encoding annotation is allowed.");
        }
        isMultipart = true;
      } else if (annotation instanceof FormUrlEncoded) {
        if (isMultipart) {
          throw methodError(method, "Only one encoding annotation is allowed.");
        }
        isFormEncoded = true;
      }
    }

这里对方法注解的处理方式主要可以分为三类:

  1. GETPOST等请求方法:调用RequestFactory.Builder::parseHttpMethodAndPath方法进行处理
  2. Headers的注解:调用RequestFactory.Builder::parseHeaders方法进行处理
  3. MultipartFormUrlEncoded注解:主要是在标记变量中进行记录

我们看下第12步是如何处理的。

GETPOST等请求方法的注解解析,使用RequestFactory.Builder::parseHttpMethodAndPath

private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
    // 1.若已设置过httpMethod,则抛出异常
    if (this.httpMethod != null) {
        throw methodError(
            method,
            "Only one HTTP method is allowed. Found: %s and %s.",
            this.httpMethod,
            httpMethod);
    }
    // 记录 请求方法 及 是否有请求体
    this.httpMethod = httpMethod;
    this.hasBody = hasBody;

    // 若请求方法的注解(如GET)里面没有写值,则结束
    if (value.isEmpty()) {
        return;
    }

    // Get the relative URL path and existing query string, if present.
    // 2.判断请求方法的注解中的值是否合理,不合理则抛出异常
    int question = value.indexOf('?');
    if (question != -1 && question < value.length() - 1) {
        // Ensure the query string does not have any named parameters.
        String queryParams = value.substring(question + 1);
        // 使用正则表达式匹配
        Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
        if (queryParamMatcher.find()) {
            throw methodError(
                method,
                "URL query string \"%s\" must not have replace block. "
                + "For dynamic query parameters use @Query.",
                queryParams);
        }
    }

    // 3.记录相对Url;解析并记录注解中的占位符(parsePathParameters方法内部使用了正则表达式)
    this.relativeUrl = value;
    this.relativeUrlParamNames = parsePathParameters(value);
}

该方法主要做了下面的几件事情:

  1. 记录 请求方法 及 是否有请求体
  2. 判断请求方法的注解中的值是否合理,不合理则抛出异常
  3. 记录相对Url,解析并记录注解中的占位符

我们以GET请求方法注解为例,第2步主要是防止GET的出现类似"users?sortby={sortby}"这种值,它希望我们动态设置的参数使用@Query注解来实现,举一个例子:

    @GET("/banner")
    fun getBanners(@Query("type") type: Int): Call<BannerJson>

而不是

    @GET("/banner?type={type}")
    fun getBanners(@Path("type") type: Int): Call<BannerJson>

3步,例如我们的请求方法为

interface IUser {
    @GET("/users/{nickname}")
    fun getUser(@Path("nickname") nickname: String): Call<User>
}

那么计算后的值为

// 相对url
this.relativeUrl = "/users/{nickname}" 
// 也就是{}包裹的值,如果有多个{},那么Set<String>会有多个值
this.relativeUrlParamNames = 包含"nickname"的Set<String> 

Headers注解的解析,使用RequestFactory.Builder::parseHeaders方法:

    private Headers parseHeaders(String[] headers) {
      // 这是okhttp3的Headers.Builder  
      Headers.Builder builder = new Headers.Builder();
      // 遍历传入的headers
      for (String header : headers) {
        int colon = header.indexOf(':');
        if (colon == -1 || colon == 0 || colon == header.length() - 1) {
          throw methodError(
              method, "@Headers value must be in the form \"Name: Value\". Found: \"%s\"", header);
        }
        // 获取Header名和Header值  
        String headerName = header.substring(0, colon);
        String headerValue = header.substring(colon + 1).trim();
        // 如果Header是"Content-Type",则会进行一些特殊处理
        if ("Content-Type".equalsIgnoreCase(headerName)) {
          try {
            contentType = MediaType.get(headerValue);
          } catch (IllegalArgumentException e) {
            throw methodError(method, e, "Malformed content type: %s", headerValue);
          }
        } else {
          // 将Header添加到builder中  
          builder.add(headerName, headerValue);
        }
      }
      // 返回okhttp3.Headers  
      return builder.build();
    }

该方法主要做的事情:将传入的字符串数组headers,构造为okhttp3.Headers并返回,对于Content-Type类型的Header,会进行一些特殊的处理。

对方法参数的处理

RequestFactory.Builder::parseParameter

    # p:方法参数的位置
    # parameterType:方法参数的类型(带泛型)
    # annotations:方法参数的注解
    # allowContinuation:是否允许为Continuation(通过是否为最后一个参数进行判断)    
	private @Nullable ParameterHandler<?> parseParameter(
        int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
      ParameterHandler<?> result = null;
      if (annotations != null) {
        // 对该参数的每个注解进行解析  
        for (Annotation annotation : annotations) {
          // 使用parseParameterAnnotation进行注解的解析  
          ParameterHandler<?> annotationAction =
              parseParameterAnnotation(p, parameterType, annotations, annotation);

          if (annotationAction == null) {
            continue;
          }

          // 一个方法参数最多只能有一个Retrofit注解,多了则抛异常  
          if (result != null) {
            throw parameterError(
                method, p, "Multiple Retrofit annotations found, only one allowed.");
          }
		  // 记录结果
          result = annotationAction;
        }
      }

      if (result == null) {
        // 对kotlin协程方面的特殊处理  
        if (allowContinuation) {
          try {
            if (Utils.getRawType(parameterType) == Continuation.class) {
              isKotlinSuspendFunction = true;
              return null;
            }
          } catch (NoClassDefFoundError ignored) {
          }
        }
        throw parameterError(method, p, "No Retrofit annotation found.");
      }

      return result;
    }

该方法主要做的事情:

  1. 使用parseParameterAnnotation解析方法参数的注解,且一个方法参数最多只能有一个Retrofit注解。最终返回result
  2. 若参数是方法的最后一个参数且为Continuation类型,说明与kotlin协程有关,做特殊处理。最终返回null

parseParameterAnnotation方法会对参数每种类型的注解进行特有的处理,然后返回相应的ParameterHandler

ServiceMethod 的创建

ServiceMethod 的创建使用HttpServiceMethod.parseAnnotations方法:

  // 检查接口方法的注释,以构造一个使用HTTP的可重用的ServiceMethod。这可能需要代价高昂的反射,所以
  // 对于要使用到的ServiceMethod最好只构建一次然后重用它
  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    // 记录是否为suspend函数  
    boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
    boolean continuationWantsResponse = false;
    boolean continuationBodyNullable = false;
	// 获取方法注解
    Annotation[] annotations = method.getAnnotations();
    Type adapterType;
    if (isKotlinSuspendFunction) {
      Type[] parameterTypes = method.getGenericParameterTypes();
      Type responseType =
          Utils.getParameterLowerBound(
              0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
      if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
        // Unwrap the actual body type from Response<T>.
        responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
        continuationWantsResponse = true;
      } else {
        // TODO figure out if type is nullable or not
        // Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
        // Find the entry for method
        // Determine if return type is nullable or not
      }

      adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
      annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
    } else {
      // 记录方法的返回类型(含泛型信息),如Call<User>  
      adapterType = method.getGenericReturnType();
    }

    // 创建CallAdapter对象  
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
     // 接口方法的实际返回类型,例如Call<User>会返回User   
    Type responseType = callAdapter.responseType();
   
    ...(一些异常处理)
	// 创建Converter对象
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {
      // 不是suspend函数,就创建并返回一个CallAdapted对象 
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>)
          new SuspendForResponse<>(
              requestFactory,
              callFactory,
              responseConverter,
              (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
    } else {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>)
          new SuspendForBody<>(
              requestFactory,
              callFactory,
              responseConverter,
              (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
              continuationBodyNullable);
    }
  }

这里暂时先不考虑Retrofit对协程的支持。这个方法主要做了下面几件事:

  1. 记录方法的返回类型(含泛型信息),如Call<User>
  2. 创建CallAdapter对象
  3. 创建Converter对象
  4. 创建并返回一个CallAdapted对象,CallAdapted继承至HttpServiceMethod

CallAdapter

CallAdapter用于将retrofit2.Call<R>对象适配为类型为T的对象,定义如下:

// CallAdapter实例由CallAdapter.Factory创建,Retrofit里面有CallAdapter.Factory的实例
public interface CallAdapter<R, T> {
  // 返回Response Type,如Call<User>的Response Type就是User  
  Type responseType();
  // 适配:Call<R> -> T  
  T adapt(Call<R> call);
    
  // 基于接口方法的返回类型,创建CallAdapter实例  
  abstract class Factory {
    // 如果该工厂可以处理指定的returnType和annotations的接口方法,则返回CallAdapter,否则返回null
    // returnType:接口方法的返回类型,如Call<User>  
    public abstract @Nullable CallAdapter<?, ?> get(
        Type returnType, Annotation[] annotations, Retrofit retrofit);      
      
    // 提取泛型参数的上界,例如index = 1,type = Map<String, ? extends Runnable>,则
    // 返回值为Runnable 
    protected static Type getParameterUpperBound(int index, ParameterizedType type) {
      return Utils.getParameterUpperBound(index, type);
    }
     
    // 返回Type的raw class type,例如type = List<? extends Runnable>,则返回List.class  
    protected static Class<?> getRawType(Type type) {
      return Utils.getRawType(type);
    }      
  }
}

查看HttpServiceMethod::createCallAdapter方法,看CallAdapter是如何被创建的:

  private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
      Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
    try {
      //noinspection unchecked
      return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
    } catch (RuntimeException e) { // Wide exception range because factories are user code.
      throw methodError(method, e, "Unable to create call adapter for %s", returnType);
    }
  }

Retrofit::callAdapter

  // 从可用的factories中返回returnType相应的CallAdapter
  public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }

Retrofit::nextCallAdapter

  # skipPast:null
  # returnType:接口方法的返回类型,如Call<User>
  # annotations:接口方法的注解    
  public CallAdapter<?, ?> nextCallAdapter(
      @Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
    Objects.requireNonNull(returnType, "returnType == null");
    Objects.requireNonNull(annotations, "annotations == null");
	
    // 从列表开始寻找的位置,这里是从0开始 
    int start = callAdapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
      // 若索引处的CallAdapter.Factory可以处理该接口方法,则返回CallAdapter,否则返回null  
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      // 可以获取到CallAdapter则返回它
      if (adapter != null) {
        return adapter;
      }
    }

    // 没有获取到适合该接口方法的CallAdapter,则拼接异常信息并抛出异常 
    StringBuilder builder = ...
    ...
    throw new IllegalArgumentException(builder.toString());
  }

该方法会遍历RetrofitcallAdapterFactories,查看是否有可以处理指定的returnTypeannotationsCallAdapter.Factory,有则返回该CallAdapter,整个列表都没有找到合适的CallAdapter.Factory,则抛出异常。

回到Retrofit.Builder::build方法,可以知道callAdapterFactories中有哪些元素

List<CallAdapter.Factory> callAdapterFactories = 
    					new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

PlatformdefaultCallAdapterFactories如下:

  List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
      @Nullable Executor callbackExecutor) {
    DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
    return hasJava8Types
        ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
        : singletonList(executorFactory);
  }

在「Retrofit对象创建」当中提到,Platform的实例是AndroidAndroid实例通过SDK版本是否大于等于24来判断hasJava8Types的值是否为true,我们这里认为它是true。因为hasJava8Types的值为true,所以在defaultCallAdapterFactories方法会将CompletableFutureCallAdapterFactoryDefaultCallAdapterFactory添加到callAdapterFactories中,所以callAdapterFactories的元素:

  1. 用户自定义的CallAdapter.Factory(我们一般不会自定义CallAdapter.Factory)
  2. CompletableFutureCallAdapterFactory(只处理接口方法的返回类型为CompletableFuture<T>的)
  3. DefaultCallAdapterFactory

RxJava的适配器:XXX.addCallAdapterFactory(RxJava3CallAdapterFactory.create()),就是属于一种「用户自定义的CallAdapter.Factory」。

并且由上至下优先级递减,其中DefaultCallAdapterFactory的优先级最低。一般情况下,由DefaultCallAdapterFactory处理我们的请求,这里直接分析它即可:

final class DefaultCallAdapterFactory extends CallAdapter.Factory {
  // 默认情况下,这是一个MainThreadExecutor,可以通过handler将任务调度到主线程中执行  
  private final @Nullable Executor callbackExecutor;

  DefaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    this.callbackExecutor = callbackExecutor;
  }

  # returnType:接口方法的返回类型,如Call<User>
  # annotations:接口方法的注解
  @Override
  public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    // 检查接口方法的返回类型  
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    if (!(returnType instanceof ParameterizedType)) {
      throw new IllegalArgumentException(
          "Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
    }
    // 获取返回类型的泛型参数的上界  
    final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);

    // 判断方法注解是否包含SkipCallbackExecutor.class,一般不包含,所以这里executor的值为
    // callbackExecutor(默认情况下,它是一个MainThreadExecutor)  
    final Executor executor =
        Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
            ? null
            : callbackExecutor;

    // 创建并返回CallAdapter  
    return new CallAdapter<Object, Call<?>>() {
      @Override
      public Type responseType() {
        return responseType;
      }

      // 将Call<Object>适配为Call<Object>  
      @Override
      public Call<Object> adapt(Call<Object> call) {
        // 正常情况下executor不为null,因此call会被适配为一个ExecutorCallbackCall  
        return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }
  
  static final class ExecutorCallbackCall<T> implements Call<T> {...}    
}

简单来说,DefaultCallAdapterFactoryget方法会返回一个CallAdapter,通过CallAdapteradapt方法可以将传入的retrofit2.Call适配包装为一个ExecutorCallbackCall

这个ExecutorCallbackCall实际上就是我们业务层拿到的retrofit2.Call,可以调用它的enqueue或者execute方法进行网络请求,ExecutorCallbackCallDefaultCallAdapterFactory的静态内部类,其定义如下:

  static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    // retrofit2.Call  
    final Call<T> delegate;

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }

    # callback:业务层传入的Callback  
    @Override
    public void enqueue(final Callback<T> callback) {
      Objects.requireNonNull(callback, "callback == null");

      // 调用delegate的enqueue进行请求  
      delegate.enqueue(
          new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, final Response<T> response) {
              // 将回调给业务层的代码,切到主线程中执行  
              callbackExecutor.execute(
                  () -> {
                    if (delegate.isCanceled()) {
                      // Emulate OkHttp's behavior of throwing/delivering an IOException on
                      // cancellation.
                      callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                    } else {
                      callback.onResponse(ExecutorCallbackCall.this, response);
                    }
                  });
            }

            @Override
            public void onFailure(Call<T> call, final Throwable t) {
               // 将回调给业务层的代码,切到主线程中执行  
              callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
            }
          });
    }
    ...
    @Override
    public Response<T> execute() throws IOException {
      return delegate.execute();
    }
	...
  }

两种执行方式:

  • enqueue:异步执行。使用callbackExecutor将给业务层的回调代码切换到主线程中执行。
  • execute:同步执行。

实际上,callbackExecutor也不一定是切换到主线程的MainThreadExecutor,但是默认情况下是MainThreadExecutor,这里我们就认为它是MainThreadExecutor,展开讨论。

ExecutorCallbackCall声明的其余方法不多介绍:

image-20220111125105998

那么,传入ExecutorCallbackCalldelegate变量是怎样的呢?后面将会介绍。

后面我们会知道delegate变量其实是一个OkHttpCall实例。

Converter

Converter是一个接口,用于将类型为F的数据转换为类型T

// Converter实例由Converter.Factory创建,Retrofit里面有Converter.Factory的实例
public interface Converter<F, T> {
  @Nullable
  T convert(F value) throws IOException;

  abstract class Factory {
    // 该Factory可以处理type和annotations的接口方法,则返回Converter,否则返回null  
    # type:接口方法的实际返回类型,例如接口方法声明的是Call<User>类型,则这里传入的是User类型   
    # annotations:接口方法的注解    
    public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
        Type type, Annotation[] annotations, Retrofit retrofit) {
      return null;
    }

    public @Nullable Converter<?, RequestBody> requestBodyConverter(
        Type type,
        Annotation[] parameterAnnotations,
        Annotation[] methodAnnotations,
        Retrofit retrofit) {
      return null;
    }

    public @Nullable Converter<?, String> stringConverter(
        Type type, Annotation[] annotations, Retrofit retrofit) {
      return null;
    }

    protected static Type getParameterUpperBound(int index, ParameterizedType type) {
      return Utils.getParameterUpperBound(index, type);
    }

    protected static Class<?> getRawType(Type type) {
      return Utils.getRawType(type);
    }
  }   
}

Converter.Factory的几个方法:

  • responseBodyConverter:完成ResponseBody到实际的返回类型的转化,实际返回类型例如是Call<User>里面的泛型User
  • requestBodyConverter:完成对象到RequestBody的构造。

关于Converter.Factory更多信息,可以查看 Retrofit2 完全解析 探索与okhttp之间的关系_Hongyang-CSDN博客 的 「六、自定义Converter.Factory」 一节。

查看HttpServiceMethod::createResponseConverter如何创建Converter

  private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
      Retrofit retrofit, Method method, Type responseType) {
    Annotation[] annotations = method.getAnnotations();
    try {
      return retrofit.responseBodyConverter(responseType, annotations);
    } catch (RuntimeException e) { // Wide exception range because factories are user code.
      throw methodError(method, e, "Unable to create converter for %s", responseType);
    }
  }

Retrofit::responseBodyConverter

  public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
    return nextResponseBodyConverter(null, type, annotations);
  }

Retrofit::nextResponseBodyConverter

  public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
      @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
    Objects.requireNonNull(type, "type == null");
    Objects.requireNonNull(annotations, "annotations == null");

    // 从列表开始寻找的位置,这里是从0开始  
    int start = converterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = converterFactories.size(); i < count; i++) {
      // 若索引处的Converter.Factory可以处理接口方法,则返回Converter,否则返回null 
      Converter<ResponseBody, ?> converter =
          converterFactories.get(i).responseBodyConverter(type, annotations, this);
      // 可以获取到Converter则返回它  
      if (converter != null) {
        //noinspection unchecked
        return (Converter<ResponseBody, T>) converter;
      }
    }

    // 没有获取到适合该接口方法的Converter,则拼接异常信息并抛出异常 
    StringBuilder builder = ...
    ...
    throw new IllegalArgumentException(builder.toString());
  }

获取Converter和获取CallAdapter的过程非常类似。

Retrofit.Builder::build得知,列表中会有三种类型的Converter.Factory

  • BuiltInConverters
  • 用户自定义的Converter.Factory,如GsonConverterFactory
  • platform.defaultConverterFactories,其实就是OptionalConverterFactory

BuiltInConverters:当接口方法声明的是Call<ResponseBody>Call<Void>Call<Unit>的时候,BuiltInConverters可以处理,并返回相应的Converter

OptionalConverterFactory:从该类的responseBodyConverter方法可以看出,该类与Optional类有关,若我们的接口方法的返回值没有用到Optional类,则OptionalConverterFactory会返回null

另外要说明的是,BuiltInConverters是优先级最高的Converter.Factory,这防止其它工厂覆盖它的行为;而OptionalConverterFactory的优先级比自定义工厂的优先级低,是优先级最低的Converter.Factory

CallAdapted

在不考虑Retrofit协程支持的情况下,HttpServiceMethod::parseAnnotations最终会创建并返回一个CallAdapted对象,CallAdapted的继承关系:

CallAdapted -> HttpServiceMethod -> ServiceMethod

CallAdaptedHttpServiceMethod的静态内部类

ServiceMethod是一个抽象类,定义如下:

abstract class ServiceMethod<T> {
  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {...}
  // 抽象方法invoke  
  abstract @Nullable T invoke(Object[] args); 
}

它内部定义了抽象方法invoke,在Retrofit::create动态代理InvocationHandler中,就调用了ServiceMethodinvoke方法。

ServiceMethod的直接子类只有一个,即HttpServiceMethod,它也是一个抽象类:

abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
	...
  @Override
  final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }
    
  protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);    
    
  static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {...}  
  ...  
}

HttpServiceMethod的大部分方法前面都已经看过了(即省略号的部分)。上面列出的代码,主要关注的点:

  1. invoke方法中,创建了一个retrofit2.OkHttpCall对象,并且调用虚方法adaptOkHttpCall进行转化,adapt方法在子类中实现。
  2. CallAdapted继承至HttpServiceMethod

注意,HttpServiceMethod重写了父类的invoke方法并标记为final,意味着子类无法重写该方法,又由于ServiceMethod的直接子类只有HttpServiceMethod一个,所以调用ServiceMethod::invoke,实际上调用的是HttpServiceMethod::invoke

CallAdapted定义如下:

  static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
    private final CallAdapter<ResponseT, ReturnT> callAdapter;

    CallAdapted(
        RequestFactory requestFactory,
        okhttp3.Call.Factory callFactory,
        Converter<ResponseBody, ResponseT> responseConverter,
        CallAdapter<ResponseT, ReturnT> callAdapter) {
      super(requestFactory, callFactory, responseConverter);
      this.callAdapter = callAdapter;
    }

    @Override
    protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
      return callAdapter.adapt(call);
    }
  }

HttpServiceMethod::parseAnnotations中创建CallAdapted对象的语句是:

return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);

CallAdapted类中存在很多泛型参数,这里在一个假定的场景下进行讨论,方便理解,假如接口方法的返回类型是Call<User>,并且使用的CallAdapter.FactoryDefaultCallAdapterFactory,则CallAdapted类中的泛型参数为:

ResponseT = Object;
ReturnT = Call<User>;
即CallAdapted<Object, Call<User>>

因此,CallAdaptedadapt方法就可以实现转化:retrofit2.Call

posted @ 2022-01-21 13:53  Giagor  阅读(427)  评论(0编辑  收藏  举报