Retrofit源码分析

一、简介

Retrofit基于OkHttp通过注解配置网络请求参数。支持同步、异步的网络请求,支持Gson、Json、XML、Protobuf等多种数据的解析、序列化。

Retrofit有以下优点:

  1. 功能强大
    支持同步、异步网络请求、支持Rxjava、支持多种数据解析
  2. 简单
    由注解配置网络请求参数,并运用了大量的设计模式
  3. 拓展性强
    高度封装功能模块,可自定义Converter等来高解耦

二、请求流程

具体过程如下:

  • ① 解析网络请求接口的注解、配置网络请求参数
  • ② 通过动态代理生成网络请求对象
  • ③ 网络请求适配器将网络请求对象进行平台适配(Android、RxJava、Guava、Java8)
  • ④ 网络请求执行器发送网络请求
  • ⑤ 数据转换器 解析服务器返回的数据
  • ⑥ 回调执行器切换线程
  • ⑦ 用户在主线程处理返回结果

三、创建Retrofit实例

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://www.baidu.com/")
        .addConverterFactory(GsonConverterFactory.create())
        .build();

Retrofit实例是使用 建造者模式 通过Builder类构建出来的,将复杂对象的构建、表示进行分离,用户可以在不知道对象创建细节情况下就可以直接创建复杂对象。

在这里插入图片描述

3.1 new Retrofit

这里配置了一堆的成员变量:

  • serviceMethod:包含所有网络请求的对象—> private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
  • baseUrl:网络请求url
  • callFactory:网络请求工厂—>生成Call
  • adapterFactories:网络请求适配器工厂的集合—>生成CallAdapter
  • converterFactories:数据转换器工厂的集合—>生产Converter
  • callbackExecutor:回调方法执行器
  • validateEagerly:标志位,是否提前对接口的注解进行验证转换

这里的一些xxxFactory用到了工厂模式!将 类实例化的操作 与 使用对象的操作 分开,使得使用者不用知道具体参数就可以实例化出所需要的“产品”类。

public final class Retrofit {
  //网络请求配置对象(对网络请求接口中的方法注解进行解析后得到的对象)
  //存储网络请求相关配置(网络请求方法、数据转换器、网络请求适配器、网络请求工厂、基地址)  
  private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();

  //网络请求器的工厂,生成网络请求器Call,Retrofit默认使用OkHttp  
  private final okhttp3.Call.Factory callFactory;
  
  //网络请求url
  private final HttpUrl baseUrl;
  
  //数据转换器工厂的集合,用来生产数据转换器converter
  private final List<Converter.Factory> converterFactories;
  
  //网络请求适配器工厂的集合,用来生成网络请求适配器CallAdapter
  private final List<CallAdapter.Factory> adapterFactories;
  
  //回调方法执行器
  private final Executor callbackExecutor;
  
  //是否提前对业务接口中的注解进行验证转换的标志位
  private final boolean validateEagerly;

  Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
      List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
      Executor callbackExecutor, boolean validateEagerly) {
    this.callFactory = callFactory;
    this.baseUrl = baseUrl;
    
    //unmodifiableList(list)相当于UnmodifiableList<E>(list),
    //创建的新对象能够对list数据进行访问,但是不能对list集合中的元素进行修改
    this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site.
    this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site.
    this.callbackExecutor = callbackExecutor;
    this.validateEagerly = validateEagerly;
  }
  省略......
}  

callAdapterFactory负责生产callAdapter,即网络请求适配器,网络请求执行器Call(默认OkHttpCall)的适配器。有以下4种:

  • ExecutorCallAdapterFactory 默认
  • GuavaCallAdapterFactory
  • Java8CallAdapterFactory
  • RxJavaCallAdapterFactory

CallAdapter的作用:将默认的Call(即OkHttpCall)转换,以适应不同平台。

默认使用OkHttpCall通过ExecutorCallbackCall切换线程,但RxJava用来切换线程不需要Handler,更方便。用RxJavaCallAdapterFactoryCallAdapter来将OkHttpCall转换为RxJava:

// 把response封装成rxjava的Observeble,然后进行流式操作
Retrofit.Builder.addCallAdapterFactory(newRxJavaCallAdapterFactory().create()); 

3.2 xx.Builder()

在这里插入图片描述

Builder类的构建用到了建造者模式!先看看Builder类,Builder类的成员变量和Retrofit类的成员变量是对应的,所以Retrofit类的成员变量基本上都是通过Builder类来配置的。

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

<-- 步骤1 -->
// Builder的构造方法(无参)
 public Builder() {
      this(Platform.get());
    }
...
}

<-- 步骤2 -->
class Platform {

  private static final Platform PLATFORM = findPlatform();
  // 将findPlatform()赋给静态变量

