Retrofit源码解析

1 Retrofit简单介绍和用法示例

1.1 Retrofit简介

Retrofit是Square公司推出的一个Http客户端开源框架,主要用于Android和Java应用程序。其核心的理念是将Http的网络接口转化为对应的Java/Kotlin接口,借鉴Java开发中的REST风格注解,将网络请求的方法参数和接口入参对应成一个个注解和注解入参。Retrofit具备如下优点(项目的地址github.com/square/retr...

  1. REST风格的基于注解的java接口定义Http网络接口和网络接口入参
  2. Retrofit在编译时通过注解器和运行时确保类型安全
  3. 强大的数据转化能力,通过Converter机制把请求体转为Java/Kotlin对象,并将返回体解析为对应的对象
  4. 灵活的CallAdapter适配器模式,使得接口不仅限于基础的Call类型,可以无缝衔接如协程、Rxjava等异步编程体系
  5. 与OkHttp比,不需要处理线程切换了,回调切换到主线程调用

1.2 Retrofit使用简介

首先还是库的导入工作,根据上面提供的项目地址可以看到,需要在gradle中导入如下库:

kotlin 复制代码
implementation("com.squareup.retrofit2:retrofit:3.0.0")
// 选择性导入,根据项目需求导入对应的converter
implementation("com.squareup.retrofit2:retrofit:converter-gson:3.0.0")

然后通过build模式创建Retrofit实例(实际可以添加很多自定义的项目配置项):

kotlin 复制代码
val retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com")
    .build()

通过Kotlin接口定义我们的网络接口:

kotlin 复制代码
interface GitHubService {
  @GET("users/{user}/repos")
  fun listRepos(@Path("user") String user):Call<List<Repo>> 
}

根据前面创建的Retrofit实例和定义的GitHubService接口可以开始真正的网络接口执行部分了:

kotlin 复制代码
val service = retrofit.create(GitHubService.class)
service.listRepos("UserName").enqueue(object : Callback<List<Repo>> {
      override fun onResponse(call: Call<List<Repo>>, response: Response<List<Repo>>) {
        // 数据成功回调(主线程中)
      }

      override fun onFailure(call: Call<List<Repo>>, t: Throwable) {
        // error 处理逻辑
      }
    })

可以看到当我们定义的网络接口返回为Call类型时,实际就是以OkHttp的方式进行回调处理。

2 Retrofit源码实现分析

2.1 网络接口请求主流程分析

从1.2的使用介绍中可以看到retrofit2.Retrofit#create方法真正返回了GitHubService接口实例,后续的接口请求也是依赖于GitHubService实例进行的,那么先看看这个create方法里面做了些什么吧:

java 复制代码
public <T> T create(final Class<T> service) {
    validateServiceInterface(service);
    return (T)
        Proxy.newProxyInstance(
            service.getClassLoader(),
            new Class<?>[] {service},
            new InvocationHandler() {
              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.
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                args = args != null ? args : emptyArgs;
                Reflection reflection = Platform.reflection;
                return reflection.isDefaultMethod(method)
                    ? reflection.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(service, method).invoke(proxy, args);
              }
            });
  }
  1. 可以看到create方法的入参为Class,返回的类型为T,其中一共做了两个处理,首先是retrofit2.Retrofit#validateServiceInterface,然后动态代理传入的接口类,接下来先看看validateServiceInterface里面做了些什么:
java 复制代码
private void validateServiceInterface(Class<?> service) {
    // a、入参service类型检查不为接口直接抛异常
    if (!service.isInterface()) {
      throw new IllegalArgumentException("API declarations must be interfaces.");
    }

    Deque<Class<?>> check = new ArrayDeque<>(1);
    check.add(service);
    // b、循环检查传入的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());
      }
      Collections.addAll(check, candidate.getInterfaces());
    }

    if (validateEagerly) {
      Reflection reflection = Platform.reflection;
      for (Method method : service.getDeclaredMethods()) {
        if (!reflection.isDefaultMethod(method)
            && !Modifier.isStatic(method.getModifiers())
            && !method.isSynthetic()) {
          // c、加载服务方法
          loadServiceMethod(service, method);
        }
      }
    }
  }

