Android源码:Retrofit源码解析

一、前言
二、源码解析
       1、构建Retrofit对象
            1.1、Retrofit类的成员变量
            1.2、Retrofit.Builder
            1.3、Builder.build()方法
       2、创建网络请求接口实例
            2.1、动态代理模式
            2.2、接口实例的创建
            2.3、创建ServiceMethod
                     2.3.1、RequestFactory.parseAnnotations解析注解
                     2.3.2、HttpServiceMethod.parseAnnotations创建ServiceMethod
            2.4、ServiceMethod.invoke()
       3、发起网络请求
三、总结

一、前言

Retrofit已经出来很久了,相信我们大家都已经知道它 内部的网络请求是通过 OkHttp 完成, 自身仅负责的是网络请求接口的封装 。 今天我们就来一起分析一下Retrofit的源码,Retrofit源码的版本为2.7.1。
retrofit的使用我们就不再做过多的介绍,就简单列一下retrofit使用的四个基本步骤,然后从这四个步骤开始分析
1.创建api接口

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

2.创建Retrofit实例

Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("https://api.github.com/")
            .build();

3.创建api的实现

GitHubService service = retrofit.create(GitHubService.class);

4.发起网络请求

Call<List<Repo>> repos = api.listRepos("test");
repos.execute()  或者 repos.enqueue()

对于这四步基本使用我们应该都知道,现在我们就按照上述过程来分析对应的源码。看源码之前,我们最好是带着问题去看,对于一些API调用链,理清思路即可,要不然很容易一头扎进源码细节出不来。 针对Retrofit我们可以像自己提出四个问题,然后带着问题去分析源码:
1.Retrofit的原理是什么
2.Retrofit 是怎么解析注解的,并把它组装成网络请求参数
3.用到了哪些设计模式呢,为什么用代理模式,代理模式的作用是什么
4.rxjava和retrofit如何结合来支持RxJava的

二、源码分析

1.构建Retrofit对象

Retrofit retrofit = new Retrofit.Builder()
   .baseUrl("https://api.github.com/")
   .build();

对于构建过程我们可以从这几个方面来分析
1.Retrofit的成员变量
2.构建Builder
3.build的过程

1.1Retrofit的成员变量

//serviceMethodCache: 缓存ServiceMethod中一些网络请求的相关配置、网络请求的方法、数据转换器和网络请求适配器等等
 private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
 // Retrofit默认使用OkHttp,callFactory实际上就是OkHttpClient
  final okhttp3.Call.Factory callFactory;
// 网络请求的url地址
 final HttpUrl baseUrl;
  // 数据转换器工厂的集合
 final List<Converter.Factory> converterFactories;
 // 网络请求适配器工厂的集合
 //在Retrofit中提供了四种CallAdapterFactory: ExecutorCallAdapterFactory(默认)、GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory
 final List<CallAdapter.Factory> callAdapterFactories;
 // 回调方法执行器 , 用来切换线程的
 final @Nullable Executor callbackExecutor;
 // 是否缓存创建的ServiceMethod
 final boolean validateEagerly;

1.2Retrofit.Builder

在Retrofit.Builder中我们可以看到 Builder 构造函数中调用了 Platform.get() ,然后赋值给自己的 platform 变量

  public static final class Builder {
   private final Platform platform;
   private @Nullable okhttp3.Call.Factory callFactory;
   private @Nullable HttpUrl baseUrl;
   private final List<Converter.Factory> converterFactories = new ArrayList<>();
   private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
   private @Nullable Executor callbackExecutor;
   private boolean validateEagerly;

   Builder(Platform platform) {
     this.platform = platform;
   }

   public Builder() {
     this(Platform.get());
   }
   
   ...

接下来我们来看看 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) {
    }
    return new Platform(true);
  }

  private final boolean hasJava8Types;

  Platform(boolean hasJava8Types) {
    this.hasJava8Types = hasJava8Types;
  }
 // 返回默认的 Executor 对象,正是 Retrofit 的成员变量回调执行器,它的内部采用 Handler 负责子线程到主线程的切换工作
  @Nullable Executor defaultCallbackExecutor() {
    return null;
  }

 //返回默认的 CallAdapter.Factory 对应Retrofit 成员变量中的网络请求适配器工厂集合callAdapterFactories
  List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
      @Nullable Executor callbackExecutor) {
    DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
    return hasJava8Types
        ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
        : singletonList(executorFactory);
  }

  //返回默认的 Converter.Factory 对应Retrofit 成员变量中的网络请求数据转换器集合converterFactories 
  List<? extends Converter.Factory> defaultConverterFactories() {
    return hasJava8Types
        ? singletonList(OptionalConverterFactory.INSTANCE)
        : emptyList();
  }
 
  static final class Android extends Platform {
    Android() {
      super(Build.VERSION.SDK_INT >= 24);
    }

    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

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

  • Platform.get() 调用了 findPlatform() 方法,然后判断如果是 Android 平台会返回一个 Android() 对象
  • Android()对象的defaultCallbackExecutor:实现了默认的Executor线程切换器,它对应着Retrofit成员变量中的callbackExecutor,我们可以看出来其内部采用 Handler 负责子线程到主线程的切换工作。
  • Android()的构造函数:判断当前sdk版本是否大于Android 7.0 ,然后赋值给父类Platfrom中的hasJava8Types属性,而Platfrom中的hasJava8Types 主要在Platfrom中2个方法中使用:
    (1) defaultCallAdapterFactories:返回的是默认的 CallAdpter.Factory 的集合,就是Retrofit 成员变量中的网络请求适配器工厂集合callAdapterFactories。
    (2) defaultConverterFactories:返回的是默认的 Converter.Factory 的集合,就是Retrofit 成员变量中的数据转换器集合converterFactories。

1.3 build的过程

public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        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.
      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);
    }