  static Platform get() {
    return PLATFORM;    
    // 返回静态变量PLATFORM,即findPlatform() ->>步骤3
  }

<-- 步骤3 -->
private static Platform findPlatform() {
    try {

      Class.forName("android.os.Build");
      // Class.forName(xxx.xx.xx)的作用:要求JVM查找并加载指定的类(即JVM会执行该类的静态代码段)
      if (Build.VERSION.SDK_INT != 0) {
        return new Android(); 
        // 此处表示:如果是Android平台,就创建并返回一个Android对象 ->>步骤4
      }
    } catch (ClassNotFoundException ignored) {
    }

    try {
      // 支持Java平台
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }

    try {
      // 支持iOS平台
      Class.forName("org.robovm.apple.foundation.NSObject");
      return new IOS();
    } catch (ClassNotFoundException ignored) {
    }

    // 说明Builder指定了运行平台为Android
    return new Platform();
  }
...
}

<-- 步骤4 -->
// 用于接收服务器返回数据后进行线程切换在主线程显示结果

static class Android extends Platform {

    @Override
      CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {

      // 创建默认的网络请求适配器工厂  
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

    @Override 
      public Executor defaultCallbackExecutor() {
      // 返回一个默认的回调方法执行器
      // 作用:将子线程切换到主线程,并在主线程(UI线程)中执行回调方法
      return new MainThreadExecutor();
    }

    static class MainThreadExecutor implements Executor {
   
      // 获取与Android 主线程绑定的Handler  
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override 
      public void execute(Runnable r) {
        
        // 该Handler是上面获取的与Android 主线程绑定的Handler 
        // 在UI线程进行对网络请求返回数据处理等操作。       
        handler.post(r);
      }
    }
  }

// 下面继续看步骤5的Builder有参构造方法
<-- 步骤5 -->
//  Builder类的构造函数2(有参)
  public  Builder(Platform platform) {

  // 接收Platform对象(Android平台)
      this.platform = platform;

// 通过传入BuiltInConverters()对象配置数据转换器工厂(converterFactories)

// converterFactories是一个存放数据转换器Converter.Factory的数组
// 配置converterFactories即配置里面的数据转换器
      converterFactories.add(new BuiltInConverters());

// BuiltInConverters是一个内置的数据转换器工厂(继承Converter.Factory类)
// new BuiltInConverters()是为了初始化数据转换器
    }

5步走:

  • ①用this调用自己的有参构造方法public Builder(Platform platform),并调用Platform.get()方法传入platform对象
  • ②return findPlatform()
  • ③Retrofit2.0支持Android、Ios、Java3个平台,最后 将一个指定的平台对象platform return给Builder的有参构造方法public Builder(Platform platform)
  • ④接收服务器返回的数据后,从子线程切换到主线程显示:构建默认的网络请求适配器工厂ExecutorCallAdapterFactory,生产的adpater会使得Call在异步调用时在指定的Executor上执行回调(用到了策略模式)。获取到与主线程绑定的Handler,通过handler.post()方法在UI线程显示数据。切换线程的流程:回调ExecutorCallAdapterFactory生成一个ExecutorCallbackCall对象,通过调用ExecutorCallbackCall.enqueue(CallBack)方法调用MainThreadExecutor的execute()方法,通过handler切换到主线程
  • ⑤Builder类的有参构造方法会接收Platform对象(Android平台),并且会配置数据转换器工厂converterFactories

对Builder类,它设置了默认的Platform-Android、网络请求适配器工厂CallAdapterFactory(CallAdapter会对原始Call再次封装,如Call —>Observable)、数据转换器工厂converterFactory、回调执行器callbackExecutor。这里仅设置了默认值,并未真正配置到具体Retrofit类的成员变量中。

3.3 .baseUrl(“http://www.baidu.com/”)

在这里插入图片描述

配置Retrofit类的网络请求url,将传入的String类型的url转化为适应OkHttp类型的HttpUrl,并通过一系列判断来检查是否“合格”。

通过HttpUrl.parse(baseUrl)将url类型转换,并进一步加工(将HttpUrl分割为几个路径碎片,检查最后一个碎片是否以“/”结尾。否则,就抛出异常)

<-- 步骤1 -->
public Builder baseUrl(String baseUrl) {
  // 检查baseUrl不为空
  checkNotNull(baseUrl, "baseUrl == null");
  
  //把String类型的url转化为适应OkHttp的HttpUrl类型
  HttpUrl httpUrl = HttpUrl.parse(baseUrl);
  if (httpUrl == null) {
    throw new IllegalArgumentException("Illegal URL: " + baseUrl);
  }
  
  //返回带HttpUrl类型参数的baseUrl
  return baseUrl(httpUrl);
}



<-- 步骤2 -->
public Builder baseUrl(HttpUrl baseUrl) {
  //还得检查不为null  
  checkNotNull(baseUrl, "baseUrl == null");
  
  //把baseUrl参数分割成几个路径碎片
  List<String> pathSegments = baseUrl.pathSegments();
  
  //检查最后一个碎片,判断baseUrl是不是以“/”结尾。否则就抛异常
  if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
    throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
  }
  this.baseUrl = baseUrl;
  return this;
}

3.4 .addConverterFactory(GsonConverterFactory.create())在这里插入图片描述

这里主要做了两件事:

  • 1 内部的GsonConverterFactory.create()会调用create(new Gson)方法来创建一个含有Gson对象的GsonConverterFactory
  • 2 讲这个含有Gson实例的GsonConverterFactory,通过addConverterFactory方法,放到数据转化器 工厂converterFactories中
public final class GsonConverterFactory extends Converter.Factory {

  <-- 步骤1 -->
  public static GsonConverterFactory create() {
      
    //创建一个Gson对象--->步骤2  
    return create(new Gson());
  }

  <-- 步骤2 -->
  public static GsonConverterFactory create(Gson gson) {
      
    //创建一个含有Gson对象实例的GsonConverterFactory--->步骤3  
    return new GsonConverterFactory(gson);
  }

  private final Gson gson;

  <-- 步骤3 -->
  private GsonConverterFactory(Gson gson) {
    if (gson == null) throw new NullPointerException("gson == null");
    this.gson = gson;
  }

  省略......
}


// 将刚刚创建的GsonConverterFactory放到converterFactories数组中
//这里需要联系3.2章节的步骤5,添加了一个内置数据转换器工厂BuiltInConverters()后又放入了一个GsonConverterFactory
public Builder addConverterFactory(Converter.Factory factory) {
  converterFactories.add(checkNotNull(factory, "factory == null"));
  return this;
}

由此可以看出:Retrofit默认Gson解析,也可以继承Converter.Factory自定义,来解析其他格式数据(Json、XML、Protocobuf)

3.5 .build()

通过前面步骤设置的遍变量,配置好Retrofit类的所有成员变量,进而成功创建Retrofit实例。
配置:

  • 1 网络请求执行器, okhttp3.Call.Factory callFactory = this.callFactory;若未指定,就new OkHttpClient()使用OkHttp
  • 2 回调方法执行器callbackExecutor。若未指定,就默认使用Platform对应的callbackExecutor
  • 3 网络请求适配器工厂,List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
  • 4 数据转换器工厂,List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

在这里插入图片描述

最后,这个“武装到牙齿”的Rertrofit就配置好了,return

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

  // 配置网络请求执行器-CallFactory
  okhttp3.Call.Factory callFactory = this.callFactory;
  // 如果没指定,默认使用OkHttp,所以Retrofit默认使用OkHttp进行网络请求
  if (callFactory == null) {
    callFactory = new OkHttpClient();
  }

  // 配置回调方法执行器-callbackExecutor  
  Executor callbackExecutor = this.callbackExecutor;
  // 如果没指定,默认使用Platform检测环境时默认的callbackExecutor
  //即Android默认的callbackExecutor
  if (callbackExecutor == null) {
    callbackExecutor = platform.defaultCallbackExecutor();
  }

  // 配置网络请求适配器工厂-CallAdapterFactory
  List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
  // 将3.2章节步骤4中创建的CallAdapter.Factory请求适配器 添加到集合器末尾
  //请求适配器工厂集合存储顺序为:自定义1适配器工厂、自定义2适配器工厂...默认适配器工厂ExecutorCallAdapterFactory
  adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

  // 配置数据转换器工厂-converterFactory
  // 在3.2章节-步骤2中已经添加了内置的数据转换器BuiltInConverters()到集合器首位,
  // 在3.2章节-步骤4中又插入了一个Gson的转换器GsonConverterFactory到集合器第二位
  List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
  // 数据转换器工厂集合的存储顺序:默认的数据转换器工厂BuiltInConverters、自定义1数据转换器工厂GsonConverterFactory、自定义2数据转换器工厂...

  // 最后return一个Retrofit对象,并传入以上配置好的成员变量  
  return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
      callbackExecutor, validateEagerly);
}

至此,Retrofit就使用建造者模式,通过Builder类创建了一个Retrofit实例。具体配置了:

  • Platform - Android
  • baseUrl
  • callFactory - OkHttpCall
  • adapterFactories - ExecutorCallAdapterFactory
  • converterFactories
  • callbackExecutor
    得益于建造者模式,并不需要关心配置细节就可以创建好Retrofit实例!