2.根据流程1中的注释,完成必要的入参检查后,我们看看流程1的注释c处retrofit2.Retrofit#loadServiceMethod方法中做了些什么:

java 复制代码
ServiceMethod<?> loadServiceMethod(Class<?> service, Method method) {
    while (true) {
      // Note: Once we are minSdk 24 this whole method can be replaced by computeIfAbsent.
      // a、尝试从serviceMethodCache缓存中取,取到的是ServiceMethod对象直接返回
      Object lookup = serviceMethodCache.get(method);
      if (lookup instanceof ServiceMethod<?>) {
        // Happy path: method is already parsed into the model.
        return (ServiceMethod<?>) lookup;
      }

      if (lookup == null) {
        // Map does not contain any value. Try to put in a lock for this method. We MUST synchronize
        // on the lock before it is visible to others via the map to signal we are doing the work.
        Object lock = new Object();
        synchronized (lock) {
          // b、将锁对象存入serviceMethodCache中
          lookup = serviceMethodCache.putIfAbsent(method, lock);
          if (lookup == null) {
            // On successful lock insertion, perform the work and update the map before releasing.
            // Other threads may be waiting on lock now and will expect the parsed model.
            ServiceMethod<Object> result;
            try {
              // c、解析方法注解
              result = ServiceMethod.parseAnnotations(this, service, method);
            } catch (Throwable e) {
              // Remove the lock on failure. Any other locked threads will retry as a result.
              serviceMethodCache.remove(method);
              throw e;
            }
            // d、更新缓存serviceMethodCache中注解解析结果
            serviceMethodCache.put(method, result);
            return result;
          }
        }
      }

      synchronized (lookup) {
        // e、lookup不为空,表示serviceMethodCache缓存中已经有方法的解析结果了,检查缓存中结果
        Object result = serviceMethodCache.get(method);
        if (result == null) {
          // The other thread failed its parsing. We will retry (and probably also fail).
          continue;
        }
        return (ServiceMethod<?>) result;
      }
    }
  }
  1. 从流程2中可以看出来,关键点在于注释c处的retrofit2.ServiceMethod#parseAnnotations方法的解析结果,接下来跟进parseAnnotations方法中,其实现如下:
java 复制代码
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Class<?> service, Method method) {
    // a、解析Http方法的注解
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, service, 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.");
    }
    // b、返回解析后的Http接口方法
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }
  1. 流程3处的代码注释a处,retrofit2.RequestFactory#parseAnnotations会解析我们写的接口的方法注解和方法参数注解,生成RequestFactory并传入retrofit2.HttpServiceMethod#parseAnnotations方法中,看来最重要的部分都留在了流程3的注释b处,继续跟进这个方法看看其内部实现:
java 复制代码
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
    boolean continuationWantsResponse = false;
    boolean continuationBodyNullable = false;
    boolean continuationIsUnit = 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 {
        if (getRawType(responseType) == Call.class) {
          throw methodError(
              method,
              "Suspend functions should not return Call, as they already execute asynchronously.\n"
                  + "Change its return type to %s",
              Utils.getParameterUpperBound(0, (ParameterizedType) responseType));
        }

        continuationIsUnit = Utils.isUnit(responseType);
      }

      adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
      annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
    } else {
      adapterType = method.getGenericReturnType();
    }

    // a、生成CallAdapter适配器实例
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    Type responseType = callAdapter.responseType();
    if (responseType == okhttp3.Response.class) {
      throw methodError(
          method,
          "'"
              + getRawType(responseType).getName()
              + "' is not a valid response body type. Did you mean ResponseBody?");
    }
    if (responseType == Response.class) {
      throw methodError(method, "Response must include generic type (e.g., Response<String>)");
    }
    if (requestFactory.httpMethod.equals("HEAD")
        && !Void.class.equals(responseType)
        && !Utils.isUnit(responseType)) {
      throw methodError(method, "HEAD method must use Void or Unit as response type.");
    }

    // b、生成Convert转化器实例
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {
      // c、非协程方式,生成Call适配器对象实例
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      // d、协程式的Respone适配器实例
      return (HttpServiceMethod<ResponseT, ReturnT>)
          new SuspendForResponse<>(
              requestFactory,
              callFactory,
              responseConverter,
              (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
    } else {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      // e、协程式的Body适配器实例
      return (HttpServiceMethod<ResponseT, ReturnT>)
          new SuspendForBody<>(
              requestFactory,
              callFactory,
              responseConverter,
              (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
              continuationBodyNullable,
              continuationIsUnit);
    }
  }
  1. 假设我们是按照前面Retrofit使用简介章节中给到的方式发起Http请求的,那么上面的流程4中实际返回的是一个CallAdapter类型的对象,现在回到Retrofit的create方法中,前面流程1到流程4介绍的是retrofit2.Retrofit#validateServiceInterface方法的处理逻辑,前面create方法还做动态代理处理,现在看看动态代理实际上执行了流程4返回的retrofit2.HttpServiceMethod.CallAdapted对象的invoke方法,经过调用会走到retrofit2.HttpServiceMethod.CallAdapted#adapt方法,该方法调用的流程4中注释a处生成的Adapter实例,这个实例的来源是retrofit2.DefaultCallAdapterFactory#get方法中返回的,我们一起看看这个get方法的实现:
java 复制代码
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);

    final Executor executor =
        Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
            ? null
            : callbackExecutor;

    return new CallAdapter<Object, Call<?>>() {
      @Override
      public Type responseType() {
        return responseType;
      }

      @Override
      public Call<Object> adapt(Call<Object> call) {
        return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }
  1. 前面提到的etrofit2.HttpServiceMethod.CallAdapted#adapt就调用了流程5中retrofit2.DefaultCallAdapterFactory#get返回中的ExecutorCallbackCall对象,前面使用简介章节中的enqueue方法实际调用的是retrofit2.DefaultCallAdapterFactory.ExecutorCallbackCall#enqueue方法,其实现如下:
java 复制代码
public void enqueue(final Callback<T> callback) {
      Objects.requireNonNull(callback, "callback == null");

      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));
            }
          });
    }

其中delegate实例的类型是OkHttpCall类型,创建于retrofit2.HttpServiceMethod#invoke方法中,至此Retrofit完成了Call的请求入列,整个Retrofit主流程就分析完了。后续进入了OkHttp框架请求流程中,这一块在我的专栏《OkHttp源码解析》中有介绍,这里就不再重复赘述了,这也是我先写OkHttp后写这篇文章的原因。具体的实现细节可以移步这个链接中juejin.cn/post/752843...

2.2 Retrofit源码细节

2.2.1 Retrofit回调线程切换

OkHttp与Retrofit有个区别是,OkHttp的网络加载回调默认在子线程中,而Retrofit默认是在主线程回调网络返回结果(划重点啦,这一个面试中经常问到的问题)。我们来看下Retrofit框架为我们做了什么事情,可以默认在主线程给出网络回调。在2.1节介绍主流程的时候我们知道retrofit2.DefaultCallAdapterFactory#get方法返回了一个ExecutorCallbackCall对象,这个对象的构造函数有两个,其中一个是Executor,查看Executor参数传入的地方,实际来自于retrofit2.Retrofit.Builder#build方法初始化默认的CallAdaptFactory对象的时候传入的,具体看看build方法中和Executor相关代码:

java 复制代码
    Epublic Retrofit build() {
      // 省略部分代码实现
      ...

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        // a、未设置的时候默认取Platform.callbackExecutor值
        callbackExecutor = Platform.callbackExecutor;
      }

      BuiltInFactories builtInFactories = Platform.builtInFactories;

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

     // 省略部分代码实现
}