至此,Retrofit 的创建流程就完成了,build方法中配置了Retrofit类的所有成员变量,
serviceMethodService:暂时为空
callFactory:默认OkHttpClient 对象
baseUrl:根据配置的 baseUrl,构建成okhttp的HttpUrl 对象
callAdapterFactories:配置的和默认的网络请求适配器工厂集合
converterFactories:配置的和默认的数据转换器工厂集合
callbackExecutor:MainThreadExecutor 对象
validateEagerly:默认 false

2.创建网络请求接口实例

我们都知道retrofit.create() 这里利用了动态代理,通过动态代理Retrofit将一个普通的Java Interface转化为了Http请求。那么问题就来了,动态代理到底是什么呢,所以在看create源码之前,这里我们就先来简单了解一下设计模式中代理模式,这样才会有利于我们去理解源码。

2.1动态代理模式

代理模式定义:
为其他对象提供一种代理以控制这个对象的访问
代理模式的角色:
Subject:代理者与被代理者共同实现的接口,可以理解为需要代理的行为;
RealSubject:被代理者,其为具有某种特定行为的实现者;
Proxy:代理者,其会全权代理RealSubject所具有的功能,在实现其功能的基础上做一些额外的工作;
Client:客户端,客户端访问代理者与访问被代理者具有类似的效果,其无法区分访问的是代理者还是被代理者。
它的结构图下图很清晰的表示了出来


image.png

代理模式的应用最直白的就是在Spring中的面向切面编程(AOP),我们能在一个切点之前执行一些操作,在一个切点之后执行一些操作,这个切点就是一个个方法。这些方法所在类肯定就是被代理了,在代理过程中切入了一些其他操作。对于代理,根据创建代理类的时间点, 可以分为静态代理和动态代理。
静态代理:就是在编译时就已经将接口,被代理类,代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。
动态代理:代理类在程序运行时创建的代理方式被成为动态代理。

我们这里着重说一下动态代理 ,动态代理的创建其实就分为2步
第一步通过Proxy.getProxyClass创建代理类的class对象
第二步通过反射获得这个类的构造方法并传入InvocationHandler的实现从而得到代理的实例对象

然后我们看一下下面的的例子:将GitHubService转化为一个代理对象

public interface GitHubService {
     String  listRepos(String user);
}

1.通过Proxy.getProxyClass生成GitHubService 代理对象的Class对象:

 Class  mProxyClass = Proxy.getProxyClass(GitHubService.class.getClassLoader(),GitHubService.class );

2.第二步通过反射获得这个类的构造方法并传入InvocationHandler的实现类从而获取代理类的实例

GitHubService mServcieImpl = (GitHubService) mProxyClass.getConstructor(InvocationHandler.class).newInstance(new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                   String s1 = (String) args[0];
                  return "代理类统一处理:"  +s1 ;
            }
        });