四、创建网络请求接口的实例

<-- 步骤1:定义接收网络数据的类 -->
public class JavaBean {
  ...
  }

<-- 步骤2:定义网络请求的接口类 -->
public interface Api {

    @GET(...)
    Call<JavaBean> getCall();
}

<-- 步骤3:在MainActivity创建接口类实例  -->
API api= retrofit.create(AccessApi.class);
       
<-- 步骤4:对发送请求的url进行封装,即生成最终的网络请求对象  --> 
        Call<JavaBean> call = api.getCall();

4.1 创建接口类实例:API api= retrofit.create(AccessApi.class);

采用外观模式访问,内部使用代理模式。选用外观模式:可在内部调用各个方法来创建网络请求接口的实例,配置网络请求参数。有效的降低系统耦合度;选用动态代理:代理类在运行时由程序动态生成,return (T) Proxy.newProxyInstance(…InvocationHandler…)动态生成网络请求接口的代理类,并将代理类的实例创建,交给InvocationHandler作为具体实现,最终返回一个动态代理对象。生成实例的过程中含有生成实现类的缓存机制,运用了单例模式:result = serviceMethodCache.get(method)

好处:

  • ①当api.getCall()时,会进行拦截。所有的调用都会集中转发到InvocationHandler#invoke()中,几种处理
  • ②可获取网络请求接口实例上的所有注解
  • ③更方便的封装ServiceMethod
public <T> T create(final Class<T> service) {
  Utils.validateServiceInterface(service);
  
  //判断是否需要提前验证
  if (validateEagerly) {
    //对接口中每个方法的注解进行解析,并得到一个ServiceMethod对象,
    //以Method为key将该对象存入LinkedHashMap集合中。  
    eagerlyValidateMethods(service);
  }
  //如果不提前验证,就动态解析对应方法,得到一个ServiceMethod对象,最后存到LinkedHashMap中,类似延迟加载
  
  //创建网络请求接口的动态代理对象,通过动态代理来创建网络请求接口的实例并返回。
  //该动态代理是为了拿到网络请求接口上的所有注解
  return (T) Proxy.newProxyInstance(
  service.getClassLoader(), // 动态生成接口的实现类
  new Class<?>[] { service }, // 动态创建实例
      new InvocationHandler() { //将代理类的实现交给InvocationHandler类作为具体的实现
        private final Platform platform = Platform.get();

        
        //在InvocationHandler类的invoke()实现中,除了执行真正的逻辑(如再次转发给真正的实现类对象),
        //还会进行统计执行时间、初始化和清理、检查接口调用等其他操作
        @Override public Object invoke(Object proxy, Method method, 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);
          }
          //这才是最关键的!
          ServiceMethod serviceMethod = loadServiceMethod(method);
          OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
          return serviceMethod.callAdapter.adapt(okHttpCall);
        }
      });
}

private void eagerlyValidateMethods(Class<?> service) {
  Platform platform = Platform.get();
  for (Method method : service.getDeclaredMethods()) {
    // 将传入的serviceMethod对象加入到LinkedHashMap<Method,ServiceMethod>集合中,
    // LinkedHashMap好处: lruEntries.values().iterator().next()获取到的是集合最不经常用到的元素,提供了一种Lru算法的实现 
    if (!platform.isDefaultMethod(method)) {
      loadServiceMethod(method);
    }
  }
}

以上主要做了两件事:

  • 1 通过validateEagerly判断是否提前验证。若需要,则调用eagerlyValidateMethods方法解析接口中每个方法的注解,得到一个ServiceMethod对象。将其以method为key存储到LinkedHashMap中:LinkedHashMap<Method, ServiceMethod>。使用LinkedHashMap的好处是lruEntries.values().iterator().next()获取到的是集合最不经常用到的元素,LRU的体现。若不提前验证,就对方法动态解析,得到ServiceMethod对象,放到LinkedHashMap中
  • 2 创建爱你网络请求接口的动态代理对象,即动态代理创建网络请求接口实例。动态代理的目的是拿到接口实例上的所有注解,其中主要将代理类的实现交给InvocationHandler#invoke()

关于InvocationHandler#invoke(),主要做了3件事!

4.1.1 ServiceMethod serviceMethod = loadServiceMethod(method);

目的就是读取网络请求接口中的方法,并根据配置好的属性来配置serviceMethod对象。这个loadServiceMethod方法就是负责加载serviceMethod对象,以便和网络请求接口中定义的方法一一对应。

这里的ServiceMethod对象的创建用到了缓存机制:利用单例模式实现一个ServiceMethod对象对应 网络请求接口 中的一个方法。每次获取接口实例都是传入class对象,而class对象在进程内是单例的,因此获取它的同一个Method对象也是单例的。

