Retrofit2源码解析

本篇文章基于 retrofit2 的 2.5.0 版本。


首先我们想要分析源码,那就首先要会使用。看下简单用法:

public interface GitHubService {
    @GET("users/{user}/repos")
    Call<List<Repo>> listRepos(@Path("user") String user);
}
//创建Retrofit对象
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .build();
//创建service
GitHubService service = retrofit.create(GitHubService.class);
//创建Call
Call<List<Repo>> repos = service.listRepos("octocat");
//开始请求
repos.enqueue(new Callback<List<Repo>>() {
    @Override
    public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {

    }
    @Override
    public void onFailure(Call<List<Repo>> call, Throwable t) {

    }
});

1.

从create方法入手,发现是动态代理。
调用Platform.get获取platform,暂时不知道是干嘛的,
接着看核心方法是loadServiceMethod(method).invoke(..);

image.png

2.

进入loadServiceMethod方法中,找到核心方法parseAnnotations()。从方法名上看出是解析注解的意思。

image.png

3.

进入parseAnnotations方法中,有两处核心代码。

RequestFactory.parseAnnotations(retrofit, method);

HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);

image.png

4.

先查看第一处核心代码RequestFactory.parseAnnotations(retrofit, method);
发现是使用了Builder模式创建了RequestFactory对象,看里面的方法,发现有一个create方法可以使用,进入方法里面。

image.png
image.png
  • 先看第一段代码RequestBuilder,查看类里面的方法,字面意思是quest的构造器。
    image.png
  • 再看第二段代码,用刚才的RequestBuilder对象创建了一个okhttp3.Request对象。查看里面的方法。知道大概是一个真正用来发起请求的类。先记着,还没有用到。
    image.png

5.

现在回到第3个步骤继续。查看第二处核心代码HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);

image.png

看注释可以了解到,ServiceMethod最好缓存起来使用,这样就能解释上面第2个步骤的缓存了。接着往下看核心代码:
①创建了CallAdapter。

追踪方法得知最终是由Retrofit对象的nextCallAdapter方法获取,内部是从callAdapterFactories这个List中取出,由于还没有查看Retrofit类的实现,暂时先放着。

②创建了ResponseConverter

追踪方法最终还是由Retrofit对象的nextResponseBodyConverter方法获取,与上一个类似,从converterFactories中取出,还是先放着。

③获取callFactory

这个更直接,从retrofit中取出成员变量callFactory。

④传入4个参数,创建一个HttpServiceMethod对象

最后看看HttpServiceMethod的构造方法,发现只是设置了变量。

6.

回到最初开始分析时的代码loadServiceMethod(method).invoke(..);
loadServiceMethod(method)实际上返回了HttpServiceMethod对象,查看里面的invoke方法。

image.png

其中4个变量都是构造方法传进来的,继续查看callAdapter.adapt方法。发现是一个接口方法。

T adapt(Call<R> call);

现在需要找到CallAdapter实现类。从上一步骤知道,这里的4个成员变量callAdapter,requestFactory,callFactory,responseConverter中除了requestFactory是刚才知道怎么创建的,其他都是从Retrofit对象中取出来的。

7.

现在需要知道Retrofit对象是怎么构建的,回到最初的简单用法中得知,Retrofit是从Retrofit.Builderbuild方法创建的。

//创建Retrofit对象
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .build();

8.

现在从build方法入手。

/**
 * Create the {@link Retrofit} instance using the configured values.
 * <p>
 * Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link
 * OkHttpClient} will be created and used.
 */