第一步我们通过Proxy生成了mProxyClass ,Proxy类的getProxyClass方法就创建了一个动态代理对象。我们点进去getProxyClass可以看到它的源码中最主要的一句是Class<?> cl = getProxyClass0(loader, intfs),就是这句话创建了代理类。
这个类的产生就是整个动态代理的关键,这个类文件是缓存在java虚拟机中的, 我们利用这个方法把System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true") 将运行时生成的动态代理类mProxyClass的Class文件保存下来 我们看一下动态生成的$Proxy0里的主要内容

 public final class $Proxy0 extends Proxy implements GitHubService {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

     public final String listRepos(String var1) throws  {
        try {
            return (String)super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }
 
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("com.java.learn.GitHubService").getMethod("listRepos", Class.forName("java.lang.String"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

代码很简单,我们可以看到动态生成的代理类也实现了GitHubService接口,并且它的构造函数中传的是InvocationHandler。然后,我们看一下代理类的listRepos方法 这里的super.h 就是父类Proxy中InvocationHandler 。 而父类Proxy中InvocationHandler是从 $Proxy0的构造方法中传入。看到这是不是就明白了当我们调用代理类的listRepos方法时 就会调用InvocationHandler 对象的invoke方法并传入方法对应的Method对象和参数。而代理类的InvocationHandler 正是我们第二步中传入的InvocationHandler的实现类。这样一来我们就知道每一个动态代理类都必须要实现InvocationHandler这个接口, 然后当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler的 invoke 方法来进行调用。这就是我们动态代理的基本原理。那动态代理优势在哪呢?我们可以看一下 《深入理解Java虚拟机》一书中的描述:

image.png

2.2接口实例的创建

简单了解完了动态代理 我们再来继续来看Retrofit中create的源码 。

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

看完这里我们是不是就知道 create这里也是用的动态代理,返回的正是我们刚才所看到的$Proxy0的实例 ,说明create这里的原理就是通过动态代理生成了GitHubService代理类的Class二进制流,并且加载到虚拟机中形成代理类的Class对象,再通过反射得到代理类对象,而该代理类即实现了GitHubService,并且持有了InvocationHandler的引用。

这样 当我们开始调用时

Call<List<Repo>> repos = api.listRepos("test");

就会执行到InvocationHandler引用的对象的invoke方法。
对于invoke方法其中最主要的是下面这一句

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

我们可以从loadServiceMethod和 invoke我们分别来分析一下

2.3创建ServiceMethod

我们先来看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;
  }

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

我们可以看到loadServiceMethod 返回的是ServiceMethod对象,ServiceMethod是一个抽象类,它只有两个方法,一个是parseAnnotations(Retrofit retrofit, Method method),一个是抽象的方法invoke(), 对于ServiceMethod.parseAnnotations 方法里主要是两个方法:
RequestFactory.parseAnnotations
HttpServiceMethod.parseAnnotations 我们来分别看下这两个方法

2.3.1通过RequestFactory.parseAnnotations解析注解配置

RequestFactory.parseAnnotations 方法主要是通过 RequestFactory 解析注解配置,就是我们常用的@GET @POST @Multipart、 封装到 RequestFactory 对象中,然后将其返回。
然后我们看一下RequestFactory内部怎么实现的

Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

这里有几个重要的参数:
retrofit:retrofit实例
method:接口方法
methodAnnotations:接口方法的注解,在retrofit里一般为请求方式
parameterTypes:参数类型
parameterAnnotationsArray:参数注解数组,一个参数可能有多个注解
我们先从build()的方法开始,我把注解处理的主要代码截取了出来我们来看下

 RequestFactory build() {
     for (Annotation annotation : methodAnnotations) {
       parseMethodAnnotation(annotation);
     }
     ...
     int parameterCount = parameterAnnotationsArray.length;
     parameterHandlers = new ParameterHandler<?>[parameterCount];
     for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
       parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
     }
    ...
}

我们可以看第一段build其中主要有两个方法
解析方法上的注解parseMethodAnnotation()
解析参数中的注解parseParameter()

parseMethodAnnotation-方法注解处理

private void parseMethodAnnotation(Annotation annotation) {
    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 retrofit2.http.Headers) {
       String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
       if (headersToParse.length == 0) {
         throw methodError(method, "@Headers annotation is empty.");
       }
       headers = parseHeaders(headersToParse);
     } else if (annotation instanceof Multipart) {
       if (isFormEncoded) {
         throw methodError(method, "Only one encoding annotation is allowed.");
       }
       isMultipart = true;
     } else if (annotation instanceof FormUrlEncoded) {
       if (isMultipart) {
         throw methodError(method, "Only one encoding annotation is allowed.");
       }
       isFormEncoded = true;
     }
       ....

对于parseMethodAnnotation它的解析主要有三类
第一类开头是例如DELETE、GET、POST、HEAD这些,注解处理走的是parseHttpMethodAndPath方法
第二类是@header,执行的是parseHeaders方法
第三类就@Multipart和@FormUrlEncoded,就是改了一下标志位。
我们继续来看下parseHttpMethodAndPath方法和parseHeader方法

 private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
     ...
     // 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(method, "URL query string \"%s\" must not have replace block. "
             + "For dynamic query parameters use @Query.", queryParams);
       }
     }

     this.relativeUrl = value;
     this.relativeUrlParamNames = parsePathParameters(value);
   }

