<源码系列> Retrofit之二:源码分析

说明:
本文的源码分析较为粗浅,和其他源码“解析”的文章相比并未特别详细,个人觉得看别人的源码,将整体的思路和大框架了解了,理解了其思想原理足矣

很重要的一点:
一定要带着质疑别人所谓的的“解析”去分析,一定要结合源码有自己的理解,不能完全相信他人的观点,即便是所谓的“大神”,人,总有犯错的时候。

如果文中有哪里不对的地方,请多指教。

从调用的流程开始分析

流程

一、Retrofit的初始化

    // 初始化配置Retrofit
    retrofit = new Retrofit.Builder()
            .baseUrl(AppConfig.BASE_URL)
            //可设置自定义的client
            .client(getOkHttpClient())
            //可设置自定义的执行类CallAdapterFactory,可多个
            .addCallAdapterFactory(new CustCallAdapterFactory())
            //可设置自定义的解析类ConverterFactory,可多个
            .addConverterFactory(new CustConvertFactory())
            .build();

   private OkHttpClient getOkHttpClient() {
      if (okHttpClient == null) {
         okHttpClient = new OkHttpClient().newBuilder()
               .connectTimeout(15 * 1000, TimeUnit.MILLISECONDS)
               .readTimeout(15 * 1000, TimeUnit.MILLISECONDS)
               .retryOnConnectionFailure(true)
               .addInterceptor(xxxInterceptor)
               .build();
      }
      return okHttpClient;
   }
  • 这里对Retrofit进行初始化,是通过构造者模式进行构建相关的参数数据
  • addConverterFactory:为对象的序列化和反序列化添加转换器工厂
  • addCallAdapterFactory:添加调用适配器工厂以支持除Call之外的服务方法返回类型

