Retrofit的源码阅读记录

680 阅读6分钟

文笔有限,内容比较杂乱,大家可以在看源码时凭此文作为思路补充,行文仓促,后面有空会进行重写,如果错误之处,欢迎指正`

Retrofit 简介

A type-safe HTTP client for Android and Java.

这是官网对Retrofit的描述,即一个类型安全的网络客户端请求库,在我们使用它的时候,运行阶段不会发生类型相关的错误,它能够在编译阶段就能将错误检查出来,所以就“类型安全”来说,一般不谈及某种语言,某种方法类型安全,而是某个工具,某个库 是类型安全,这套工具可以帮助你在运行之前就检查出类型相关的错误,就是就是“类型安全”。

Retrofit 和 OkHttp

Retrofit是OkHttp的进一步包装,让开发者更加容易的进行网络开发,但是进行功能细化的同时,功能收窄是不可避免的,所以Retrofit没有OKHttp功能强大,但使用方便。

简单使用

  1. 引入依赖

    implementation 'com.squareup.retrofit2:retrofit:(insert latest version)'
    
  2. 声明APi

    public interface GitHubService {
        @GET("users/{user}/repos")
        Call<List<Repo>> listRepos(@Path("user") String user);
    }
    

    此处使用获取Github信息来模拟获取数据的姿势,Repo既是获取请求获取的映射类,要获取它,我们要预先获取请求的返回体的 结构,让我们做一个请求https://api.github.com/users/yangSpica27/repos,获取到这段json后,就可以编写相应的类,Kotlin用户使用Kotlin Data Class Code可以自动生成我们的Repo,java用户可以使用GsonFormat

  3. 创建请求Client

    //可以进行更多额外配置
     Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();
    
  4. 实例化接口

    GitHubService service = retrofit.create(GitHubService.class);
    
  5. 进行请求

    Call<List<Repo>> repos = service.listRepos("yangSpica27");
    

    可以使用两种请求方式

    repos.enquene()//异步
    
    repos.execute()//同步
    

    请求发起要传入CallBack对象

     repos.enqueue(new Callback<List<Repo>>() {
            //请求成功时回调
            @Override
            public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
                //请求处理,输出结果
               response.body()//body既是我们获取的返回体,List<Repo>
               reponse.body.get(0).getName()//获取我的Name
            }
    
            //请求失败时候的回调
            @Override
            public void onFailure(Call<List<Repo>> call, Throwable throwable) {
              
            }
        });
    

源码理解

我们首先追根溯源,从enqueue开始,可以看到enqueue仅仅是Call接口的一个方法;

在向上一级service.listRepos()创建出了Repos,但是service.listRepos()依旧只是个接口,而且是由我们手写的;

再向上一级retrofit.create()创建了出了service,终于,到此我们可以看见真正的实现代码。

@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
  public <T> T create(final Class<T> 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.
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                args = args != null ? args : emptyArgs;
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }

create也是Retrofit最核心的代码

validateServiceInterface(service);,直接翻译可以理解为”验证服务接口“,

直接上源码

 private void validateServiceInterface(Class<?> service) {
     //第一部分
    if (!service.isInterface()) {
      throw new IllegalArgumentException("API declarations must be interfaces.");
    }
    //第二部分
    Deque<Class<?>> check = new ArrayDeque<>(1);
    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());
      }
      Collections.addAll(check, candidate.getInterfaces());
    }

    //第三部分
    if (validateEagerly) {
      Platform platform = Platform.get();
      for (Method method : service.getDeclaredMethods()) {
        if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
          loadServiceMethod(method);
        }
      }
    }
  }

validateServiceInterface()的第一部分

   if (!service.isInterface()) {
      throw new IllegalArgumentException("API declarations must be interfaces.");
        }

service是我们传入的接口,这部分是在做类型验证,防止我们传入错误的类型如类,抽象类等。

validateServiceInterface()的第二部分

Deque<Class<?>> check = new ArrayDeque<>(1);
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());
      }
      Collections.addAll(check, candidate.getInterfaces());
    }

Deque是一个双向队列,允许我们从前后两个方向插入,此步将我们的接口加入了check队列, check.removeFirst()将我们刚刚插入的接口取出来,再进行中间的处理之后,再经过Collections.addAll(check, candidate.getInterfaces()) 将Service的父接口也传入check队列之中,说明我们的service 接口如果继承自其他上层接口,它也会进行处理。 我们接下里看看处理过程。

candidate.getTypeParameters().length != 0

getTypeParameters是获取什么参数? 这指的是泛型参数,如SpicaObject<T>,"T"就是这个参数,这个判断的意思就是有"<>"内的参数就报错, 换句话说,这个接口不允许为泛型接口,父接口也不允许是泛型接口。

validateServiceInterface()的第三部分

   if (validateEagerly) {
      Platform platform = Platform.get();
      for (Method method : service.getDeclaredMethods()) {
        if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
          loadServiceMethod(method);
        }
      }
    }

"validateEagerly"翻译过来是激进验证, 我们在使用Retrofit的时候,我们创建的service接口,当它在初次调用的时候,会有一些初始化操作, 这些初始化流程只会在我们第一次调用的时候发生,不使用的时候则不会去主动初始化,为了防止这些方法在触发后产生问题, 在create的过程中我们就可以进行验证,方便测试,这就是"validateEagerly"激进验证的由来。 loadServiceMethod(method)就是调用方法的加载,进行方法的初始化,从而检查,上方的判断就是判断接口的类型,不是默认实现,不是静态方法, 这也表示,Retrofit是不支持静态方法和默认实现的接口方法的。

create()

接下来我们返create部分,下面让我们来看看Retrofit的核心方法Proxy.newProxyInstance(),也就是动态代理

动态代理:

  • 代理:Retrofit创建了一个类,这个类会生成一个对象,这个类实现了我们给予它的一系列接口, 这个类就代理我们那些接口中的方法。

  • 动态:指的是这个类是我们运行的时候生成的,而不是编译过程中。

下面来看看传入的参数:

  1. service.getClassLoader()

    一个classLoader

  2. new Class<?>[] {service}

    一个数组,里面包含了我们的接口

  3. new InvocationHandler(Object proxy, Method method, @Nullable Object[] arg){}

    一个监听器,我们接口实现方法的调用都要经过这个hanlder,如实例请求中的service.listRepos(),就可以理解为,我们的service经过反射 被Retrofit造成了一个ServiceProxy类,这个类具体实现了listRepos(),当我们调用listRepos()的时候,InvocationHandler会执行 invoke(),这个方法需要三个参数,proxy,为代理对象,就是Serviceproxy本身,method,既是这个方法换成java中的反射就是 GitHubService.getClass.getDeclaredMethod("listRepos",String.class),args即为参数,如例子中我的github账号。

 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.
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                args = args != null ? args : emptyArgs;
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });

if (method.getDeclaringClass() == Object.class)用来排除Object中的方法,防止接口中的Object方法参与代理,调用的时候直接执行原方法。

platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);

最后执行这部分则是一个判断,判断运行环境,使用不同的执行方法,如Java 8环境,open Jdk5 环境等。

loadServiceMethod(method).invoke(args)

  1. loadServiceMethod(method)
  ServiceMethod<?> loadServiceMethod(Method method) {
    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;
  }

这一步是从serviceMethodCache查找有无这个方法,有则直接返回,没有就创造出来就放入serviceMethodCache中,这是个缓存流程。 下面让我们看看parseAnnotations()是如何创建的。

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

这最后经过一系列判断之后,指向了HttpServiceMethod.parseAnnotations(),在进入一步,查看HttpServiceMethod.parseAnnotations的实现, 如下:

 static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    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 {
      adapterType = method.getGenericReturnType();
    }

 @Override
  final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }

HttpServiceMethod继承自ServiceMethod,是它的具体实现。首先进行了一个判断isKotlinSuspendFunction,判断它是否属于 挂起方法,是则就进行一系列协程化的处理(这部分与Retrofit的基础功能相关性不是很大,不做详细描述)。getGenericReturnType()用于返回方法 的最后return对象的类型,如方法String test(){return "test"},返回类型就为class java.lang.String,接下来看invoke()的实现, invoke()创建了一个okHttpCall对象,这其实就是Call<List<Repo>> repos = service.listRepos("yangSpica27")时,创建的Call,adpt()则将 获取的call进行了转换。

这部分获取的call,最后被我们repos.enqueue()调用后获取对象列表,这部分的内部源码可见:

@Override
  public void enqueue(final Callback<T> callback) {
    Objects.requireNonNull(callback, "callback == null");

    okhttp3.Call call;
    Throwable failure;

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;

      call = rawCall;
      failure = creationFailure;
      if (call == null && failure == null) {
        try {
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          throwIfFatal(t);
          failure = creationFailure = t;
        }
      }
    }

    if (failure != null) {
      callback.onFailure(this, failure);
      return;
    }

    if (canceled) {
      call.cancel();
    }

    call.enqueue(
        new okhttp3.Callback() {
          @Override
          public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
            Response<T> response;
            try {
              response = parseResponse(rawResponse);
            } catch (Throwable e) {
              throwIfFatal(e);
              callFailure(e);
              return;
            }

            try {
              callback.onResponse(OkHttpCall.this, response);
            } catch (Throwable t) {
              throwIfFatal(t);
              t.printStackTrace(); // TODO this is not great
            }
          }

          @Override
          public void onFailure(okhttp3.Call call, IOException e) {
            callFailure(e);
          }

          private void callFailure(Throwable e) {
            try {
              callback.onFailure(OkHttpCall.this, e);
            } catch (Throwable t) {
              throwIfFatal(t);
              t.printStackTrace(); // TODO this is not great
            }
          }
        });
  }

可见,Retrofit首先使用createRawCall()创建出了一个Okhttp3的call,然后进行请求,获取字节码序列,通过response = parseResponse(rawResponse);将字节码转化为 相应的对象后返回。