我们可以看parseHttpMethodAndPath,从名字就可以看出来,这个方法应该主要拼装当前http的请求方式(POST或GET之类)以及url的设置,这里最主要就是给relativeUrl 赋值,对应的value正是由((GET) annotation).value()这样得到的,其中有一段正则的检查,正则的完整表达式如下:{([a-zA-Z][a-zA-Z0-9_-]*)} , 我们都知道retrofit注解里是可以放{}占位符的,当下面这样?后面出现占位符就会抛出异常,也就是说?后面不允许占位符

public interface IpServiceForPath {
   @GET("{path}/getIpInfo.php?ip={ip}")
   Call<IpModel> getIpMsg(@Path("path") String path);
}

这样通过这个方法我们就得到了网络请求的相对地址,类似于{path}/getIpInfo.php这样的。里面的“{path}”是我们parseParameter中需要赋值的变量

 private Headers parseHeaders(String[] headers) {
     Headers.Builder builder = new Headers.Builder();
     for (String header : headers) {
       int colon = header.indexOf(':');
       if (colon == -1 || colon == 0 || colon == header.length() - 1) {
         throw methodError(method,
             "@Headers value must be in the form \"Name: Value\". Found: \"%s\"", header);
       }
       String headerName = header.substring(0, colon);
       String headerValue = header.substring(colon + 1).trim();
       if ("Content-Type".equalsIgnoreCase(headerName)) {
         try {
           contentType = MediaType.get(headerValue);
         } catch (IllegalArgumentException e) {
           throw methodError(method, e, "Malformed content type: %s", headerValue);
         }
       } else {
         builder.add(headerName, headerValue);
       }
     }
     return builder.build();
   }

parseHeader这个方法返回 的是OkHttp的Headers。整个方法没什么难以理解的,就是检查了下格式,然后把一个个键值对放进去而已,对于“Content-Type"做了特殊处理,根据这个type的value值设置了ServiceMethod.contentType。

parseParameter-参数注解处理
前面我们说到RequestFactory Build方法里有parseMethodAnnotation方法和parseParameter方法,接下来我们看parseParameter

   private @Nullable ParameterHandler<?> parseParameter(int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
     ParameterHandler<?> result = null;
     if (annotations != null) {
       for (Annotation annotation : annotations) {
         ParameterHandler<?> annotationAction = parseParameterAnnotation(p, parameterType, annotations, annotation);
             ...

          result = annotationAction;
      }
      ...
     return result;
 }



   @Nullable
   private ParameterHandler<?> parseParameterAnnotation(
       int p, Type type, Annotation[] annotations, Annotation annotation) {

     if (annotation instanceof Url) {
        ...
       Converter<?, String> converter = retrofit.stringConverter(type, annotations);
       return new ParameterHandler.Path<>(method, p, name, converter, path.encoded());

     } else if (annotation instanceof Query) {
        ...
       Class<?> rawParameterType = Utils.getRawType(type);
       gotQuery = true;
       if (Iterable.class.isAssignableFrom(rawParameterType)) {
        ...
         Converter<?, String> converter =
             retrofit.stringConverter(iterableType, annotations);
         return new ParameterHandler.Query<>(name, converter, encoded).iterable();
       } else if (rawParameterType.isArray()) {
         Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
         Converter<?, String> converter =
             retrofit.stringConverter(arrayComponentType, annotations);
         return new ParameterHandler.Query<>(name, converter, encoded).array();
       } else {
         Converter<?, String> converter =
             retrofit.stringConverter(type, annotations);
         return new ParameterHandler.Query<>(name, converter, encoded);
       }
      ...
     } 
     ...
}


 static final class Query<T> extends ParameterHandler<T> {
   private final String name;
   private final Converter<T, String> valueConverter;
   private final boolean encoded;

   Query(String name, Converter<T, String> valueConverter, boolean encoded) {
     this.name = Objects.requireNonNull(name, "name == null");
     this.valueConverter = valueConverter;
     this.encoded = encoded;
   }

   @Override void apply(RequestBuilder builder, @Nullable T value) throws IOException {
     if (value == null) return; // Skip null values.

     String queryValue = valueConverter.convert(value);
     if (queryValue == null) return; // Skip converted but null values

     builder.addQueryParam(name, queryValue, encoded);
   }
 }

parseParameter就是负责解析 API 定义时每个方法的参数,并在构造 HTTP 请求时设置参数,他核心逻辑是通过parseParameterAnnotation()方法解析参数注解生成ParameterHandler对象,ParameterHandler是一个抽象类,ParameterHandler的子类封装了参数的数据和数据的处理过程,例如子类ParameterHandler.Query就封装了@Query注解的参数,Retrofit 为方法中的每个参数创建一个ParameterHandler<?>对象并解析每个参数使用的注解类型。这里的注解包括:Body、PartMap、Part、FieldMap、Field、Header、QueryMap、Query、Path、Url 。我们可以看到里面有一个apply 方法,那apply 什么时候被调用呢。在我们 后面通过OkHttpCall进行同步或者异步请求时,会有一个过 createRawCall ,我们点进他的源码可以看到执行了每个参数对应的ParameterHandler的 apply 方法,赋值到RequestBuilder 然后就构造一个 Request 对象。
这基本上就是注解的处理过程

2.3.2HttpServiceMethod.parseAnnotations创建ServiceMethod

看完了ServiceMethod.parseAnnotations中的RequestFactory.parseAnnotations,我们再来看另一个地方,就是最后一句

    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);

