Retrofit2(v2.5.0)源码解析

前言

Retrofit这个强大的网络请求库相信每个做安卓的小伙伴们都不陌生,通过简单的构造之后,只需要在create中提供一个接口,就可以方便的跟后台做数据交互了,那么Retrofit到底是怎么实现这么强大的功能的呢?接下来我们就一探究竟,看看大名鼎鼎的Retrofit源码!

Retrofit源码目录(基于2.5.0)

首先我们能看到,Retrofit源码总共只有46个类(OMG,是不是突然觉得怎么这么少~~~),其中还包含了25个注解类,剩下21个类才是真正的源码(感觉一下子少了一半的工作量)。。。

  • 注解类

    • 请求方式注解(7个)
      • DELETE
      • GET
      • HEAD
      • OPTIONS
      • PATCH
      • POST
      • PUT
    • 方法上部注解 (5个)
      • FormUrlEncoded
      • Headers
      • HTTP
      • Multipart
      • Streaming
    • 方法参数注解 (12个)
      • Body
      • Field
      • FieldMap
      • Header
      • HeaderMap
      • Part
      • PartMap
      • Path
      • Query
      • QueryMap
      • QueryName
      • Url
    • 其他注解 (1个)
      • EverythingIsNonNull
真正要看的源码

从Retrofit使用流程来阅读源码

首先我们来看看Retrofit官方推荐的使用流程

        //首先通过Builder建造者模式拿到builder对象
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.example.com/")//设置BaseUrl
                .addConverterFactory(GsonConverterFactory.create())//添加Json的转换器
                .build();//调用build()方法得到retrofit对象

        //调用create()方法并传入我们的接口类,得到接口的对象?????
        MyApi api = retrofit.create(MyApi.class);
        //用接口的对象调用接口里面的方法?????
        Response obj = api.doSomething().execute();

其实在使用的时候,我们就应该会有疑问,问什么我传入了一个接口,Retrofit却返回给我们一个接口的实体类?

Retrofit.Builder()

首先我们从Retrofit.Builder()这个方法看起,点进去之后,我们发现,里面调用了 this(Platform.get())这个方法

public static final class Builder {
    public Builder() {
      this(Platform.get());
    }
}

我们可以看到这里调用了一个带参数的构造方法,继续往下点查看Platform.get()方法(这里贴出Platform部分代码)

class Platform {
  private static final Platform PLATFORM = findPlatform();
  
  static Platform get() {
    return PLATFORM;
  }
}

顾名思义,Platform就是平台的意思,这里get()方法返回了PLATFORM对象,而该对象又是由findPlatform()方法赋值的,继续看

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

可以看到,findPlatform()方法最终会返回Android()或者Java8()这两种平台其中一种,平台不同,处理方式也不同,比如判断是否为默认方法,创建默认的CallbackExecutor等等。这里贴出Android类(Java8也是继承自Platform)

  static class Android extends Platform {
    @IgnoreJRERequirement // Guarded by API check.
    @Override boolean isDefaultMethod(Method method) {
      if (Build.VERSION.SDK_INT < 24) {
        return false;
      }
      return method.isDefault();
    }

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

    @Override List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
        @Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      ExecutorCallAdapterFactory executorFactory = new ExecutorCallAdapterFactory(callbackExecutor);
      return Build.VERSION.SDK_INT >= 24
        ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
        : singletonList(executorFactory);
    }

    @Override int defaultCallAdapterFactoriesSize() {
      return Build.VERSION.SDK_INT >= 24 ? 2 : 1;
    }

    @Override List<? extends Converter.Factory> defaultConverterFactories() {
      return Build.VERSION.SDK_INT >= 24
          ? singletonList(OptionalConverterFactory.INSTANCE)
          : Collections.<Converter.Factory>emptyList();
    }

    @Override int defaultConverterFactoriesSize() {
      return Build.VERSION.SDK_INT >= 24 ? 1 : 0;
    }

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

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