ServiceMethod loadServiceMethod(Method method) {
  ServiceMethod result;
  // 设置线程同步锁
  synchronized (serviceMethodCache) {
      
    // ServiceMethod对象采用单例模式创建,在创建ServiceMethod对象前,
    // 先看 serviceMethodCache 有没有缓存之前创建过的网络请求实例
    result = serviceMethodCache.get(method);
    
    // serviceMethodCache 没缓存就利用建造者模式构建
    if (result == null) {
      result = new ServiceMethod.Builder(this, method).build();
      serviceMethodCache.put(method, result);
    }
  }
  return result;
}

ServiceMethod的加载分为以下3步:
① 设置线程同步锁synchronized (serviceMethodCache)
单例模式创建ServiceMethod对象,即先看看ServiceMethodCache是否缓存过创建好的网络请求实例
③如果serviceMethodCache没有缓存,就利用建造者模式构建ServiceMethod实例:result = new ServiceMethod.Builder(this, method).build();

4.1.1.1 建造者模式创建ServiceMethod1~构造函数

ServiceMethod的构造,传入各种网络请求参数。如:网络请求工厂、网络请求适配器工厂、Response数据转换器、网络请求(相对)地址、http方法、http请求头、http报文body的类型、方法参数处理器parameterHandler(用来解析定义的方法的参数,并在构造Http请求时设置参数)

<-- ServiceMethod 类 -->
public final class ServiceMethod {
final okhttp3.Call.Factory callFactory;  // 网络请求工厂  
final CallAdapter<?> callAdapter;  // 网络请求适配器工厂 

//作用:负责把服务器返回的数据(JSON或者其他格式,由 ResponseBody 封装)转化为 T 类型的对象;
private final Converter<ResponseBody, T> responseConverter; // Response内容转换器 
 

  
private final HttpUrl baseUrl; // 网络请求地址  
private final String relativeUrl; // 网络请求的相对地址  
private final String httpMethod;   // 网络请求的Http方法  
private final Headers headers;  // 网络请求的http请求头 键值对  
private final MediaType contentType; // 网络请求的http报文body的类型  

// 方法参数处理器,作用:负责解析 API 定义时每个方法的参数,并在构造 HTTP 请求时设置参数;
private final ParameterHandler<?>[] parameterHandlers;  

<-- ServiceMethod 类的构造函数 -->
ServiceMethod(Builder<T> builder) {

    this.callFactory = builder.retrofit.callFactory();  
    this.callAdapter = builder.callAdapter;   
    this.responseConverter = builder.responseConverter;   
  
    this.baseUrl = builder.retrofit.baseUrl();   
    this.relativeUrl = builder.relativeUrl;   
    this.httpMethod = builder.httpMethod;  
    this.headers = builder.headers;  
    this.contentType = builder.contentType; .  
    this.hasBody = builder.hasBody; y  
    this.isFormEncoded = builder.isFormEncoded;   
    this.isMultipart = builder.isMultipart;  
    this.parameterHandlers = builder.parameterHandlers;  
}
4.1.1.2 建造者模式创建ServiceMethod2~.Builder(this, method)

获取网络请求接口方法中的注释、参数类型、注解内容等

public Builder(Retrofit retrofit, Method method) {
  this.retrofit = retrofit;
  this.method = method;
  //获取网络请求接口方法中的注释
  this.methodAnnotations = method.getAnnotations();
  //获取网络请求接口方法中的参数类型
  this.parameterTypes = method.getGenericParameterTypes();
  //获取网络IQ那个IQu借款发放中的注解内容
  this.parameterAnnotationsArray = method.getParameterAnnotations();
}
4.1.1.3 建造者模式创建ServiceMethod3~.build()

build()方法是控制ServiceMethod对象的生成流程:

  • ①根据网络请求接口方法中的返回值和注解类型,依次从Retrofit对象中获取对应的网络请求适配器(createCallAdapter()方法)及返回的数据类型(callAdapter.responseType()方法)、对应的数据转换器。遍历Converter.Factory集合取出合适的工厂做数据转换(这里指的Gson)
  • ②根据方法的注解,为ServiceMethod域赋值
  • ③对每个方法的所有参数的注解进行解析,获得ParameterHandler对象。该对象保存有一个Request内容转换器

这里涉及到了策略模式:选择RxJavaCallAdapterFactory后,即可通过策略模式得到对应的adapter。只需要根据网络请求接口方法的返回值类型,就能选择使用哪种CallAdapterFactory,然后创建具体的CallAdapter实例。

至此,就配置好了网络请求参数,即ServiceMethod对象。

public ServiceMethod build() {
  // 关注点1 
  //根据网络请求接口方法中的返回值和注解类型,从Retrofit对象中获取对应的网络请求适配器 
  callAdapter = createCallAdapter();
  
  //根据网络请求接口方法中的返回值和注解类型,从Retrofit对象中获取该网络请求适配器返回的数据类型
  responseType = callAdapter.responseType();
  if (responseType == Response.class || responseType == okhttp3.Response.class) {
    throw methodError("'"
        + Utils.getRawType(responseType).getName()
        + "' is not a valid response body type. Did you mean ResponseBody?");
  }
  // 关注点3
  //根据网络请求接口方法中的返回值和注解类型,从Retrofit对象中获取对应的数据转换器
  responseConverter = createResponseConverter();

  //解析网络请求接口方法中的注解,从而获取Http请求的方法。  
  for (Annotation annotation : methodAnnotations) {
    parseMethodAnnotation(annotation);
  }

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

  if (!hasBody) {
    if (isMultipart) {
      throw methodError(
          "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
    }
    if (isFormEncoded) {
      throw methodError("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++) {
    Type parameterType = parameterTypes[p];
    if (Utils.hasUnresolvableType(parameterType)) {
      throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
          parameterType);
    }

    Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
    if (parameterAnnotations == null) {
      throw parameterError(p, "No Retrofit annotation found.");
    }
    //对方法参数中的注解进行解析(Body、Query等),从而获取到一个ParameterHandler<?>对象
    parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
  }

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

  return new ServiceMethod<>(this);
}


<-- 关注点1createCallAdapter() -->
private CallAdapter<?> createCallAdapter() {
  //获取网络请求接口方法里的返回值类型  
  Type returnType = method.getGenericReturnType();
  if (Utils.hasUnresolvableType(returnType)) {
    throw methodError(
        "Method return type must not include a type variable or wildcard: %s", returnType);
  }
  if (returnType == void.class) {
    throw methodError("Service methods cannot return void.");
  }
  //获取网络请求接口方法中的注解,此处为@GET
  Annotation[] annotations = method.getAnnotations();
  try {
    //关注点2  
    //根据网络请求接口方法中的返回值和注解类型,从Retrofit对象中获取对应的网络请求适配器
    return retrofit.callAdapter(returnType, annotations);
  } catch (RuntimeException e) { // Wide exception range because factories are user code.
    throw methodError(e, "Unable to create call adapter for %s", returnType);
  }
}

<-- 关注点2:retrofit.callAdapter()  -->
 public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }

 public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {

    
    // 遍历 CallAdapter.Factory 集合寻找合适的工厂(该工厂集合在第一步构造 Retrofit 对象时进行添加)
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);      
      if (adapter != null) {
        return adapter;
      }
    }
    
    
<--   关注点3:createResponseConverter() -->
 private Converter<ResponseBody, T> createResponseConverter() {
      Annotation[] annotations = method.getAnnotations();
      try {
    
        // responseConverter 还是由 Retrofit 类提供  -->关注点4
        return retrofit.responseBodyConverter(responseType, annotations);
      } catch (RuntimeException e) { 
        throw methodError(e, "Unable to create converter for %s", responseType);
      }
    }    
    

<--   关注点4:responseBodyConverter() -->
  public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
    return nextResponseBodyConverter(null, type, annotations);
  }

 public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast,

    int start = converterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = converterFactories.size(); i < count; i++) {

       // 关注点5  获取Converter 过程
         Converter<ResponseBody, ?> converter =
          converterFactories.get(i).responseBodyConverter(type, annotations, this); 
       // 遍历 Converter.Factory 集合并寻找合适的工厂(该工厂集合在构造 Retrofit 对象时进行添加)
       // 由于构造Retroifit默认Gson解析方式,所以取出的是GsonResponseBodyConverter
       // Retrofit - Converters 还提供了 JSON,XML,ProtoBuf 等类型数据的转换功能。

    }


<--   关注点5:responseBodyConverter() -->
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, 
    Annotation[] annotations, Retrofit retrofit) {

  // 根据目标类型,利用 Gson#getAdapter 获取相应的 adapter
  TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
  return new GsonResponseBodyConverter<>(gson, adapter);
}

// 做数据转换时调用 Gson 的 API 即可。
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
  private final Gson gson;
  private final TypeAdapter<T> adapter;

  GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
    this.gson = gson;
    this.adapter = adapter;
  }

  @Override 
   public T convert(ResponseBody value) throws IOException {
    JsonReader jsonReader = gson.newJsonReader(value.charStream());
    try {
      return adapter.read(jsonReader);
    } finally {
      value.close();
    }
  }
}    

4.1.2 OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);

根据刚才配置好的ServiceMethod对象和输入的参数args,创建OkHttpCall对象