public Retrofit build() {
  if (baseUrl == null) {
    throw new IllegalStateException("Base URL required.");
  }

  okhttp3.Call.Factory callFactory = this.callFactory;
  if (callFactory == null) {
    callFactory = new OkHttpClient();
  }

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

  // Make a defensive copy of the adapters and add the default Call adapter.
  List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
  callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

  // Make a defensive copy of the converters.
  List<Converter.Factory> converterFactories = new ArrayList<>(
      1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

  // Add the built-in converter factory first. This prevents overriding its behavior but also
  // ensures correct behavior when using converters that consume all types.
  converterFactories.add(new BuiltInConverters());
  converterFactories.addAll(this.converterFactories);
  converterFactories.addAll(platform.defaultConverterFactories());

  return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
      unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}

先看注释,明白这里就是通过一些配置来创建一个Retrofit对象,即Builder模式。
看到callFactory的创建,默认是一个OkHttpClient对象,这一点注释也有说明。
创建了一个Executor,使用了platform的defaultCallbackExecutor方法。
创建了一个callAdapterFactories的List,把默认的CallAdapterFactories添加进去,还是使用了platform的方法,defaultCallAdapterFactories(callbackExecutor)。
类似的实现方式,创建了converterFactories,也是添加了默认的对象。
最后创建了一个Retrofit对象并返回,把参数设置到了对象中。

现在清楚了第6步骤使用的对象都是在Retrofit创建时就已经配置好了,但是我们继续查看时,发现它们都是接口,所以我们需要找出它们的实际对象,即是要找出它们实例化的代码。

9.

由于默认的Executor,CallAdapter,ConverterFactories都是由Platform的defaultXXXX方法创建的,所以分析一下platform这个对象其实是什么。回到第一步骤,Retrofit的create方法的return中的一行代码。

private final Platform platform = Platform.get();

进去看看

private static final Platform PLATFORM = findPlatform();//获取平台

static Platform get() {
  return PLATFORM;
}

private static Platform findPlatform() {
  try {
    Class.forName("android.os.Build");
    if (Build.VERSION.SDK_INT != 0) {
      return new Android();//这里看到Platform对象其实就是Android对象
    }
  } catch (ClassNotFoundException ignored) {
  }
  try {
    Class.forName("java.util.Optional");
    return new Java8();
  } catch (ClassNotFoundException ignored) {
  }
  return new Platform();
}

现在知道了platform其实就是Android对象,我们查看Retrofit的build方法里的platform的调用:

  • callbackExecutor = platform.defaultCallbackExecutor();
  • platform.defaultCallAdapterFactories(callbackExecutor)
  • platform.defaultConverterFactoriesSize()
  • platform.defaultConverterFactories()
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();
  }

  //①默认的Executor是MainThreadExecutor
  @Override public Executor defaultCallbackExecutor() {
    return new MainThreadExecutor();
  }

  //②默认的CallAdapterFactories
  @Override List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
      @Nullable Executor callbackExecutor) {
    if (callbackExecutor == null) throw new AssertionError();
    //CallAdapterFactory的默认对象,传入了callbackExecutor
    ExecutorCallAdapterFactory executorFactory = new ExecutorCallAdapterFactory(callbackExecutor);
    return Build.VERSION.SDK_INT >= 24
      ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
      : singletonList(executorFactory);
  }

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

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

  //③默认的ConverterFactoriesSize
  @Override int defaultConverterFactoriesSize() {
    return Build.VERSION.SDK_INT >= 24 ? 1 : 0;
  }

  //默认的Executor中的execute方法就是用handler发消息,把操作放到主线程中
  static class MainThreadExecutor implements Executor {
    private final Handler handler = new Handler(Looper.getMainLooper());

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

10.

现在回看第5个步骤,发现了使用的参数都是由这里的对象中取出的,那么可以继续分析第6步骤的方法:


image.png

callAdapter的获取,在nextCallAdapter方法中
核心callAdapterFactories.get(i).get(returnType, annotations, this);

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

  int start = callAdapterFactories.indexOf(skipPast) + 1;
  for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
    CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
    if (adapter != null) {
      return adapter;
    }
  }
  ...
}

上面知道了callAdapterFactories的默认实现就是ExecutorCallAdapterFactory,进入该类查看get方法。

@Override public @Nullable CallAdapter<?, ?> get(
    Type returnType, Annotation[] annotations, Retrofit retrofit) {
  ...
  //创建了一个CallAdapter
  return new CallAdapter<Object, Call<?>>() {
    @Override public Type responseType() {
      return responseType;
    }

    //核心方法
    @Override public Call<Object> adapt(Call<Object> call) {
      return new ExecutorCallbackCall<>(callbackExecutor, call);
    }
  }; 
}

