美文网首页网络
Retrofit2(v2.5.0)源码解析

Retrofit2(v2.5.0)源码解析

作者: 李晓通 | 来源:发表于2019-05-31 17:24 被阅读544次

    前言

    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完成同步或者异步的网络请求了!

    尾声

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

    相关文章

      网友评论

        本文标题:Retrofit2(v2.5.0)源码解析

        本文链接:https://www.haomeiwen.com/subject/xetutctx.html