Retrofit2 源码解析

本文主要用于自我学习和交流,如有错误欢迎指正,不胜感激

先看一下我们通常的使用方法

// 1 初始化Retrofit,设置相关参数
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .build();

// 2 通过动态代理创建解析出定义API接口中的方法和注解参数,并创建方法实例
GitHubService service = retrofit.create(GitHubService.class);
Call<List<Repo>> repos = service.listRepos("octocat"); // 此处会执行动态代理InvokeHandler的invoke方法

// 3 最终调用执行方法,实际是调用的OkHttp3的网络请求,这里会在下一篇文章的解析
repos.enqueue(new Callback<List<Repo>>() {
            @Override
            public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
            }
            @Override
            public void onFailure(Call<List<Repo>> call, Throwable t) {
            }
        })

一、Retrofit初始化

==建造者模式==,使用Builder来创建复杂对象Retrofit

    Builder(Platform platform) {
      this.platform = platform;
      // 添加了默认的转换器工厂
      converterFactories.add(new BuiltInConverters());
    }

    public Builder() {
      // 无参构造方法,自动获取平台来初始化Android,Java8
      this(Platform.get());
    }

我们主要看一下Retrofit.Builder的==build==方法

/**
    * Create the {@link Retrofit} instance using the configured values.
    * <p>
    * Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link
    * OkHttpClient} will be created and used.
    * 通过配置创建Retrofit实例,如果没有给Retrofit设置client或者callFactory,
    * 那么会创建并使用默认的OkHttpClient
    */

    public Retrofit build() {
      // 1.1 检验baseUrl是否为空
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      // 1.2 获取执行网络请求调用call的callFactory,如果没有则会使用默认的OkHttpClient
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

      // 1.3 获取默认的回调执行器,没有设置会使用默认平台的执行器,主要用于执行call中返回的execute,request,enqueue等方法
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // 1.4 制作适配器的防御副本并添加默认的呼叫适配器。
      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
     adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // 1.5 制作转换器的防御副本
      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

      // 1.6 使用上述参数创建retrofit对象
      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }

二、retrofit创建接口实例

下面我们先分析一下create中进行的操作

  @SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
  public <T> T create(final Class<T> service) {
    // 2.1 校验传入的参数是否是interface类型
    Utils.validateServiceInterface(service);

    // 这里validateEagerly默认初始化为false
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }

    // 2.2 使用动态代理,解析接口方法的注解和申明字段,并创建传入接口的实例
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();
          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            // 如果是继承自父类Object的方法
            // If the method is a method from Object then defer to normal invocation.
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }

            // 平台自带的方法
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }

            // 步骤一 :Service接口上申明的方法, 这里会解析方法的注解,参数和返回值,并根据相关的信息找到对应的转换器Converter和CallAdapter,这些信息都将保存在ServiceMethod中,最后将方法参数和ServiceMethod存入OkHttpCall中
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);

            // 将OkHttpCall转换成对应平台的Call,Android -> ExecutorCallAdapterFactory.ExecutorCallbackCall, Java8 ->DefaultCallAdapterFactory.new CallAdapter()
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

三、执行网络请求

Java动态代理就会拦截被调用的Java方法,然后解析这个Java方法的注解,最后生成Request由OkHttp发送,最终转化为对应平台的CallAdapter返回给调用者,这里就是动态代理在Retrofit中的精髓所在

先分析下核心的步骤一,通过动态代理拿到接口方法Method method和其参数Object[] args,下面我们具体的看一下==ServiceMethod.loadServiceMethod==中具体进行了哪些操作。

ServiceMethod<?, ?> loadServiceMethod(Method method) {
    // 从缓存中查看是否解析过该方法
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    if (result != null) return result;
    // 缓存中没有的话,同步执行解析方法,并将解析接过存入缓存中
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
      // Builder构造方法,获取了方法的注解,参数类型,参数注解
        result = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }

    return result;
  }

==ServiceMethod==是ServiceMethod中核心的方法,需要详细的分析

public ServiceMethod build() {
      // 1.创建出调用Adapter,并获取响应类型
      callAdapter = createCallAdapter();
      responseType = callAdapter.responseType();

      // 判断响应类型是否合法
      if (responseType == Response.class || responseType == okhttp3.Response.class) {
        throw methodError("'"
            + Utils.getRawType(responseType).getName()
            + "' is not a valid response body type. Did you mean ResponseBody?");
      }

      // 2. 根据初始化Retrofit时候设置的转化器和默认的转化器BuildInConverter,创建对应方法响应的converter,当有多个符合条件的转化器时,会选择List中第一个符合条件的converter
      responseConverter = createResponseConverter();

      // 3. 转化接口方法注解,
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }

      ......
      // 4. 解析方法参数注解,并存储在ParameterHandler中
      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];
        if (Utils.hasUnresolvableType(parameterType)) {
          throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
              parameterType);
        }

        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
        if (parameterAnnotations == null) {
          throw parameterError(p, "No Retrofit annotation found.");
        }

        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }
      ......

      // 最终把Builder中的数据存入到ServiceMethod中
      return new ServiceMethod<>(this);
}