那么看到了这里,我们的platform对象算是拿到了,回到Retrofit.Builder()方法, 通过刚才的看源码,我们知道里面的Platform.get()得到的是一个platform对象,然后又调用了自己带参数的构造方法

  public static final class Builder {
    private final Platform platform;

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

带参数的构造方法里面就是给自己的成员变量赋值操作,那么到此我们的Retrofit.Build()方法算是走完了。

通过Retrofit.Build()这一步,我们完成的事情有:
  1. 根据条件判断,得到Android或者Java8的Platform对象
  2. 把得到的Platform对象给Retrofit类里面的成员变量private final Platform platform赋值

baseUrl()方法

刚才我们的Retrofit.Builder()方法调用完成之后,下面继续调用了baseUrl("your baseUrl')这个方法,继续来看看吧!

public final class Retrofit {
    public Builder baseUrl(String baseUrl) {
      checkNotNull(baseUrl, "baseUrl == null");
      return baseUrl(HttpUrl.get(baseUrl));
}

传入baseUrl之后,首先判断了一下,是否为空,如果为空则直接抛出异常,否则调用baseUrl(HttpUrl.get(baseUrl))方法,那么我们来看一下HttpUrl.get(baseUrl)做了哪些操作吧!

public final class HttpUrl {
  public static HttpUrl get(String url) {
    return new Builder().parse(null, url).build();
  }
}

注意,这里的HttpUrl是okhttp的类,所以我们不展开太详细的介绍,大体的讲一下里面的逻辑即可,主要是看Retrofit里面的源码。可以看到,HttpUrl.get(baseUrl)方法里面,创建了一个Builder调用parse()方法来解析我们传进来的url,而这个parse()方法,主要是做了一些验证的逻辑,比如是否http或者https之类的,最终调用build()拿到了一个HttpUrl对象。然后把这个对象传到了baseUrl(HttpUrl baseUrl)这个方法里面。

public final class Retrofit {
    public Builder baseUrl(HttpUrl baseUrl) {
      checkNotNull(baseUrl, "baseUrl == null");
      List<String> pathSegments = baseUrl.pathSegments();
      if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
        throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
      }
      this.baseUrl = baseUrl;
      return this;
    }
}

大家可以看到,这里先是判断baseUrl是否为空,如果不为空,再判断baseUrl的结尾是否是以“/”结尾的,如果不是,则抛出异常!!!(所以说baseUrl必须要以/结尾,哈哈哈),如果baseUrl没问题,则给自己的baseUrl赋值。

小插曲:如果碰到需求,要求我们动态修改baseUrl的值,怎么办?

大家都知道,Retrofit其实并没有提供修改baseUrl方法的,但是在真实开发中,确实会有这样的需求,比如我们给测试打包,有个button可以一键切换debug和release地址,如果不动态修改的话,我们就只能给测试打2个包,测试还得来回安装卸载,很麻烦,既然Retrofit没有提供,我们就自己想办法去动态修改他的baseUrl吧(毕竟源码都看了,是吧!)。
传送门:如何动态修改retrofit的baseUrl www.baidu.com

addConverterFactory(GsonConverterFactory.create())

设置好了baseUrl之后,我们需要调用addConverterFactory()方法来设置一个转换器,进去瞅瞅呗。

public final class Retrofit {
    private final List<Converter.Factory> converterFactories = new ArrayList<>();

    public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }
}

还是老规矩,先做了非空判断(真TM严谨。。。),若不为空,则把我们传进来的factory对象添加到了converterFactories里面。
差点忘了看我们传进来的factory是什么了。。。,看下GsonConverterFactory.create()吧。

public final class GsonConverterFactory extends Converter.Factory {
  public static GsonConverterFactory create() {
    return create(new Gson());
  }
}

0.0 没想到吧,里面居然只是new Gson()。。。

build()

一些参数设置完了之后,终于开始调用build()方法了

    public Retrofit build() {
      //老规矩啊,先对baseUrl进行非空判断
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      //如果callFactory为空,则创建一个默认的
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

      List<Converter.Factory> converterFactories = new ArrayList<>(
          1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

      converterFactories.add(new BuiltInConverters());
      converterFactories.addAll(this.converterFactories);
      converterFactories.addAll(platform.defaultConverterFactories());

      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }
  1. 第一行,又是老规矩,对baseUrl进行非空判断。。。
  2. 拿到自己的callFactory对象,如果callFactory为空,则创建一个默认的OkHttpClient()对象,里面设置了默认的读写时间等等
  3. 拿到callbackExecutor对象,如果为空,则创建一个默认的platform.defaultCallbackExecutor()对象
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }
}

new了一个MainThreadExecutor对象

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

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

可以看到,里面其实就是创建一个Handler对象,并且传入了Looper.getMainLooper()。所以下面的execute()方法是执行在主线程。

  1. 剩下的基本就是创建集合,然后往里面添加数据,最后调用Retrofit带参数的构造方法,里面主要就是给变量赋值,看看就好!
  Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
      List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories,
      @Nullable Executor callbackExecutor, boolean validateEagerly) {
    this.callFactory = callFactory;
    this.baseUrl = baseUrl;
    this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
    this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
    this.callbackExecutor = callbackExecutor;
    this.validateEagerly = validateEagerly;
  }

