Retrofit2.5.0解析

并不想将Retrofit放在okhttp中,但是感觉单独出来太占地了,但是Retrofit中还是有使用到okhttp的,所以将其放在一起吧。
本文分析的Retrofit是基于2.5.0,也就是现在的最新版本。
具体的下载: 地址
先讲讲题外的,当你将上述工程拷贝下来时,发现这个工程并不是一个Android的工程(有点坑了),刚开始我的做法是将其中的目录有关Retrofit的项目工程复制出来粘贴到AndroidStduio中,但是发现这个过程中还是有其他问题(注解报错,构建Retrofi实例的时候出现解析gson的报错),我们还要单独在gralde文件中引入其他库。这样太麻烦了

  implementation 'com.google.code.findbugs:jsr305:3.0.2'
  implementation 'com.squareup.retrofit2:converter-gson:2.5.0' // 用Gson解析json的转换器

当然还有其他方法,上面的工程其实是一个java工程,只需要下载IDEA工具(网上有破解版的),等待编译成功之后,运行“SimpleService”文件即可执行。
当然在AndroidStudio中添加引入不可能用上面的那种方法(太麻烦了),可以在工程中添加gradle依赖

implementation 'com.squareup.retrofit2:converter-gson:2.5.0' // 用Gson解析json的转换器
implementation 'com.squareup.retrofit2:retrofit:2.5.0'

这种方法的缺点是分析代码流程中会有问题,我说的问题只是说分析流程有些许问题,如果这些你感觉可以忽略,那么完全没必要用IDEA来编译项目,可以使用AndroidStudio来分析。
至于Retrofit使用的话,Retrofit类注解中已经有例子,并且有官方文档

/**
 * Retrofit adapts a Java interface to HTTP calls by using annotations on the declared methods to
 * define how requests are made. Create instances using {@linkplain Builder
 * the builder} and pass your interface to {@link #create} to generate an implementation.
 * <p>
 * For example,
 * <pre><code>
 * Retrofit retrofit = new Retrofit.Builder()
 *     .baseUrl("https://api.example.com/")
 *     .addConverterFactory(GsonConverterFactory.create())
 *     .build();
 *
 * MyApi api = retrofit.create(MyApi.class);
 * Response&lt;User&gt; user = api.getUser().execute();
 * </code></pre>
 *
 * @author Bob Lee (bob@squareup.com)
 * @author Jake Wharton (jw@squareup.com)
 */
public final class Retrofit {
  ...
}

现在来分析下Retrofit的实现过程,需要先熟悉动态代理,如果忘记的话可以看看这篇动态代理
下面以SimpleService 为例,来分析整个实现过程。

public final class SimpleService {
  public static final String API_URL = "https://api.github.com:443/";

  public static class Contributor {
    public final String login;
    public final int contributions;

    public Contributor(String login, int contributions) {
      this.login = login;
      this.contributions = contributions;
    }
  }

  public interface GitHub {
    @GET("/repos/{owner}/{repo}/contributors")
    Call<List<Contributor>> contributors(
        @Path("owner") String owner,
        @Path("repo") String repo);
  }

  public static void main(String... args) throws IOException {
    // Create a very simple REST adapter which points the GitHub API.
    Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(API_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .build(); //1

    // Create an instance of our GitHub API interface.
    GitHub github = retrofit.create(GitHub.class); //2

    // Create a call instance for looking up Retrofit contributors.
    Call<List<Contributor>> call = github.contributors("square", "retrofit");//3

    // Fetch and print a list of the contributors to the library.
    List<Contributor> contributors = call.execute().body();//4
    for (Contributor contributor : contributors) {
      System.out.println(contributor.login + " (" + contributor.contributions + ")");
    }
  }
  • 1 是Retrofit的构建过程
  • 2是使用动态代理生成代理类的过程
  • 3是调用代理类中的方法
  • 4是通过okhttpclient请求数据的过程
    Retrofit的构建过程使用了Builder设计模式,首先是添加请求的baseUrl地址,注意baseUrl的格式是这种“protocol://hostname:port/”例如:https://api.github.com/,端口号可加可不加。addConverterFactory()是一种一种数据序列化和反序列话对象的转换器。最后再看下build()方法。
 public Retrofit build() {
      //如果baseUrl为空出现异常
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      //okhttp的工厂类
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        // 生成一个默认的okhttpclient,用于发送http请求和接受
        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.
      // callAdapter集合
      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);
    }
  }

其中Builde的默认构造方法也需要看下,根据不同编译环境,得到不同编译平台,在build()方法中有使用,现在使用的idea构建的的所以是Java8的版本(还有Android的版本)。

 public Builder() {
      this(Platform.get());
    }
   Builder(Platform platform) {
      this.platform = platform;
    }
   ---
class Platform {
  private static final Platform PLATFORM = findPlatform();

  static Platform get() {
    return PLATFORM;
  }
  // 判断当前的环境
  private static Platform findPlatform() {
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }
....
}