HttpServiceMethod 的 parseAnnotations() 方法中创建了ServiceMethod,他里面有两个主要的方法就是
createCallAdapter() 生成请求适配器callAdapter
createResponseConverter() 生成响应体(Response)的数据转换器Converter


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


public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
     Annotation[] annotations) {
   Objects.requireNonNull(returnType, "returnType == null");
   Objects.requireNonNull(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);
     if (adapter != null) {
       return adapter;
     }
   }
...
}

看到这里之前我们来了解一下CallAdapter, CallAdapter 顾名思义,它就是网络请求执行器的适配器,Retrofit中默认的网络请求执行器是OkHttpCall,CallAdapter可以将OkHttpCall转换成适合被不同平台来调用的网络请求执行器形式。说到这不得不提一下适配器模式,适配器模式一句话:将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作。适配器模式简单来说,就是将一个已存在的东西转换成适合我们使用的东西。 我们常用的就是RecyclerView中的Adapter。 我们Retrofit中的CallAdapter就是将OkHttpCall转化成适合不同平台来调用
的网络执行器 。 Retrofit中用了适配器模式把OkHttpCall轻松适配到了RxJava的Observable、Android的ExecutorCallbackCall、Java8的CompletableFuture,Guava,如果以后要扩展就可以在继续适配就行,非常容易扩展。Retrofit跟据网络接口方法的返回值类型来选择具体要用哪种 CallAdapterFactory,然后获取具体的 CallAdapter。在Retrofit中有四种CallAdapterFactory: DefaultCallAdapterFactory(默认)、Java8CallAdapterFactory、RxJavaCallAdapterFactory、GuavaCallAdapterFactory
在前面的Platform我们知道Retrofit 内置了两种默认的适配器工厂:CompletableFutureCallAdapterFactory(系统版本大于等于24时生效)和DefaultCallAdapterFactory,当然我们还可以在Build的时候设置RxJava2CallAdapterFactory,这样一来retrfit也就和RxJava结合到一起,我们在这里看一下DefaultCallAdapterFactory的代码

final class DefaultCallAdapterFactory extends CallAdapter.Factory {
  private final @Nullable Executor callbackExecutor;
 
  @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>");
    }
    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);
      }
    };
  }

creatCallAdapter :看到这里我们是不是就明白了,creatCallAdapter 通过nextCallAdapter中的CallAdapter.Factory.get来得到calladapter,而DefaultCallAdapterFactory 中get方法返回的是一个新的CallAdapter实例 。在实例的adapt函数中,把Retrofit中用来访问网络的OkHttpCall,转换为一个ExecutorCallbackCall,OkHttpCall和ExecutorCallbackCall都实现了retrofit2.Call接口,结果就出现了从OkHttpCall转换为Call<Object>的情况,那么rxjava呢 同理就知道 RxJava2CallAdapterFactory把retrofit2.Call对象通过适配器转换为了一个实为Observable<?>的Object对象。这个CallAdapter的转换就比较明显了,把retrofit2.Call对象通过适配器转换为了一个实为Observable<?>的Object对象。
至此,我们可以理解Retrofit根据接口定义动态生产Call网络请求工作对象的原理了,其实就是通过适配器把retrofit2.Call对象转换为目标对象。