那么到此为止,我们的retrofit对象算是成功创建出来了,虽然我们调用起来只写了短短几行代码,但是Retrofit内部却做了一大堆操作,这里其实就用到了好几种设计模式,比如Builder模式,外观模式,Factory模式。

create(Api.class) —— 重头戏来了

通过上面的一系列设置,最终我们得到了retrofit对象,按照官方文档的步骤,我们接下来要调用create()方法,这个create()方法到底做了什么,为什么我们传进去的接口类会返回给我们一个接口的实体类?这些问题我们一步一步揭晓!

  public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    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 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);
          }
        });
  }

首先映入我们眼帘的,就是一个Retrofit的常规操作,检查。。。没错,Utils.validateServiceInterface(service)这个方法就是为了检查我们传进来的类是否为接口
,如果不是,则抛异常!

  static <T> void validateServiceInterface(Class<T> service) {
    if (!service.isInterface()) {
      throw new IllegalArgumentException("API declarations must be interfaces.");
    }
    if (service.getInterfaces().length > 0) {
      throw new IllegalArgumentException("API interfaces must not extend other interfaces.");
    }
  }

可能有小伙伴就会问,为什么必须传接口?传一个其他的类不行吗?对于这个问题,就要涉及到Java的动态代理模式了,因为Java的动态代理模式,只允许传入接口,不允许传入别的类,感兴趣的小伙伴可以自行研究。

动态代理模式

接下来,因为我们的validateEagerly默认是false,所以eagerlyValidateMethods(service)没有被调用,我们直接来看Proxy.newProxyInstance动态代理。

 public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,
                                          InvocationHandler h) throws IllegalArgumentException{
        Objects.requireNonNull(h);
        final Class<?>[] intfs = interfaces.clone();
        Class<?> cl = getProxyClass0(loader, intfs);
        try {
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                cons.setAccessible(true);
            }
            return cons.newInstance(new Object[]{h});
        } 
    }

为了简洁,我把catch的代码直接删了,主要是看newProxyInstance的操作,首先我们要知道的是Proxy这个类并不是Retrofit里面的,而是我们java.lang.reflect下面的类,正是因为有Proxy,我们才得以使用接口的对象调用我们接口里面的方法。

  1. 首先调用了非空判断,检查我们传入的InvocationHandler对象是否为空。
  2. 把我们传进来的接口数组clone一份(数组里面其实就只有我们传进来的一个接口类)。
  3. 通过getProxyClass0方法拿到Class的对象cl
  4. 通过cl拿到构造方法,并且重新创建了一个类,参数是一个Object[],里面放有我们传进来的InvocationHandler对象。

看到了这里,我们肯定很好奇,由Proxy创建的类到底长什么样子?既然如此,我们不妨打印出来看看,这个类到底是何方神圣!
首先我们创建一个普通的接口类

interface ApiService {
     void dosomething();
}

然后经过Proxy一系列操作之后我们打印出来看看


public final class ApiService extends Proxy implements com.example.demo.ApiService {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public ApiService(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void dosomething() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.example.demo.ApiService").getMethod("dosomething");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

你没有看错,直接生成了一个类,而且还自动extends Proxy并实现了你的接口,所以这就是为什么动态代理模式只能传入接口。在生成的这个类里面,我们可以清楚地看到里面有dosomething这个方法(所以说,我们拿到的接口对象其实就是这个类的对象)

到此为止,我们最重要的一个环节,根据我们传的接口类,创建了一个新的类,并且把这个类的对象返回给我们。

调用请求的方法

完成了一系列的配置之后,终于开始了我们的网络请求,Retrofit到底是如何帮我们实现网络请求的呢?我们继续往下看。

public interface ApiService {
    @GET("url")
    Call<String> dosomething();
}
api.dosomething();

我们先定义一下正常的get请求并发送该请求,通过断点,我们可以看到,发送请求时,直接进入了我们的Proxy里面的InvocationHandler里面(想想也正常,毕竟创建新类的时候,传入了InvocationHandler的对象)

  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 {
            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时传进去的,只不过里面的invoke方法是在用户发送请求的时候才会被调用,原因就不用我讲了吧,直接看动态代理生成的类就明白了。

  1. 首先通过method.getDeclaringClass()检查了一下,是否为Object的方法,显然这里不是,往下走
  2. 通过platform.isDefaultMethod(method)判断是否为平台的默认方法,显然也不是
  3. 最终调用loadServiceMethod(method).invoke(args != null ? args : emptyArgs)

我们先来看loadServiceMethod(method)

public final class Retrofit {
  private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();

  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;
  }
}
  1. 首先使用serviceMethodCache.get去取,得到一个ServiceMethod对象result,如果不为空,直接把result返回
  2. 如果result为空,就调用ServiceMethod.parseAnnotations(this, method)方法
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);
  }
}