<--OkHttpCall类 -->
public class OkHttpCall {
    // 含有所有网络请求参数信息的对象
    private final ServiceMethod<T> serviceMethod; 
    // 网络请求接口的参数   
    private final Object[] args; 
    //实际进行网络访问的类  
    private okhttp3.Call rawCall; 
    //几个状态标志位  
    private Throwable creationFailure; 
    private boolean executed;  
    private volatile boolean canceled;  
  
<--OkHttpCall构造函数 -->
  public OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) {  
    // 传入了配置好的ServiceMethod对象和输入的请求参数
    this.serviceMethod = serviceMethod;  
    this.args = args;  
}  

4.1.3 return serviceMethod.callAdapter.adapt(okHttpCall);

将上一步创建的OkHttpCall对象传递给ServiceMethod对象中对应的网络请求适配器工厂的adap()方法中,返回的对象类型是默认的Call<>。如果设置了RxJavaCallAdapterFactory,就返回Observable<>

参数齐全的OkHttpCall对象最终交给了静态代理delegate,静态代理作用:代理执行被代理者的方法,且可在要执行的方法前后加入自己的动作,进行对系统功能的拓展

public <R> Call<R> adapt(Call<R> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);  
      }

   ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      // 把参数齐全的OkhttpCall对象交给静态代理delegate 
      this.delegate = delegate; 
      
      // 传入上面定义的回调方法执行器,用于进行线程切换 
      this.callbackExecutor = callbackExecutor;  
    }

传入定义的回调方法执行器callbackExecutor,用于线程切换。OkHttpCall.enqueue()用于异步请求,回调的callback在子线程,需要Handler切换到UI线程进行回调。ExecutorCallbackCall就是用于线程回调的。

ExecutorCallbackCall就是装饰者,这里用到了装饰模式,真正的执行网络请求的还是OkHttpCall。这样做的原因就是希望OkHttpCall在发请求时,还能额外的做线程切换。

4.2 调用接口方法:api.getCall()

api为动态代理对象Proxy.newProxyInstance(),并非真正的接口创建的对象。当调用接口方法时,会被动态代理对象Proxy.newProxyInstance()拦截,然后调用自己的InvocationHandler#invoke()方法。invoke()方法会将代理对象Object proxy、调用的方法Method传入。最后利用反射得到定义的接口方法的注解信息,配合args创建ServiceMethod对象。最终创建并返回一个OkHttpCall类型的Call对象。但是它只是OkHttp的包装类,并不能发送网络请求,必须得创建好Request对象后才行。

4.3 总结

由动态代理创建接口实例、建造者&单例模式创建ServiceMethod对象、策略模式对ServiceMethod进行网络请求参数的配置(主要体现在ConverterFactory的选用)、装饰模式对ServiceMethod加入线程切换操作。
最终返回OkHttpCall类型的网络请求对象

五、执行网络请求

5.1 OkHttpCall.execute()同步请求

同步请求流程如下:

  • ①对网络请求接口的方法中的每个参数,利用对应ParameterHandler进行解析,再根据ServiceMethod对象创建一个OkHttp的Request对象
  • ②使用OkHttp的Request发送网络请求;
  • ③对返回的数据使用之前设置的GsonConverterFactory解析,最终得到一个Response对象。这里还会检查状态码,将response body传入serviceMethod中,serviceMethod再通过GsonConverterFactory将response body转换为Java对象
@Override 
public Response<T> execute() throws IOException {
  okhttp3.Call call;

 // 设置同步锁
  synchronized (this) {
    call = rawCall;
    if (call == null) {
      try {
        // 步骤1:创建一个OkHttp的Request对象请求
        call = rawCall = createRawCall();
      } catch (IOException | RuntimeException e) {
        creationFailure = e;
        throw e;
      }
    }
  }
  // 步骤2:调用OkHttpCall的execute()发送网络请求(同步)
  // 步骤3:解析网络请求返回的数据parseResponse()
  return parseResponse(call.execute());
}

// 创建一个OkHttp的Request对象请求 
private okhttp3.Call createRawCall() throws IOException {
  // 从ServiceMethod的toRequest()返回一个Request对象
  Request request = serviceMethod.toRequest(args);
   // 根据serviceMethod和request对象创建 一个okhttp3.Request
  okhttp3.Call call = serviceMethod.callFactory.newCall(request);

  if (call == null) {
    throw new NullPointerException("Call.Factory returned null.");
  }
  return call;
}

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
  ResponseBody rawBody = rawResponse.body();

  rawResponse = rawResponse.newBuilder()
      .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
      .build();
  // 收到返回数据后进行状态码检查
  int code = rawResponse.code();
  if (code < 200 || code >= 300) {
  }

  if (code == 204 || code == 205) {
    return Response.success(null, rawResponse);
  }

  ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
  try {
    // 等Http请求返回后 & 通过状态码检查后,将response body传入ServiceMethod中,
    //ServiceMethod通过调用Converter接口(之前设置的GsonConverterFactory)
    //将response body转成一个Java对象,即解析返回的数据
    T body = serviceMethod.toResponse(catchingBody);
   
 

// 生成Response类
    return Response.success(body, rawResponse);
  } catch (RuntimeException e) {
    ... // 异常处理
  }
}