1、baseUrl:

  • baseUrl的方法有多个重载,最终通过构造HttpUrl传入,一直传递给okhttp3.Request

    public Builder baseUrl(HttpUrl baseUrl)  //最终的调用
    public Builder baseUrl(String baseUrl)
    
    Request build() {
      HttpUrl url;
      HttpUrl.Builder urlBuilder = this.urlBuilder;
      if (urlBuilder != null) {
        url = urlBuilder.build();
      } else {
        // No query parameters triggered builder creation, just combine the relative URL and base URL.
        url = baseUrl.resolve(relativeUrl);
        if (url == null) {
          throw new IllegalArgumentException(
              "Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl);
        }
      }
      //省略好多...
      return requestBuilder
          .url(url)
          .method(method, body)
          .build();
    }
    
  • 如何动态切换Retrofit的BaseURL?
    Retrofit中接收的baseUrl(String),最终是作为HttpUrl(okhttp3包里的)的类型参数传入的,在HttpUrl中有个host的字段,可以通过反射进行修改

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

二、Retrofit的请求和响应

    // ① 获取接口实现
    GitHubService service = retrofit.create(GitHubService.class);
    
    // ② 调用(下面同步或异步请求选其一)
    Call> repos = service.listRepos("octocat");
    
    // ③ 同步请求
    Response res = repos.execute();
    
    // ③ 异步请求
    repos.enqueue(new Callback() {
        @Override
        public void onResponse(Call call, Response response) {
            try {
                System.out.println(response.body().string());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public void onFailure(Call call, Throwable t) {
            t.printStackTrace();
        }
    });

    // 或者通过使用Observable,需要在初始化时进行配置:
    // addCallAdapterFactory(RxJava3CallAdapterFactory.createSynchronous())
   Observable call = mRetrofit.create(GitHubService.class).getUserData();
   call.subsribe(Xxx)

1、接口的实现类:

Retrofit 的示例来看,只需要一个接口及接口方法即可,调用者无需实现接口的具体实现类,就可以调用其内的方法,接口的实现类是从哪来的呢?
通过Retrofit#create 方法获得了接口的实现类,其内部是通过 动态代理(模式) Proxy.newProxyInstance 来实现的:

  public  T create(final Class 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)  //对default方法进行判断
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }
  • 动态代理Proxy.newProxyInstance 的参数和返回结果:

    • classLoader[参数]:类加载器会产生新类(实现的是传入的接口)
    • class[][参数]:新类实现的接口,传进来(放到数组中)
    • invocationHandler 接口[参数]:执行方法体
    • T[返回值]:一个封装了请求参数的接口的类,来发起网络请求
      通过字节码(或打印其getClass())可得出类似于:class com.sun.proxy.$Proxy0
  • 获取(动态代理)接口的实例对象
    Proxy中,通过newProxyInstance获取对象时,其中维护了一个代理类的缓存集合proxyClassCache【是WeakCache,其内部通过ConcurrentMap进行实际的缓存】,从此缓存中获取生成的接口实现类。
    而实现类的创建,是通过其固定的名称组装的类名:

     //Proxy中:
     //固定规则
     if (proxyPkg == null) {
        // if no non-public proxy interfaces, use com.sun.proxy package
        proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";  //com.sun.proxy
     }
     String proxyName = proxyPkg + proxyClassNamePrefix + num;
    
     byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
     try {
         //这里返回结果,加载byte[]来获取对象
         return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
     } catch (ClassFormatError e) {
         throw new IllegalArgumentException(e.toString());
     }
    
  • InvocationHandler#invoke 内部解析:
    1】Retrofit#loadServiceMethod
    在每次调用请求接口方法的时候,每次都会通过调用invocationHandler 中的loadServiceMethod 方法,
    loadServiceMethod方法内部,会解析得到具体的接口方法的实现(如例子中的listRepos),进行调用invoke(args) 执行方法,发起网络请求。
    2】platform.isDefaultMethod(method)
    invocationHandler 中对default 方法进行了判断。如果是默认方法则对默认方法进行调用
    default 是Java8的特性,在接口中可定义一些默认的方法:

     interface GithubApi {
          //默认方法
         default void hello() {
           //do something...
         }
     }
    

注:其中loadServiceMethod返回的类型是ServiceMethod ,其具体实现类为HttpServiceMethod。(似乎在之前的版本,2.2.0吧,ServiceMethodfinal 的,没有实现类。)

2、解析并装配参数(Okhttp请求)

在发送请求的时候,需要传入一些参数,对于Retrofit ,其请求的参数是放到注解上的,那它是如何对其进行解析的呢?是通过loadServiceMethod 方法内部对接口方法的注解及参数的解析而得。

  • Retrofit#loadServiceMethod
    loadServiceMethod 方法中,通过传入的Method类型的参数来封装成ServiceMethod 对象。
    获取具体的ServiceMethod对象流程(复用):
    1】先从serviceMethodCache 缓存集合(ConcurrentHashMap)中根据Method取出ServiceMethod对象,有则直接返回
    2】若无,加锁,通过ServiceMethod#parseAnnotations解析方法的注解信息,创建对应的接口方法的实现;
    并缓存到集合中
  • ConcurrentHashMap是个线程安全的集合(数组 + 链表 + 红黑树),因为网络请求都是在线程中去做的
  • ServiceMethod 对象(具体实现为HttpServiceMethod)中封装了各种解析工厂类等请求和响应的数据类信息(CallAdapterConverter 等等)。
  • ServiceMethod#parseAnnotations
    1】通过RequestFactory获取接口方法(如listRepos方法)上的注解和参数等信息
    如:baseUrlheaders等等
    2】获取返回值的泛型参数类型:
    method.getGenericReturnType()
    3】最后返回具体的注解信息结果:
    HttpServiceMethod.parseAnnotations
    通过HttpServiceMethodServiceMethod的实现类)进行 返回值包装类返回值类的处理。

  • HttpServiceMethod#parseAnnotations
    1】通过HttpServiceMethod#createCallAdapter 得到CallAdapter对象,方法内部根据参数进行匹配而得
    2】通过createResponseConverter得到Converter对象,方法内部根据参数匹配而得
    3】通过CallAdapterConverter等对象构造出HttpServiceMethod具体实现的子类对象并返回
    ① 若不是kotlin协程的方法,则返回CallAdapted对象
    ② 否则返回协程方法相关的对象实例:SuspendForResponseSuspendForBody

  • ServiceMethod#invoke(args)
    执行接口方法的调用,进而发起网络请求
    invokeServiceMethod的抽象方法,由其直接子类HttpServiceMethod实现

  • HttpServiceMethod.invoke(args)
    1】实现了父类ServiceMethod的方法
    2】创建Call对象
    Call call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    3】在实现的invoke方法中,又转交给HttpServiceMethod.adapt的抽象方法去完成的

  • HttpServiceMethod.adapt
    适配数据类型,并执行网络请求。
    1】具体如何将Call转换为指定的返回值包装类的,最终是交给实现了HttpServiceMethod的子类去完成的。
    2】如在CallAdapted中,其adapt方法是直接交由传入的CallAdapter的实现类来处理的
    在使用的例子中是RxJava3CallAdapterFactory内的具体实现RxJava3CallAdapter

3、“处理器”工厂:

这里我将类型适配器CallAdapter和解析转换器Converter称之为处理器,两者都用了 抽象工厂模式
CallAdapter:是对响应的数据进行转换,由T类型转换为R类型,这里用了 适配器模式
Converter:是对请求数据和响应结果进行处理的数据类型转换的处理类。

  • CallAdapter
    1】Retrofit中定义了接口CallAdapter,并由具体的子类实现如下方法:
    Type responseType();:返回具体的内部类型,如UserBean
    T adapt(Call call);:用于将retrofit2.Call转换为 返回值包装类,如Observable,并执行请求
    2】Retrofit默认只支持retrofit2.Call作为接口方法的 返回值包装类
    可通过实现CallAdapter接口进行扩展Call,适配器的添加是通过在初始化Retrofit时配置的:
    Retrofit.Builder.addCallAdapterFactory方法,可加多个适配器来转换 返回值包装类
    如可设置RxJava2CallAdapterFactory的Adapter
    3】而真正使用的只有一个,在Retrofit#nextCallAdapter中处理了相关逻辑
    根据类型和注解的相关信息,循环List 进行匹配,
    根据returnTypeType)、annotationsAnnotation[])等信息,匹配到了适配器(即返回结果不为null),则终止循环,直接返回这个factory。
    public interface CallAdapter {
    
      Type responseType();
    
      T adapt(Call call);
    }
    
  • Converter
    1】Retrofit 中定义了接口Converter,并由具体的子类实现convert方法:
    T convert(F value):即从FT(数据Bean)之间的转换操作。(多是处理POST请求)
    F 一般是RequestBody(请求体)或是ResponseBody (响应体),而T 是通过convert 方法返回的转换类型(如UserBean)。
    2】Retrofit提供了addConverterFactory方法,来配置添加转换实体的工厂对象,可加多个
    ① 在请求的时候,通过Retrofit#requestBodyConverter 方法(在构建RequestFactory中调用的)获取指定的 请求 数据解析器。
    ② 通过Retrofit#responseBodyConverter 方法(在HttpServiceMethod#createResponseConverter中获得的)获取指定的 响应 数据解析器。
    3】在HttpServiceMethod#parseAnnotations方法中调用了HttpServiceMethod#createResponseConverter
    并在其内部获取到匹配的转换器,实际调用了Retrofit#responseBodyConverter方法
    4】在获取响应结果的转换器Retrofit#responseBodyConverter(实际调用了nextResponseBodyConverter方法)中,会循环遍历converterFactories转换器集合(addConverterFactory方法添加)
    直到根据typeType)、annotationsAnnotation[])等信息,匹配到转换器(即返回结果不为null),则终止循环,直接返回这个factory。
    public interface Converter {
      T convert(F value) throws IOException;
    }
    