createResponseConverter:根据网络请求接口方法的返回值和注解类型从 Retrofit 对象中获取对应的数据转换器,和创建 CallAdapter 基本一致,遍历 Converter.Factory 集合并寻找具体的 Converter。

2.4ServiceMethod.invoke()

看完loadSerovice我们接着来看invoke()方法
ServiceMethod 是一个抽象类,invoke() 是一个抽象方法,具体实现在子类中。

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

首先 创建了一个 OkHttpCall 对象,这个 OkHttpCall 是 Retrofit 的 Call, 我们去看OkHttpCall的源码

final class OkHttpCall<T> implements Call<T> {

它实现了call接口

public interface Call<T> extends Cloneable {

  Response<T> execute() throws IOException;

  void enqueue(Callback<T> callback);

  boolean isExecuted();

  void cancel();

  boolean isCanceled();

  Call<T> clone();

  Request request();
}

和Okhttp的Call方法很像吧 然后我们去看OKhttpCall中的request()等方法的实现可以知道retrofit的网络请求其实就是OKHTTP实现的,篇幅原因这里就不在截取代码了

接下来我们继续回到invoke方法,我们来看看他的adapt() 方法
adapt() 是一个 抽象方法,他的具体实现在 HttpServiceMethod 的子类中。

image.png

我们可以看到HttpServiceMethod 有三个子类 非协程的情况是 CallAdapted, 协程的时候是 SuspendForResponse 以及 SuspendForBody 类。

CallAdapted:我们通过上面的分析知道,DefaultCallAdapterFactory,RxJava2CallAdapterFactory中的get中会创建calladapter实例,其中的adapt方法就正是把OKhttpCall转换为Call<Object>或者说为Observable<?>的Object对象。

SuspendForResponse:首先根据传递进来的 Call 构造了一个参数为 Response 的 Continuation 对象然后通过 Kotlin 实现的 awaitResponse() 方法将 call 的 enqueue 异步回调过程封装成 一个 suspend 的函数。

SuspendForBody:SuspendForBody 则是根据传递进来的 Call 构造了一个 Continuation 对象然后通过 Kotlin 实现的 await() 或 awaitNullable() 方法将 call 的 enqueue 异步回调过程封装为了一个 suspend 的函数。

3 发起网络请求

Call<List<Repo>> call= service.listRepos("octocat");

从前面我们知道Service是动态代理对象,执行listRepos他会调用到 InvocationHandler的 invoke() 方法,得到最终的 Call 对象。
我们看下Call 对象enqueue 方法
很简单,主要就是创建 OkHttp 的 Call 对象,调用 Call 的 enqueue 方法,解析返回结果,执行回调。

call.enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {

    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {

    }
});

由上一章我们知道,这里的call实际上就是ExecutorCallAdapterFactory中ExecutorCallbackCall,我们来看下ExecutorCallbackCall.enqueue()方法的代码

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

      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              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(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }

ExecutorCallbackCall有两个成员变量,callbackExecutor与delegate,通过之前的分析我们知道它们分别对应了MainThreadExecutor和OkHttpCall。MainThreadExecutor.execute()方法将OkHttpCall的请求回调结果发送至主线程, 就是创建 OkHttp 的 Call 对象,调用 Call 的 enqueue 方法,解析返回结果,执行回调

三、总结

至此,Retrofit 的源码基本上就基本上结束了,虽然还有很多细节没有提及,但整体流程应该比较清晰了。相信我们对开头我们提的问题应该也有了答案。
按照我们的分析步骤我们知道retrofit进行网络请求的主要过程
1.通过建造者模式构建一个Retrofit实例
2.通过Retrofit对象的create方法返回一个Service的动态代理对象
3.调用service的方法的时候解析接口注解(方法注解和参数注解)
4.构造ServiceMethod对象生成请求适配器callAdapter,数据转换器Converter
5.ServiceMethod对象注入到OkHttpCall,通过callAdapter将 网络请求对象 进行平台适配,默认是直接返回Call对象
6.调用Okhttp的网络请求方法,通过 回调执行器 切换线程(子线程 ->>主线程)

有不清晰或者不对的地方欢迎指正!

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