第一行就调用了RequestFactory.parseAnnotations(retrofit, method),好吧,点进去看看

final class RequestFactory {
  static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    return new Builder(retrofit, method).build();
  }
}

又调用new Builder(retrofit, method),继续

final class 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对象,方法上的注解之类的。。。没啥好说的,继续看build()方法

    RequestFactory build() {
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }

      if (httpMethod == null) {
        throw methodError(method, "HTTP method annotation is required (e.g., @GET, @POST, etc.).");
      }

      if (!hasBody) {
        if (isMultipart) {
          throw methodError(method,
              "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
        }
        if (isFormEncoded) {
          throw methodError(method, "FormUrlEncoded can only be specified on HTTP methods with "
              + "request body (e.g., @POST).");
        }
      }

      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]);
      }

      if (relativeUrl == null && !gotUrl) {
        throw methodError(method, "Missing either @%s URL or @Url parameter.", httpMethod);
      }
      if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
        throw methodError(method, "Non-body HTTP method cannot contain @Body.");
      }
      if (isFormEncoded && !gotField) {
        throw methodError(method, "Form-encoded method must contain at least one @Field.");
      }
      if (isMultipart && !gotPart) {
        throw methodError(method, "Multipart method must contain at least one @Part.");
      }

      return new RequestFactory(this);
    }

build()方法

1. 首先对methodAnnotations这个注解数组进行了遍历,并且调用parseMethodAnnotation方法对每一个annotation进行解析
    private void parseMethodAnnotation(Annotation annotation) {
      if (annotation instanceof GET) {
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
      } else if (annotation instanceof HEAD) {
        parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
      } 
      ...
    }

这里我删除了部分代码,因为里面都是if else判断,主要就是看你的注解是属于那一个,小伙伴们可以自行打开源码对比就好,以GET为例,如果是GET,这里直接调用parseHttpMethodAndPath("GET", ((GET) annotation).value(), false)方法。

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

      if (value.isEmpty()) {
        return;
      }

      // 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);
    }
  1. 非空判断,然后就是把我们传进来的参数给httpMethod,hasBody赋值
  2. 判断我们传进来的参数是否包含"?",如果包含,Retrofit就会帮你做一些拼接处理
  3. 然后给relativeUrl赋值
  4. relativeUrlParamNames赋值

到这里我们的parseMethodAnnotation方法调用完成,注解解析完毕'

2. 对httpMethod,是否含有body,是否为表单数据等进行一系列判断
3.返回了一个RequestFactory对象
  RequestFactory(Builder builder) {
    method = builder.method;
    baseUrl = builder.retrofit.baseUrl;
    httpMethod = builder.httpMethod;
    relativeUrl = builder.relativeUrl;
    headers = builder.headers;
    contentType = builder.contentType;
    hasBody = builder.hasBody;
    isFormEncoded = builder.isFormEncoded;
    isMultipart = builder.isMultipart;
    parameterHandlers = builder.parameterHandlers;
  }

又是一系列赋值操作,直接跳过。到此为止我们的RequestFactory对象创建完毕。
回过头来我们再来看ServiceMethod这个类里面parseAnnotations下面的操作,通过
method.getGenericReturnType()拿到我们的返回值,然后调用了HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory)方法。

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

    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

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

这里首先通过createCallAdapter()方法,拿到了我们的callAdapter对象,然后通过callAdapter.responseType()拿到了返回值类型,经过一系列判断之后,调用createResponseConverter(retrofit, method, responseType)方法,得到了一个返回值的转换器,然后使用new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter)得到我们的HttpServiceMethod对象并返回回去,也就是给我们上面的result赋值。并且把该方法,放入到serviceMethodCache缓存中。

invoke方法

通过上面的步骤,我们终于拿到了ServiceMethod对象,并且开始真正调用方法

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

这里使用的是callAdapter.adapt方法,因为CallAdapter是接口,所以自然会有实现类,又因为我们使用的是系统默认提供的的,所以这里会调用DefaultCallAdapterFactory的adapt方法

      @Override public Call<Object> adapt(Call<Object> call) {
        return call;
      }

通过adapt方法,最终拿到了我们定义的Call对象!然后就是通过call调用enqueue或者execute完成同步或者异步的网络请求了!

尾声

第一次写这种源码解析的文章,着实感觉写出来要比自己懂难得太多了。。。不管怎么样,文章算是写出来了,希望本篇文章能对大家有所帮助吧!今后也会慢慢去写其他优秀框架的源码解读,学习学习大神们都是如何写代码的~
如果觉得文章不错,可以赞赏关注收藏哦~~~

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