4、请求的发起OkHttpCall

Retrofit 中真正发起网络请求的,最终还是通过的OkHttp,所以要创建OkHttpCall

  • OkHttpCall对象的创建:
    HttpServiceMethod.invoke(args)的方法中,创建了OkHttpCall对象
    并将其实例传给了抽象方法adapt,是由子类决定如何通过OkHttp的实例发起网络请求

     @Override
     final @Nullable ReturnT invoke(Object[] args) {
       Call call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
       return adapt(call, args);
     }
    
  • OkHttpCall#getRawCall -> createRawCall
    在方法中,创建了真正的请求调用对象,并传入了请求的相关信息
    返回的Call实例,是OkHttp中的请求对象,所以具体的请求还是由OkHttp完成的。

      private okhttp3.Call createRawCall() throws IOException {
        okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
        if (call == null) {
          throw new NullPointerException("Call.Factory returned null.");
        }
        return call;
      }
    
  • OkHttpCall#enqueue / execute方法:
    1】OkHttpCall类中是具体发起请求的地方,即重写的enqueue / execute方法
    2】在接口(GitHubService)中定义的方法(listRepos)的返回类型Call ,这里的Call 实际上就是OkHttpCall类型
    3】当调用call.enqueue(Callback)时,enqueue就是OkHttpCall中的具体实现,而Callback(retrofit2.Callback)会在okhttp3.Callback回调时进行转换。
    4】HttpServiceMethod的子类实现的adapt方法中,根据传入的Call,又调用了其enqueue来执行请求的异步任务。