5.2 OkHttpCall.enqueue()异步请求

使用静态代理delegate.enqueue()执行异步请求:

  • ①对网络请求接口的方法中的每个参数,利用对应ParameterHandler进行解析,再根据ServiceMethod对象创建一个OkHttp的Request对象,再将其封装为OkHttp.Call
  • ②使用OkHttp的Request发送网络请求,delegate是OkHttpCall的静态代理,最终还是调用OkHttp.enqueue
  • ③对返回的数据使用之前设置的GsonConverterFactory解析,最终得到一个Response对象。这里还会检查状态码,将response body传入serviceMethod中,serviceMethod再通过GsonConverterFactory将response body转换为Java对象
  • ④线程切换到UI线程处理结果:callbackExecutor.execute(new Runnable…)通过Handler异步回调将结果传回到UI线程。

线程切换是通过一开始创建Retrofit对象时,Platform检查运行环境为Android时进行创建的,创建默认的回调执行器工厂,回调ExecutorCallAdapterFactory生成ExecutorCallbackCall对象,调用其enqueue()方法,从而调用MainThreadExecutor的execute()方法,通过Handler切换到主线程。这里线程切换用到了适配器模式

<--  call.enqueue()解析  -->
@Override 
public void enqueue(final Callback<T> callback) {

      delegate.enqueue(new Callback<T>() {
     // 使用静态代理 delegate进行异步请求 ->>分析1
        @Override 
        public void onResponse(Call<T> call, final Response<T> response) {
          // 步骤4:线程切换,从而在主线程显示结果
          callbackExecutor.execute(new Runnable() {
          // 最后Okhttp的异步请求结果返回到callbackExecutor
          // callbackExecutor.execute()通过Handler异步回调将结果传回到主线程进行处理(如显示在Activity等等),即进行了线程切换
          // 具体是如何做线程切换 ->>分析2
              @Override 
               public void run() {
              if (delegate.isCanceled()) {
                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);
            }
          });
        }
      });
    }


<-- 分析1:delegate.enqueue()解析 -->
@Override 
public void enqueue(final Callback<T> callback) {
   
    okhttp3.Call call;
    Throwable failure;

// 步骤1:创建OkHttp的Request对象,再封装成OkHttp.call
     // delegate代理在网络请求前的动作:创建OkHttp的Request对象,再封装成OkHttp.call
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;

      call = rawCall;
      failure = creationFailure;
      if (call == null && failure == null) {
        try {
         
          call = rawCall = createRawCall(); 
          // 创建OkHttp的Request对象,再封装成OkHttp.call
         // 方法同发送同步请求,此处不作过多描述  
        } catch (Throwable t) {
          failure = creationFailure = t;
        }
      }

// 步骤2:发送网络请求
    // delegate是OkHttpcall的静态代理
    // delegate静态代理最终还是调用Okhttp.enqueue进行网络请求
    call.enqueue(new okhttp3.Callback() {
      @Override 
        public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
        Response<T> response;
        try {
        
          // 步骤3:解析返回数据
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        callSuccess(response);
      }

      @Override 
         public void onFailure(okhttp3.Call call, IOException e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      private void callFailure(Throwable e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      private void callSuccess(Response<T> response) {
        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
    });
  }

<-- 分析2:异步请求后的线程切换-->
// 线程切换是通过一开始创建Retrofit对象时Platform在检测到运行环境是Android时进行创建的:
// 采用适配器模式
static class Android extends Platform {

    // 创建默认的回调执行器工厂
    // 如果不将RxJava和Retrofit一起使用,一般都是使用该默认的CallAdapter.Factory
    // 后面会对RxJava和Retrofit一起使用的情况进行分析
    @Override
      CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

    @Override 
      public Executor defaultCallbackExecutor() {
      // 返回一个默认的回调方法执行器
      // 该执行器负责在主线程(UI线程)中执行回调方法
      return new MainThreadExecutor();
    }

    // 获取主线程Handler
    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());


      @Override 
      public void execute(Runnable r) {
        // Retrofit获取了主线程的handler
        // 然后在UI线程执行网络请求回调后的数据显示等操作。
        handler.post(r);
      }
    }
  }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值