作为Retrofit中经典的转换器==Converter==和调用适配器==CallAdapter==,会单独的进行详细的说明,这里大家能看懂主流程即可

private CallAdapter<T, R> createCallAdapter() {
      // 1. 获取方法的返回值类型
      Type returnType = method.getGenericReturnType();

      // 2. 校验是否有不可取类型的返回类型,具体的泛型相关的知识我们单独将
      if (Utils.hasUnresolvableType(returnType)) {
        throw methodError(
            "Method return type must not include a type variable or wildcard: %s", returnType);
      }

      // 返回不可为空
      if (returnType == void.class) {
        throw methodError("Service methods cannot return void.");
      }

      // 3. 获取方法注解
      Annotation[] annotations = method.getAnnotations();
      try {
        //noinspection unchecked
        // 4. 查找对应的CallAdapter
        return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
      } catch (RuntimeException e) { // Wide exception range because factories are user code.
        throw methodError(e, "Unable to create call adapter for %s", returnType);
      }
    }

继续分析Retrofit的callAdapter方法,这里传入了我们的返回值类型和方法的注解

public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }

  // 查找出合适的调用适配器,Android默认的是
  public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
    checkNotNull(returnType, "returnType == null");
    checkNotNull(annotations, "annotations == null");

    // skipPast为null,所以start = 0, 默认adapterFactories中仅存在Android 平台的ExecutorCallAdapterFactory
    int start = adapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
    ......
    // 构建报错信息,并throw
    throw new IllegalArgumentException(builder.toString());
  }

继续研究下ExecutorCallAdapterFactory

  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    // 获取返回类型的原始类型,如果不是Call返回空, 一般我们定义接口Interface的返回值:Call
    if (getRawType(returnType) != Call.class) {
      return null;
    }

    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

从converterFactories中找出合适的转换适配器

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

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

    int start = converterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = converterFactories.size(); i < count; i++) {
      Converter<ResponseBody, ?> converter =
          converterFactories.get(i).responseBodyConverter(type, annotations, this);
      if (converter != null) {
        //noinspection unchecked
        return (Converter<ResponseBody, T>) converter;
      }
    }

转换retrofit2.http包下对应的注解头信息,请求方式、请求Header、请求体数据类型MIME1

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);
        if (!Void.class.equals(responseType)) {
          throw methodError("HEAD method must use Void as response type.");
        }
      } 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("@Headers annotation is empty.");
        }
        headers = parseHeaders(headersToParse);
      } else if (annotation instanceof Multipart) {
        if (isFormEncoded) {
          throw methodError("Only one encoding annotation is allowed.");
        }
        isMultipart = true;
      } else if (annotation instanceof FormUrlEncoded) {
        if (isMultipart) {
          throw methodError("Only one encoding annotation is allowed.");
        }
        isFormEncoded = true;
      }
    }

转化http方法和路径

private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
      if (this.httpMethod != null) {
        throw methodError("Only one HTTP method is allowed. Found: %s and %s.",
            this.httpMethod, httpMethod);
      }

      // 设置请求方式(POST,GET,PUT等)和是是否有请求体
      this.httpMethod = httpMethod;
      this.hasBody = hasBody;
      if (value.isEmpty()) {
        return;
      }

      // 检查url的相对路径?后是否包含有{id}来动态的查询的请求串,如果有抛出异常,uurl中使用动态的查询替换可以使用@Query,而不是{}方式
      // Get the relative URL path and existing query string, if present.
      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("URL query string \"%s\" must not have replace block. "
              + "For dynamic query parameters use @Query.", queryParams);
        }
      }

      // 设置请求相对路径和请求路径中的需要动态替换的参数
      this.relativeUrl = value;
      this.relativeUrlParamNames = parsePathParameters(value);
    }

总结上面的步骤

  1. 找到接口方法对应的转化器converter
  2. 找到接口方法对应的调用适配器CallAdapter
  3. 解析接口方法的注解,获取对应的请求方式,请求相对路径,路径上动态的路径参数
  4. 解析接口方法的参数,获取对应的注解
  5. 将请求包装成OkHttpCall,并转化成对应平台的类型,最后调用serviceMethod.callAdapter.adapt(okHttpCall)
  6. 最后当我们调用adapter的excute或enqueue时,交由代理类okHttpCall来完成

主要调用过程核心类

  • Retrofit
    • Retrofit.Builder
  • ==MethodService==
    • MethodService.Builder
  • CallAdapter.Factory
    • ExecutorCallAdapterFactory (Android平台)
    • DefaultCallAdapterFactory (默认、Java8)
  • Converter.Factory
    • BuiltInConverters
  • Call
    • OkHttpCall
    • ExecutorCallbackCall

关于OkHttp相关的操作,我们将在下一篇文章进行分析, 动态代理过程中涉及到很多的泛型和Method、Type的使用,这些也会逐步更新

本文主要用于自我学习和交流,如有错误欢迎指正,不胜感激

[1] MIME:Multipurpose Internet Mail Extensions

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,718评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,683评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,207评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,755评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,862评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,050评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,136评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,882评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,330评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,651评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,789评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,477评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,135评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,864评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,099评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,598评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,697评论 2 351