Retrofit2.0源码分析

本文参考诸多博客,以及自己看源码分析。内容并非完全原创,写博客的目的只是让自己能够用文字去描述一遍源码实现,让自己总结一下。

先了解一下Retorift的使用步骤

1.创建retrofit实例
2.创建网络请求接口实例
3.进行网络请求
4.处理网络请求回来的数据

那么接下来就开始根据使用步骤一步一步分析

1.创建retrofit实例

创建Retrofit实例对象

Retrofit retrofit = new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(AppUrl.getHttpUrl())
                .build();

retrofit使用的是建造者模式,可以看出,build()以后返回的是Retrofit实例对象,所以肯定会去调用构造方法,所以先看一下Retrofit的构造方法

Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
      List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
      Executor callbackExecutor, boolean validateEagerly) {
     // 网络请求器的工厂,默认使用okhttp
    this.callFactory = callFactory;
    // 网络请求的url地址
    this.baseUrl = baseUrl;
    // 数据转换器工厂的集合
    this.converterFactories = unmodifiableList(converterFactories); 
     //网络请求适配器工厂作用:生产网络请求适配器(CallAdapter)
    this.adapterFactories = unmodifiableList(adapterFactories);
    // 回调方法执行器
    this.callbackExecutor = callbackExecutor;
    //是否提前对业务接口中的注解进行验证转换的标志位
    this.validateEagerly = validateEagerly;
  }

主要初始化了以上参数,就先大概熟悉一下上面几个参数具体是有什么作用
接下来根据上面的参数一个一个的进行分析

CallAdapter(网络请求执行器Call的适配器)

callAdapter默认是使用OkHttpCall,以下代码来自Platform内部实现
在Retrofit中提供了四种CallAdapterFactory: ExecutorCallAdapterFactory(默认)、GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory

接下来就继续分析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;

    Builder(Platform platform) {
      this.platform = platform;
      converterFactories.add(new BuiltInConverters());
    }

  //会调用这个无参构造,this再去调用有参构造
    public Builder() {
      this(Platform.get());
    }

那就先看看Platform里面都