到这里其实就是callAdapter的实现了。

11.

继续查看adapt方法,前文得知传入的call就是new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
查看内部类ExecutorCallbackCall:

image.png

我们使用时就是调用了Call的enqueue方法,这里看到enqueue方法的真正实现。
其中delegate是刚才传入的OkHttpCall对象,callbackExecutor我们知道其实是MainThreadExecutor对象,所以这里的enqueue方法中主要做了两件事:

  • 调用OkHttpCall的enqueue发起请求
  • 调用MainThreadExecutor的execute方法,内部其实就是用主线程的Handler切换到主线程去运行。

我们继续查看OkHttpCall的enqueue方法:

@Override public void enqueue(final Callback<T> callback) {
  checkNotNull(callback, "callback == null");

  okhttp3.Call call;
  Throwable failure;

  synchronized (this) {
    if (executed) throw new IllegalStateException("Already executed.");
    executed = true;

    call = rawCall;
    failure = creationFailure;
    if (call == null && failure == null) {
      try {
        //创建okhttp3.Call对象
        call = rawCall = createRawCall();
      } catch (Throwable t) {
        throwIfFatal(t);
        failure = creationFailure = t;
      }
    }
  }

  if (failure != null) {
    callback.onFailure(this, failure);
    return;
  }

  if (canceled) {
    call.cancel();
  }
  //调用了okhttp3.Call对象的enqueue方法
  call.enqueue(new okhttp3.Callback() {
    @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
      Response<T> response;
      try {
        response = parseResponse(rawResponse);
      } catch (Throwable e) {
        throwIfFatal(e);
        callFailure(e);
        return;
      }

      try {
        callback.onResponse(OkHttpCall.this, response);
      } catch (Throwable t) {
        t.printStackTrace();
      }
    }

    @Override public void onFailure(okhttp3.Call call, IOException e) {
      callFailure(e);
    }

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

发现很长,其实里面的主要工作就是:

  • 创建okhttp3.Call的对象
  • 调用这个对象的enqueue方法

我们来看一下这个okhttp3.Call对象是什么,查看createRawCall()方法:

private okhttp3.Call createRawCall() throws IOException {
  //这个callFactory其实就是okhttpClient
  okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
  if (call == null) {
    throw new NullPointerException("Call.Factory returned null.");
  }
  return call;
}

由上文得知这里的callFactory就是Retrofit.build()中创建的OkhttpClient对象。
这里的newCall方法就是创建一个OkHttp的Call了,所以说Retrofit是基于OkHttp来实现的。

@Override public Call newCall(Request request) {
  return RealCall.newRealCall(this, request, false /* for web socket */);
}

总结

  1. 调用Retrofit.Builder的build方法,初始化必要的参数。
    有baseUrl、callFactory、callbackExecutor、callAdapterFactories、converterFactories等。
  2. 调用retrofit的create方法,包装出一个自定义的接口GitHubService的Class。
    内部实现是动态代理,具体实现是HttpServiceMethod的对象。其中包含了对接口方法注解的解析。
  3. 最后调用enqueue发起请求内部使用了okhttp。

谢谢大家能看到末尾,如果发现有错误的地方或者有疑问的地方请各位留言,谢谢!

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

推荐阅读更多精彩内容

  • 目录介绍 1.首先回顾Retrofit简单使用方法 2.Retrofit的创建流程源码分析2.1 Retrofit...
    杨充211阅读 1,061评论 0 16
  • 一、什么是Retrofit A type-safe HTTP client for Android and Jav...
    andcoder阅读 770评论 2 3
  • 适配器模式上一篇文章我们已经分析了Retrofit解析注解封装进ServiceMethod的流程,读者在这里要记住...
    andcoder阅读 657评论 0 2
  • 本文将顺着构建请求对象->构建请求接口->发起同步/异步请求的流程,分析Retrofit是如何实现的。 开始之前,...
    zhuhf阅读 1,619评论 0 10
  • 《庄子·山木》篇里讲了一个小故事: 一个人在乘船渡河的时候,前面一只船正要撞过来。 这个人喊了好几声没有人回应, ...
    赵肃江阅读 1,217评论 0 0