可以看到上述代码注释a处的executor值,其中Platform.callbackExecutor值的定义为AndroidMainExecutor,其类实现如下:

java 复制代码
final class AndroidMainExecutor implements Executor {
  private final Handler handler = new Handler(Looper.getMainLooper());

  @Override
  public void execute(Runnable r) {
    handler.post(r);
  }
}

可见Retrofit可以在主线程回调网络数据返回实际上,底层依赖的是Handler机制。

2.2.2 注解处理

其实整个主流程分析的过程中都没真正讲注解的处理和解析,这里先把整个Retrofit中的注解先列出来:

1. HTTP 请求方法注解
注解 作用描述
@GET 发起 GET 请求
@POST 发起 POST 请求
@PUT 发起 PUT 请求
@DELETE 发起 DELETE 请求
@PATCH 发起 PATCH 请求
@HEAD 发起 HEAD 请求
@OPTIONS 发起 OPTIONS 请求
@HTTP 自定义 HTTP 方法(需指定 methodpathhasBody

2. URL 路径处理注解
注解 作用描述
@Path 动态替换 URL 中的路径占位符(如 /user/{id}
@Url 直接传入完整 URL(覆盖 BaseUrl)

3. 请求参数注解
注解 作用描述
@Query 添加 URL 查询参数(单个)
@QueryMap 添加多个 URL 查询参数(Map 或对象)
@QueryName 添加无值的查询参数(如 ?key
@Query + 集合 添加重复键的查询参数(如 ?ids=1&ids=2

4. 请求头注解
注解 作用描述
@Header 动态添加单个请求头(方法参数)
@Headers 添加静态请求头(类或方法上)
@HeaderMap 动态添加多个请求头(Map 参数)

5. 请求体注解
注解 作用描述
@Body 将对象转换为请求体(如 JSON/XML)

6. 表单编码注解
注解 作用描述
@FormUrlEncoded 标记请求体为表单(与 @Field 配合)
@Field 添加表单字段(单个)
@FieldMap 添加多个表单字段(Map)

7. 多部分请求注解
注解 作用描述
@Multipart 标记请求体为多部分(文件上传)
@Part 添加多部分数据(如文件/文本)
@PartMap 添加多个多部分数据(Map)

8. 其他辅助注解
注解 作用描述
@Streaming 将响应体作为流处理(大文件下载)
@Tag 为请求关联标签(用于分组管理)

接下来我们看看这些注解在Retrofit框架中是如何被解析和转化成咱们的数据结构和代码的,在分析Retrofit主流程的2.1节流程3的注释a处,讲了是解析Http的注解,我们看看retrofit2.RequestFactory#parseAnnotations做了些什么:

java 复制代码
static RequestFactory parseAnnotations(Retrofit retrofit, Class<?> service, Method method) {
    return new Builder(retrofit, service, method).build();
  }

看来真正的解析还要往里面再看看:

java 复制代码
RequestFactory build() {
      for (Annotation annotation : methodAnnotations) {
        // a、解析方法注解
        parseMethodAnnotation(annotation);
      }

      // 省略部分非关键代码
     ...

      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
        // b、解析方法参数注解
        parameterHandlers[p] =
            parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
      }

     // 省略部分非关键代码
     ...

      return new RequestFactory(this);
    }

具体的处理逻辑在注释的a、b两处方法内,其实就是逐个解析注解,实现不复杂,但是代码很多,这里就不一一列举出来了,读者感兴趣的话自行了解并阅读即可。

2.2.3 Retrofit对协程的支持实现

Retrofit原生是支持协程的,在真正开始介绍Retrofit协程的支持之前,我需要先介绍一个背景知识,当我们在写接口的时候,如果我们在定义接口的时候是这样的:

kotlin 复制代码
interface GitHubService {
  @GET("users/{user}/repos")
  suspend fun listRepos(@Path("user") String user):Call<List<Repo>> 
}

那么我们生成的动态代理实例中,lisRepos方法的参数会被协程编译器增加一个Continuation续体在方法参数的最后面,在2.2.2节的build方法注释b处,会处理这个增加的Continuation续体参数,我们看看这个是怎么处理的呢:

java 复制代码
private @Nullable ParameterHandler<?> parseParameter(
        int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
      // 省略和协程不相关的部分代码
      ...

      if (result == null) {
        if (allowContinuation) {
          try {
            if (Utils.getRawType(parameterType) == Continuation.class) {
              // a、当传入的参数类型为Continuation时,
              //  isKotlinSuspendFunction变量被置位为true
              isKotlinSuspendFunction = true;
              return null;
            }
          } catch (NoClassDefFoundError ignored) {
            // Ignored
          }
        }
        throw parameterError(method, p, "No Retrofit annotation found.");
      }

      return result;
    }

从上面的注释和前面介绍的背景知识,可以了解到isKotlinSuspendFunction会被置位为true,那么这个变量到底有什么作用呢,如果你记忆力够好的话,你会记得在2.1章节分析主流程的时候,流程4处retrofit2.HttpServiceMethod#parseAnnotations方法注释c处用到了这个变量值。当isKotlinSuspendFunction是true的时候会返回retrofit2.HttpServiceMethod.SuspendForResponse#SuspendForResponse和retrofit2.HttpServiceMethod.SuspendForBody#SuspendForBody类型的适配器,这里以SuspendForResponse类型的返回为例,实际上适配器的adapt方法会调用retrofit2.KotlinExtensions#awaitResponse方法,这个方法实际上是Call接口类的一个扩展方法,他的实现如下:

kotlin 复制代码
suspend fun <T> Call<T>.awaitResponse(): Response<T> {
  return suspendCancellableCoroutine { continuation ->
    continuation.invokeOnCancellation {
      cancel()
    }
    enqueue(object : Callback<T> {
      override fun onResponse(call: Call<T>, response: Response<T>) {
        continuation.resume(response)
      }

      override fun onFailure(call: Call<T>, t: Throwable) {
        continuation.resumeWithException(t)
      }
    })
  }
}

可以看到很简单就完成了Retrofit的协程支持,当然Retrofit也支持了Rxjava流式编程,不得不说这个适配器模式还是很厉害的,可以实现Call到不同类型返回的转变,这种设计思想希望读者也能够领会到这个模式的魅力所在。

3 小结

Retrofit凭借其优雅的设计、强大的扩展性(CallAdapter/Converter机制)和优异的性能,已成为 Android开发中网络请求的首选框架,特别适合中大型项目和对代码质量要求较高的场景。这个框架设计的思想也有很多值得我们借鉴的地方,笔者自己在写这篇文章的时候再次阅读源码,也感觉受益不少,这也是我写这个系列文章的初衷之一。创作不易,欢迎各位一键三连啊,点赞、收藏、关注点起来,来跟着Muggle一起学习Android开发。

相关推荐
智江鹏26 分钟前
Android 之 串口通信
android
拾光拾趣录1 小时前
🔥99%人答不全的安全链!第5问必翻车?💥
前端·面试
IH_LZH1 小时前
kotlin小记(1)
android·java·前端·kotlin
Java技术小馆1 小时前
MCP是怎么和大模型交互
前端·面试·架构
wayhome在哪2 小时前
面试造火箭 入职拧螺丝
vue.js·面试·jquery
掘金安东尼2 小时前
⏰前端周刊第425期(2025年7月28日–8月3日)
前端·javascript·面试
_祝你今天愉快2 小时前
Java垃圾回收(GC)探析
android·java·后端
NeverSettle1105743 小时前
通过取消请求解决请求竞态问题
前端·面试
PineappleCoder3 小时前
用 “私房钱” 类比闭包:为啥它能访问外部变量?
前端·javascript·面试