You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Retrofit 2如何处理retrofit.create()传入接口的函数注解?

Retrofit 注解处理核心原理与代码解析

你定义的GiphyApiService接口:

@GET("gifs/search")
fun getSearchedGifs(
    @Query("q") searchTerm: String,
    @Query("limit") limit: Int = 50,
    @Query("offset") offset: Int = 0,
    @Query("rating") rating: String = "g",
    @Query("lang") lang: String = "en",
    @Query("bundle") bundle: String = "messaging_non_clips",
    @Query("api_key") apiKey: String = "my api key"
): Call<DataResult>

创建Retrofit服务实例的代码:

val retroService = retrofit.create(GiphyApiService::class.java)

Retrofit 处理接口注解的核心依赖动态代理和反射解析,retrofit.create() 是整个流程的入口,下面拆解关键逻辑并展示核心代码片段:

一、retrofit.create() 的核心逻辑

调用create方法时,Retrofit会通过动态代理生成接口的实现类,所有接口方法的调用都会被代理类拦截,进而触发注解解析和请求构建流程。

核心简化代码(来自Retrofit类):

public <T> T create(final Class<T> service) {
  // 校验接口合法性(必须是接口、不能有多重继承等)
  validateServiceInterface(service);
  // JDK动态代理生成实现类
  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 Object invoke(Object proxy, Method method, @Nullable Object[] args)
            throws Throwable {
          // 处理Object类的默认方法(如toString、hashCode)
          if (method.getDeclaringClass() == Object.class) {
            return method.invoke(this, args);
          }
          // 处理Kotlin/Java 8的接口默认方法
          if (platform.isDefaultMethod(method)) {
            return platform.invokeDefaultMethod(method, service, proxy, args);
          }
          // 核心逻辑:解析方法注解,构建可执行的请求处理对象
          return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
        }
      });
}

二、注解解析的核心:ServiceMethod 构建

loadServiceMethod(method) 会把接口方法上的所有注解(@GET、@Query等)解析成可执行的请求逻辑,核心分为两步:解析HTTP方法与路径、解析参数注解。

1. 解析HTTP方法注解(如@GET)

核心代码来自RequestFactory类(负责构建请求的元数据):

private void parseMethodAnnotation(Annotation annotation) {
  if (annotation instanceof GET) {
    parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
  } else if (annotation instanceof POST) {
    parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
  }
  // 同理处理PUT、DELETE、PATCH等其他HTTP方法注解
}

private void parseHttpMethodAndPath(String httpMethod, String path, boolean hasBody) {
  this.httpMethod = httpMethod; // 记录请求方法:GET
  this.relativeUrl = path; // 记录请求路径:gifs/search
  this.hasBody = hasBody; // GET请求无请求体,标记为false
}

2. 解析参数注解(如@Query)

对于@Query("q") searchTerm: String这类参数,Retrofit会解析注解的名称和参数值,最终拼接成URL的查询参数。

核心代码片段:

private ParameterHandler<?> parseParameterAnnotation(Annotation[] annotations, int paramIndex) {
  ParameterHandler<?> handler = null;
  for (Annotation annotation : annotations) {
    handler = parseSingleParameterAnnotation(annotation, paramIndex);
    if (handler != null) break;
  }
  return handler;
}

private ParameterHandler<?> parseSingleParameterAnnotation(Annotation annotation, int paramIndex) {
  if (annotation instanceof Query) {
    Query query = (Query) annotation;
    String paramName = query.value(); // 获取参数名:q
    boolean encoded = query.encoded(); // 是否需要编码参数值
    // 返回Query参数处理器,后续会把参数值拼接进URL
    return new ParameterHandler.Query<>(paramName, encoded);
  }
  // 同理处理@Path、@Body、@Header等其他参数注解
}

三、你的接口方法调用流程

当你调用retroService.getSearchedGifs("cat")时:

  1. 动态代理拦截方法调用,传入getSearchedGifs方法对象和参数列表["cat", 50, 0, "g", "en", "messaging_non_clips", "my api key"]
  2. loadServiceMethod解析方法上的@GET("gifs/search"),确定请求方法为GET,路径为gifs/search
  3. 逐个解析每个参数的@Query注解,将参数名和对应值拼接成URL查询参数,最终生成完整请求URL:
    https://api.giphy.com/v1/gifs/search?q=cat&limit=50&offset=0&rating=g&lang=en&bundle=messaging_non_clips&api_key=my api key
  4. 构建Call<DataResult>对象,调用enqueue或execute时发起实际HTTP请求

关键总结

  • Retrofit通过动态代理让接口方法的调用转向内部逻辑,无需手动实现接口
  • 所有注解的解析都在ServiceMethod/RequestFactory中完成,将注解信息转化为HTTP请求的具体参数
  • 不同的参数注解对应不同的ParameterHandler,负责将参数值注入到请求的对应位置(URL路径、查询参数、请求体等)

内容的提问来源于stack exchange,提问作者1Sayd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 13:47:48