再看下retrofit.create(GitHub.class)方法。

 public <T> T create(final Class<T> service) {
    //验证这个是不是接口
    Utils.validateServiceInterface(service);
  //默认false
    if (validateEagerly) {
      eagerlyValidateMethods(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类
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
          // 接口中的方法都是public
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            //生成方法的ServiceMethod实例
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
//            return  null;
          }
        });
  }
  • 首先是验证传进来的是不是接口
  • 是否提前将请求接口中的方法缓存对应的服务。
  • 动态代理生成对应的代理类。
    当执行github.contributors("square", "retrofit")方法时,执行loadServiceMethod(method).invoke(args != null ? args : emptyArgs)这句,看下具体的实现。先看下loadServiceMethod(method),这个是根据传入的方法生成方法的ServiceMethod,并且缓存起来。

  ServiceMethod<?> loadServiceMethod(Method method) {
    //首次的话,肯定null。
    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.parseAnnotations(this, method);

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

    //方法返回的类型
    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);//2
  }

  abstract @Nullable T invoke(Object[] args);
}
  • 1处主要是根据传入的方法,解析方法和方法注解,用来以后配置一个requet。
  • 2处是获得HttpServiceMethod对象。
    看下HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory)
  /**
   * Inspects the annotations on an interface method to construct a reusable service method that
   * speaks HTTP. This requires potentially-expensive reflection so it is best to build each service
   * method only once and reuse it.
   * 检查接口方法上的注释,在网络请求时候,构造可重用服务方法。 这需要用到反射,因此最好只构建一次每个服务方法并重用它。
   */
   static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
            Retrofit retrofit, Method method, RequestFactory requestFactory) {
      //创建CallAdapter
      CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method); // 1
      //获取method方法 返回参数的泛型表达
      Type responseType = callAdapter.responseType();
      if (responseType == Response.class || responseType == okhttp3.Response.class) {
        throw methodError(method, "'"
                + Utils.getRawType(responseType).getName()
                + "' is not a valid response body type. Did you mean ResponseBody?");
      }
      if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
        throw methodError(method, "HEAD method must use Void as response type.");
      }

      //构建Resoponseconverter对象
      Converter<ResponseBody, ResponseT> responseConverter =
              createResponseConverter(retrofit, method, responseType);

      okhttp3.Call.Factory callFactory = retrofit.callFactory;
      return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
    }

注意1处和2处,1处的作用的是将response 转换为需要的类型,2处是生成一个ServiceMethod对象。
然后在看前面代理模式中的

 return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);

也就是调用HttpServiceMethod的invoke()方法,在看HttpServiceMethod中的invoke()方法。

  ...
 @Override ReturnT invoke(Object[] args) {
    return callAdapter.adapt(
            new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
  }

实际是调用的1处的Calladapter里的adapt()方法,现在我们看看1处的生成过程。

 private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
          Retrofit retrofit, Method method) {
    Type returnType = method.getGenericReturnType();
    Annotation[] annotations = method.getAnnotations();
    try {
      // noinspection unchecked
      // DefaultCallAdapterFactory
      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生成的,然后再在retrofit中查看

 /**从callAdapterFactories 集合中根据returnType 得到callAdapter
   * Returns the {@link CallAdapter} for {@code returnType} from the available {@linkplain
   * #callAdapterFactories() factories}.
   *
   * @throws IllegalArgumentException if no call adapter available for {@code type}.
   */
  public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }

  /** CompletableFutureCallAdapterFactory
   * Returns the {@link CallAdapter} for {@code returnType} from the available {@linkplain
   * #callAdapterFactories() factories} except {@code skipPast}.
   *
   * @throws IllegalArgumentException if no call adapter available for {@code type}.
   */
  public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
    checkNotNull(returnType, "returnType == null");
    checkNotNull(annotations, "annotations == null");

    int start = callAdapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this); // 3
      if (adapter != null) {
        return adapter;
      }
    }
    ....
  }

最终会根据callAdapterFactories 来生成对象的CallAdapter对象,callAdapterFactories 在retrofit.build()时初始化

  public Retrofit build() {
     ...
      // callAdapter集合
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
    ...
    }

现在platform 是java环境默认有俩个

  @Override List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
        @Nullable Executor callbackExecutor) {
      List<CallAdapter.Factory> factories = new ArrayList<>(2);
      factories.add(CompletableFutureCallAdapterFactory.INSTANCE);
      factories.add(new DefaultCallAdapterFactory(callbackExecutor));
      return unmodifiableList(factories);
    }

所以在执行3的时候callAdapterFactories中会有2中实例,而最终根据返回类型我们是在DefaultCallAdapterFactory中得到匹配的CallApater实例。

final class DefaultCallAdapterFactory extends CallAdapter.Factory {
   ...
  @Override public @Nullable CallAdapter<?, ?> get(
   ...
//SkipCallbackExecutor 是否是annotations中的一个实例
  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) {
       //这里 executor = null;
        return executor == null
            ? call
            : new ExecutorCallbackCall<>(executor, call); //4 
      }
    };
  }
...

}

注意到4处也就是我们动态代理中的实际的返回 loadServiceMethod(method).invoke(args != null ? args : emptyArgs);最终得到的就是call 。
整理下流程:


image.png

现在我们知道SimpleService中的Call<List<Contributor>> call = github.contributors("square", "retrofit");
call 对象实际就是OkHttpCall类了。OkHttpCall实现了Call接口,在调用SimpleService中的 call.execute().body();其实也就是调用的OkhttpCall中的execute()方法。OkHttpCall中有异步和同步的调用,异步调用的是用enqueue(final Callback<T> callback)方法,现在用的是同步请求execute()。看下具体的实现:

@Override public Response<T> execute() throws IOException {
    okhttp3.Call call;

    synchronized (this) {
      //如果当前已经执行了 则抛出异常。
      if (executed) throw new IllegalStateException("Already executed.");
      //修改操作状态
      executed = true;
      //是否有异常产生
      if (creationFailure != null) {
        if (creationFailure instanceof IOException) {
          throw (IOException) creationFailure;
        } else if (creationFailure instanceof RuntimeException) {
          throw (RuntimeException) creationFailure;
        } else {
          throw (Error) creationFailure;
        }
      }
      call = rawCall;
      if (call == null) {
        try {
          //创建原生的Call
          call = rawCall = createRawCall();
        } catch (IOException | RuntimeException | Error e) {
          throwIfFatal(e); //  Do not assign a fatal error to creationFailure.
          creationFailure = e;
          throw e;
        }
      }
    }
    //如果取消则,则请求取消连接
    if (canceled) {
      call.cancel();
    }
    //解析Response
    return parseResponse(call.execute());
  }
  • 首先是判断这个请求是否已经发送。
  • 判断是否有异常产生。
  • 创建并通过OkHttpClient发送请求。
  • 解析Response数据。
    整个Retrofit创建到发送请求的,以及接收数据的流程就已经走完了。
    不知道有没有觉察到,为什么我们获取的是json这种格式的数据,但解析出来的就是Call<List<Contributor>>这种java格式呢? 下面来看看这个问题。
    首先我们来看看我们是如何来解析Response数据的。在OkHttpCall中
 Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
   ...
    try {
      //将rawBody转换为对应的 java对象
        T body = responseConverter.convert(catchingBody);
      //构建新的Response对象
      return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
      // If the underlying source threw an exception, propagate that rather than indicating it was
      // a runtime exception.
      catchingBody.throwIfCaught();
      throw e;
    }
  }

注意这个responseConverter也就是在这里将json格式转换为我们需要的格式。responseConverter 的生成是在OkHttpCall的构造器中生成的,经过系列的跟踪,发现responseConverter实例是在Retrofit中生成

  public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
    ...
    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;
      }
    }

   ...
  }

而converterFactories集合中有我们构造retrofit在实例时传递的GsonConverterFactory.create()实例,所以最终responseConverter的是在GsonConverterFactory中生成。

public final class GsonConverterFactory extends Converter.Factory {
  
....
  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonResponseBodyConverter<>(gson, adapter);
  }
...
}

现在最主要涉及的就是TypeToken.get(type) type参数的传递的是什么内容了,最终我们发现type的生成是在DefaultCallAdapterFactory中

  @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>");
    }
    //根据ParameterizedType 返回参数的范型类型
    // 假如 返回参数类型 returnType 是Call<List<Contributor>>  那么返回的参数类型的范型就是 Type = List<Contributor>,只是第一层泛型
    //假如 返回参数类型 returnType 是Contributor 那么没有参数类型的范型 就会报错
    final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
      //SkipCallbackExecutor 是否是annotations中的一个实例
    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) {
        //这里 executor = null;
        return executor == null
            ? call
            : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }

传递是通过HttpServiceMethod.回调的进行的。

    */
    static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
            Retrofit retrofit, Method method, RequestFactory requestFactory) {
    ...
      //获取method方法 返回参数的泛型表达
      Type responseType = callAdapter.responseType();
    ...
    }

所以这个reponseType是在方法定义时已经定义好了的 Call<List<Contributor>>,通过Gson将json格式转化为我们需要的Java对象。

 public interface GitHub {
    @GET("/repos/{owner}/{repo}/contributors")
    Call<List<Contributor>> contributors(
        @Path("owner") String owner,
        @Path("repo") String repo);
  }

所以整个将json解析成java对象的流程也执行流程也完了。

对我们来说,那么Retrofit有什么好处呢?
  • 更好的封装了请求,利于管理,将所有的请求都放在同一个接口文件中,不管是删除,添加,修改都很方便。
  • 通过RequetFactory 封装请求的Request。
  • Retrofit结合Okhttp使用,基本将OKhttpclient的各种好处都集成过来(支持https,缓存,连接池,自动重连,重定向等)。结合okhttpclient让我们不用花太多时间在网络层面,将更多精力放在业务层面。
  • 封装数据转换,自动可以将json格式数据自动转换为java对象。
  • CallAdapter 的设计有点巧妙。
  • 还有一个问题Retrofit 在Android中要进行线程切换 ,可以配合Rxjava来使用。
  • Retrofit的外观模式是指在retrofit.create()中,为子系统一组接口中提供一个统一的接口访问。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容