class Platform {

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

//以下代码可以看出,支持3个平台:Android平台、Java平台、IOS平台
private static Platform findPlatform() {
    try {
      // Class.forName(xxx.xx.xx)的作用:要求JVM查找并加载指定的类(即JVM会执行该类的静态代码段)
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
      // 如果是Android平台,就创建一个Android对象返回
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    //java平台
    try {
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    //ios平台
    try {
      Class.forName("org.robovm.apple.foundation.NSObject");
      return new IOS();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }

因为我们是Android平台,所以看一下Android的内部实现

 static class Android extends Platform {
    //创建默认的网络请求适配器工厂
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    // 返回一个默认的回调方法执行器
    @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

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

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

再分析一下GsonConverterFactory.create()

public final class GsonConverterFactory extends Converter.Factory {

  public static GsonConverterFactory create() {
  //创建Gson对象
    return create(new Gson());
  }

  public static GsonConverterFactory create(Gson gson) {
  //创建了包含Gson对象实例的GsonConverterFactory
    return new GsonConverterFactory(gson);
  }

  private final Gson gson;

  private GsonConverterFactory(Gson gson) {
    if (gson == null) throw new NullPointerException("gson == null");
    this.gson = gson;
  }
}

从上面这段代码可以看出,GsonConverterFactory.create()实际上就是创建了一个含有Gson对象的GsonConverterFactory,再看看addConverterFactory的内部实现,实际上就是把GsonConverterFactory添加到了数据转换器工厂的集合当中

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

再来分析一下baseUrl执行了什么操作,baseUrl(“www.baidu.com”)

public Builder baseUrl(String baseUrl) {
    //判断url是否为空
      checkNotNull(baseUrl, "baseUrl == null");
    //转换为Okhttp的HttpUrl类型
      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<String> pathSegments = baseUrl.pathSegments();
      //检查URL参数是不是以"/"结尾
      if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
        throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
      }
      this.baseUrl = baseUrl;
      return this;
    }

由此得知,url会转换为Okhttp的HttpUrl类型,并且Url一定要以"/"结尾,否则会抛出异常。
最后再分析一下,.build()方法。

public Retrofit build() {
      //判断请求url地址是否为空
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      //如果没有指定,默认用OkHttpClient
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

      //如果没有指定,会默认使用MainThreadExecutor
     //之前已经判断了当前环境是Android,而继承自Platform的Android里面已经提供了默认的
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      //添加网络请求适配器工厂到集合当中,默认适配器工厂(ExecutorCallAdapterFactory)添加到集合最后
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      //数据转换器工厂 1.默认的数据转换工厂 2.自定义的数据转换工厂
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
    
      //最终返回Retrofit的对象,并传入已经配置好的成员变量
      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }

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

//定义接收网络数据的类
public interface HttpService {
    //   app版本检查
    //注解GET:采用Get方法发送网络请求
    @GET("app/version/get-newversioninfo?versionCode=1")
    // 接受网络请求数据的方法
    Call<JavaBean> newVersionInfo();
}

HttpService httpService = retrofit.create(HttpService.class);

Call<JavaBean> call = httpService.newVersionInfo();

接下来就看看retrofit.create(service)到底做了什么。

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() {  // 将代理类的实现交给 InvocationHandler类作为具体的实现
          private final Platform platform = Platform.get();
          @Override public Object invoke(Object proxy, Method method, 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);
            }
            //主要就是一下三行代码的实现,下面再具体分析这三行代码
            ServiceMethod serviceMethod = loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

private void eagerlyValidateMethods(Class<?> service) {
    //获取当前系统环境
    Platform platform = Platform.get();
    //获取本类中的所有方法,包含private,protected以及默认权限
    for (Method method : service.getDeclaredMethods()) {
      if (!platform.isDefaultMethod(method)) {
        //将传入的ServiceMethod对象加入LinkedHashMap<Method, ServiceMethod>集合
        loadServiceMethod(method);
      }
    }
  }

  ServiceMethod loadServiceMethod(Method method) {
    ServiceMethod result;
    synchronized (serviceMethodCache) {
    //先通过key获取ServiceMethod(以Method为键将该对象存入LinkedHashMap集合中)
      result = serviceMethodCache.get(method);
    //如果ServiceMethod为空,则创建ServiceMethod并添加
      if (result == null) {
        result = new ServiceMethod.Builder(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

前面提到invoke有三行代码,现在开始分析这三行代码,loadServiceMethod在上面已经大概添加了注解了,继续看loadServiceMethod方法中的new ServiceMethod.Builder(this, method).build() 具体内部实现

final class ServiceMethod<T> {
  static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
  static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
  static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);
   // 网络请求工厂  
  final okhttp3.Call.Factory callFactory;
   //网络请求适配器工厂
  final CallAdapter<?> callAdapter;
  // 网络请求地址 
  private final HttpUrl baseUrl;
  // Response内容转换器
  private final Converter<ResponseBody, T> responseConverter;
  // 网络请求的Http方法 
  private final String httpMethod;
  // 网络请求的相对地址
  private final String relativeUrl;
  // 网络请求的http请求头
  private final Headers headers;
  // 网络请求的http报文body的类型
  private final MediaType contentType;
  private final boolean hasBody;
  private final boolean isFormEncoded;
  private final boolean isMultipart;
  private final ParameterHandler<?>[] parameterHandlers;
  ServiceMethod(Builder<T> builder) {
      this.callFactory = builder.retrofit.callFactory();
      this.callAdapter = builder.callAdapter;
      this.baseUrl = builder.retrofit.baseUrl();
      this.responseConverter = builder.responseConverter;
      this.httpMethod = builder.httpMethod;
      this.relativeUrl = builder.relativeUrl;
      this.headers = builder.headers;
      this.contentType = builder.contentType;
      this.hasBody = builder.hasBody;
      this.isFormEncoded = builder.isFormEncoded;
      this.isMultipart = builder.isMultipart;
      this.parameterHandlers = builder.parameterHandlers;
    }
}

通过上面的代码可以知道,SeviceMethod包含了网络请求的基本信息
再看看build的实现

public ServiceMethod build() {
      // 根据网络请求接口方法的返回值和注解类型,从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?");
      }
      // 根据网络请求接口方法的返回值和注解类型,从Retrofit对象中获取对应的数据转换器
      responseConverter = createResponseConverter();

      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.");
        }
        //为方法中的每个参数创建一个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);
    }

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

private Converter<ResponseBody, T> createResponseConverter() {
      Annotation[] annotations = method.getAnnotations();
      try {
        return retrofit.responseBodyConverter(responseType, annotations);
      } catch (RuntimeException e) { // Wide exception range because factories are user code.
        throw methodError(e, "Unable to create converter for %s", responseType);
      }
    }

@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, 
    Annotation[] annotations, Retrofit retrofit) {

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

推荐阅读更多精彩内容