5、结果返回类型

例子中的Call> 是如何返回的呢?

  • 类型说明
    首先先明确一下,Retrofit中如何对这个返回类型中的各个部分定义的:

    • returnType:接口方法中的 返回值类型,如Call>
    • rawType:接口方法中的 返回值包装类,如Call
    • responseType:接口方法中返回的数据Bean类型,如List
  • 创建对象后的类型返回
    1】ReturnT invoke
    上面1中说到,请求的方法通过invoke方法来调用的,那返回类型就从这里入手,
    invoke 是在ServiceMethod 中定义的,具体实现在HttpServiceMethodinvoke中(之前ServiceMethod无实现类的时候,代码直接写在Retrofit 中来实现的),
    HttpServiceMethod#invoke 中又包了一层了adapt 抽象方法,adapt定义的返回值的类型ReturnT 就是接口方法的返回类型(如Call>

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

    2】ReturnT adapt(Call call, Object[] args)
    adapt 方法的具体实现类是CallAdapted(非kotlin协程),就在HttpServiceMethod 中,是个内部类。此方法是通过CallAdapter 来实现的,它其中的adapt 方法就是一个类型转换器,具体后面介绍。

     @Override
     protected ReturnT adapt(Call call, Object[] args) {
       return callAdapter.adapt(call);
     }
    

    3】CallAdapter 的具体实现有很多,其中有个最原始的支持:DefaultCallAdapterFactory
    此类中直接创建的匿名内部类CallAdapter的实现没有具体转换,只转成了最基本的Call 类型,是因为要将线程中的请求结果,发送到主线程中,这其中就将Handler的消息发送包装了起来:

      return new CallAdapter>() {
        @Override
        public Type responseType() {
          return responseType;
        }
    
        @Override
        public Call adapt(Call call) {
          return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
        }
      };
      
      
  • 泛型类型的处理
    DefaultCallAdapterFactory 中,对相关的泛型参数类型进行了处理:

    @Override
    public @Nullable CallAdapter get(
        Type returnType, Annotation[] annotations, Retrofit retrofit) {
      if (getRawType(returnType) != Call.class) {
        return null;
      }
      if (!(returnType instanceof ParameterizedType)) {
        throw new IllegalArgumentException(
            "Call return type must be parameterized as Call or Call");
      }
      final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
    

    1】先判断rawTypeCall,在DefaultCallAdapterFactory 的只对Call 类型处理
    2】然后判断其中是否有泛型参数(即returnType[如Call>] 是否是参数化类型ParameterizedType
    3】再从参数化类型中取出泛型实参(responseType [如List]),这里取的上限(Call)的第一个(有可能有多个泛型实参)。

  • 如何处理非原始支持的类型,如kotlin的Deffered
    同样的,也是需要实现CallAdapter 来具体的进行转换返回相应的类型。

  • 6、如何获取返回结果的泛型实参

    问题:java泛型有类型擦除,那是如何在运行时获得XxxBean(如List)的呢?

    上面说到,在获取returnType 之后,判断是否为泛型参数类型(ParameterizedType),
    然后再通过CallAdapter中的getParameterUpperBound (取类型的上限)

     //Factory中
     protected static Type getParameterUpperBound(int index, ParameterizedType type) {
       return Utils.getParameterUpperBound(index, type);
     }
     
     //Utils中
     static Type getParameterUpperBound(int index, ParameterizedType type) {
         //types即为 中的 Xxx, Yyy, ...这一数组
         //获取泛型实参,主要在这里:getActualTypeArguments
         Type[] types = type.getActualTypeArguments();
         if (index < 0 || index >= types.length) {
           throw new IllegalArgumentException(
               "Index " + index + " not in range [0," + types.length + ") for " + type);
         }
         Type paramType = types[index];
         //对通配符的判断
         if (paramType instanceof WildcardType) {
           return ((WildcardType) paramType).getUpperBounds()[0];
         }
         return paramType;
     }
    

    如果需要获取泛型类型,就要在混淆的时候,保留相关的方法处理,不能进行混淆。
    若混淆了,生成的如下面的字节码上的注释都会被干掉,因此这些泛型类型都会被去掉,就无法获取到了。

    • 原始代码:
       public static Map, Set>> test(Map>> map) {
           return null;
       }
      
    • 编译后的字节码:
      // access flags 0x9
      // signature (Ljava/util/Map;>;>;)Ljava/util/Map;Ljava/util/Set;>;>;
      // declaration: java.util.Map, java.util.Set>> test(java.util.Map>>)
      public static test(Ljava/util/Map;)Ljava/util/Map;
      

    泛型擦除是一个无奈之举,因为在java1.5出现泛型之前的1.4版本及之前的版本,已经使用的很广泛了,为了兼容之前的代码程序。
    C#是将泛型作为一个真实的类型存在,没有泛型擦除的问题。

    7、Retrofit中的kotlin协程

    • 使用:可直接返回实体Bean,而不需要任何包装类
        interface GitHubService {
        
            @GET("getUserData")
            suspend fun getUserData(): UserBean
        
        }
    
        data class UserBean(val userName: String, val userAge: Long)
    
        val retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
        val service = retrofit.create(GitHubService::class.java)
        val job: Job = launch {
           try {
               val userBean: UserBean = service.getUserData()
               println("userBean: $userBean")
           } catch (e: Throwable) {
               println("onFailure: $e")
           }
        }
    
    
    • 内部解析
      1】Retrofit是以Java语言实现的,而suspend 挂起函数只能用于ktolin,不过都会编译为JVM语言
      通过将接口ApiService 反编译得到的Java类,结果如下:

       public interface ApiService {
          @GET("getUserData")
          @Nullable
          Object getUserData1(@NotNull Continuation var1);
       }
      

      2】在RequestFactory中包含一个isKotlinSuspendFunction的成员,用来标记当前解析的Method是否为suspend函数。
      isKotlinSuspendFunction的值,是在RequestFactory#build方法中跟进方法参数的最后一个是否为Continuation.class来判定的。

      3】在处理方法的解析中,HttpServiceMethod#parseAnnotations内,根据isKotlinSuspendFunction来处理kotlin协程的接口方法的解析结果
      如果是,则返回SuspendForResponse(得到Response对象)或SuspendForBody(得到数据Bean对象,如UserBean)对象,皆为HttpServiceMethod 的子类

      4】SuspendForBody实现的adapt方法中,
      将接口方法(getUserData)最后一个参数强转为Continuation
      最终会调用KotlinExtensions.await这个kotlin扩展方法

      5】KotlinExtensions.await方法中,
      suspendCancellableCoroutine 支持cancel的CoroutineScope 为作用域,依旧以Call.enqueue发起OkHttp 请求,得到responseBody 后将其回调出去。

    8、Retrofit在Android中的支持

    支持主要在两方面:
    ① 是否支持 Java8,根据Android上是否启用 Java 8来判断,(Gradle中配置)
    ② 实现UI线程回调的Executor,将回调结果切到UI线程

    • 是否为Android平台的判断:
      根据虚拟机的名称来判断,其中定义的Android 类,是Platform的唯一子类
      private static Platform findPlatform() {
        //根据 JVM 名字来判断使用方是否是 Android 平台
        return "Dalvik".equals(System.getProperty("java.vm.name"))
            ? new Android()
            : new Platform(true);
      }
    
    • 是否支持Java 8
      通过Platform中的hasJava8Types成员来判断,在Platform#Android类中,是通过构造方法传入的条件判断的:
        Android() {
          super(Build.VERSION.SDK_INT >= 24);
        }
    
    • UI线程的回调实现:
      1】在Platform#Android中,重写了defaultCallbackExecutor方法,
      返回了创建的MainThreadExecutor对象,其中通过Handler实现了将执行任务Runnable转发到UI线程的逻辑

       static final class MainThreadExecutor implements Executor {
         private final Handler handler = new Handler(Looper.getMainLooper());
      
         @Override
         public void execute(Runnable r) {
           handler.post(r);
         }
       }
      

      2】上面说到的CallAdapter.Factory ,是用于处理接口返回值包装类(如Observable)的适配器,在Retrofit#build的时候,会将DefaultCallAdapterFactory添加进去。而DefaultCallAdapterFactory 中就是处理对应的线程切换的操作。

      3】DefaultCallAdapterFactory#get方法返回的CallAdapter对象,就是包装了ExecutorCallbackCall(实现了Call接口)对象,即具体实现了执行请求的ExecutorCallbackCall#enqueue方法,在此方法中,进行了任务的执行:

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

    9、如何支持RxJava

    • 在构建Retrofit时,通过添加CallAdapterFactory

        retrofit = new Retrofit.Builder()
                   .client(OKHttpFactory.INSTANCE.getOkHttpClient())
                   .baseUrl(AppConfig.BASE_URL)
                   .addConverterFactory(GsonConverterFactory.create())
                   //看这里
                   .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                   .build();
      
    • RxJava2CallAdapterFactory内部实现:
      RxJava2CallAdapterFactory中对返回值类型进行一系列操作,处理泛型参数等,并处理返回
      其中的returnType 就是ObservableXxxBean 就是自己定义的需要解析的类型),拿到returnType 之后,获取rawType 并进行一系列判断,判断各种RxJava 中定义的类型,最终将Obervable的这种rawType 类型进行处理,然后在对泛型参数类型(即Observable 尖括号中的泛型类型)进行获取并处理,最终进行相关赋值,并返回CallAdapter

    • 还支持Observable>
      请求的时候,具体实现为BodyObservable 的类型返回,真正实现adapt 的相关工作

       Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
       Class rawObservableType = getRawType(observableType);
       if (rawObservableType == Response.class) {
         if (!(observableType instanceof ParameterizedType)) {
           throw new IllegalStateException(
               "Response must be parameterized" + " as Response or Response");
         }
         responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
       } else if (rawObservableType == Result.class) {
         if (!(observableType instanceof ParameterizedType)) {
           throw new IllegalStateException(
               "Result must be parameterized" + " as Result or Result");
         }
         responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
         isResult = true;
       } else {
         responseType = observableType;
         isBody = true;
       }
      
       return new RxJava2CallAdapter(
           responseType, scheduler, isAsync, isResult, isBody, isFlowable, isSingle, isMaybe, false);
      }
      

    10、如何在反序列化时实例化对象

    具体处理类是GsonConverterFactory
    其中在处理request请求和response响应时,通过 gson.getAdapter 来返回TypeAdapter ,并传入 GsonRequestBodyConverterGsonResponseBodyConverter 构造来处理解析的数据。在 TypeAdapterFactory 获取的TypeAdapter 实现的,一般是ReflectiveTypeAdapterFactory ,而ObjectTypeAdapter 中的read 方法是对基本数据类型进行处理解析。
    具体的实例化是,在 Gson 构造函数中,创建了一个ConstructorConstructor 构造器的构造器,接收一个instanceCreators(调用者传进来的):

    Gson(final Excluder excluder, final FieldNamingStrategy fieldNamingStrategy, final Map> instanceCreators,
          ..., ...//省略好多入参....
        ) {
        //省略好多....
        this.constructorConstructor = new ConstructorConstructor(instanceCreators);
        //省略好多....
    }
    

    ConstructorConstructor 中对对象的构造做了很多流程判断(如图),判断了是否有无参构造(通过newDefaultConstructor)
    终极方案就是使用newUnsafeAllocator 中的native 方法来开辟对象内存空间:

    public native Object allocateInstance(Class var1) throws InstantiationException;
    

    在终极方案中,进行实例化对象:

    private  ObjectConstructor newUnsafeAllocator(
          final Type type, final Class rawType) {
        return new ObjectConstructor() {
          private final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create();
          @SuppressWarnings("unchecked")
          @Override public T construct() {
            try {
               //看这里
              Object newInstance = unsafeAllocator.newInstance(rawType);
              return (T) newInstance;
            } catch (Exception e) {
              throw new RuntimeException(("Unable to invoke no-args constructor for " + type + ". "
                  + "Registering an InstanceCreator with Gson for this type may fix this problem."), e);
            }
          }
        };
      }
    

    最终实例化了对象,实例化的时机,是在read的时候:

    //ReflectiveTypeAdapterFactory <-- 大多数都是这个factory
    public static final class Adapter extends TypeAdapter {
        private final ObjectConstructor constructor;
        private final Map boundFields;
    
        Adapter(ObjectConstructor constructor, Map boundFields) {
          this.constructor = constructor;
          this.boundFields = boundFields;
        }
    
        @Override
        public T read(JsonReader in) throws IOException {
          if (in.peek() == JsonToken.NULL) {
            in.nextNull();
            return null;
          }
          //看这里啊,这里啥都木有,就是实例化一个对象,字段全是默认值
          T instance = constructor.construct();
          //省略好多..... 
          return instance;
        }
    
        @Override
        public void write(JsonWriter out, T value) throws IOException {
          //省略好多.....
        }
      }
    
    Gson对象实例化流程

    设计模式举例:

    1、Builder模式

    image.png

    2、工厂模式

    • 抽象工厂模式:生产一系列的产品,关注的是一个大的集合
    • 工厂方法模式:创建一类对象,一种产品
    • 二者关联:抽象工厂通常是工厂方法来实现的
    抽象工厂模式

    Retrofit中的抽象工厂模式

    工厂方法模式
    • 简单工厂:根据传递的参数(String、class等等)来创建对应的类对象(产品)
      特点:接口较少,简单方便
      缺点:增加产品的时候,需要增加/修改simpleFactory的代码


      简单工厂

    3、适配器模式

    适配器模式
    • adapt 接收一种类型(接口),让实现者去转换为具体的结果,接收的是R 类型,返回的是T 类型。
      除了Retrofit的CallAdapter,还有Gson中的TypeAdapter同样也是适配器模式
    Retrofit中的适配器模式

    4、代理模式

    代理模式

    访问子类(真正实现类)不可直接访问,要通过Proxy 的访问策略,来对内部私有的子类成员来进行控制访问。都实现了同样的接口(父类Subject)

    需要注意的是,在Retrofit中创建实例的时候,虽然用了java中的动态代理,但并不是严格意义上的代理?难道不是代理了传入的接口service 么?

    public  T create(final Class service) {
        Utils.validateServiceInterface(service);
        if (validateEagerly) {
          eagerlyValidateMethods(service);
        }
        return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class[] { service },
            new InvocationHandler() {
              //省略好多...
    }
    
    • 代理模式 vs 装饰模式
      • 代理模式:控制访问
      • 装饰模式:增强功能

    如何分析源码总结:

    • 带着问题入手
    • 从最熟悉的部分切入
    • 看看有哪些可扩展性设计
    • 分析下运用了哪些设计模式

    你可能感兴趣的:(<源码系列> Retrofit之二:源码分析)