透过Retrofit使用看其源码设计模式

前言

这篇文章我将从Retrofit的基本用法出发,透过其使用步骤,一步步的探究Retrofit的实现原理及其源码的设计模式。这篇文章可能会将Retrofit中用到的设计模式和其实现原理穿插着写,所以各位同学也可以选择性的阅读。而对于Retrofit具体使用还不太清楚的同学可以去看的另一篇文章Retrofit2的使用介绍

Retrofit基本用法

我以用户登录作为示例:

声明接口

首先我们先定义一个登录服务接口LoginService,如下:

1
2
3
4
5
public interface LoginService {
@FormUrlEncoded
@POST("login")
Call<String> login(@Field("username") String name, @Field("password") String password);
}

创建Retrofit对象

1
2
3
4
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://ittiger.cn")
.addConverterFactory(GsonConverterFactory.create())
.build();

发起请求

1
2
3
LoginService service = retrofit.create(LoginService.class);
Call<User> call = service.login("user", "pwd");
call.execute()或call.enqueue()

Retrofit关键类

在讲Retrofit实现原理之前,我先说下Retrofit里面涉及到几个关键类都是干什么用的

  1. Retorift: 负责配置请求过程中的基本参数,如:请求地址,结果转换器,自定义OKHttpClient等,同时还会生成请求接口对象
  2. Call: 网络请求执行者(Retrofit.Call),比如:上面示例中最后调用login方法得到的Call对象就是此接口的实例
  3. OkHttpCall: 此类是Retrofit.Call接口的实现,示例中最后调用login方法得到的Call对象就是此类的实例。但是其底层网络请求执行都是通过OkHttp.Call接口间接执行的,也就是说OkHttpCall是对OkHttp.Call网络请求功能的封装。
  4. Converter & Converter.Factory: 分别负责网络请求结果转换以及生成Converter转换器
  5. CallAdapter & CallAdapter.Factory: 分别负责对Retrofit.Call实例(OkHttpCall)进行适配及生成CallAdapter适配器
  6. Platform: 确定Retrofit当前运行平台,以及确定当前平台默认的的CallAdapter.FactoryExecutor
  7. ExecutorCallAdapterFactory: Android平台下的默认CallAdapter.Factory实现
  8. ServiceMethod: 解析接口服务所有注解、生成请求对象Request、解析请求结果Response
  9. ParameterHandler: 服务接口方法(login())参数解析处理器,配合ServiceMethod进行服务接口参数注解解析
  10. RequestBuilder: 根据参数和URL构造请求需要的OkHttp.Request对象

以上就是Retrofit源码实现中比较关键的10个类及其相关作用

使用流程 >> 实现 >> 设计模式

Builder模式创建Retrofit

Retrofit场景

1
2
3
4
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://ittiger.cn")
.addConverterFactory(GsonConverterFactory.create())
.build();

上面代码的对象创建方式看着是不是似曾相识,看着很眼熟,没错,Android里面的Dialog的创建就是使用的这种方式:Builder模式

Builder模式定义

将一个复杂对象的构建与它的表示分离,使得同样的构建可以创建不同的表示

Builder模式使用场景

  1. 相同的方法不同的执行顺序产生不同的结果
  2. 多个部件都可以装配到一个对象中,但是产生的结果不同

Builder模式类图

Retrofit中的Builder模式

  1. Retrofit中的Builder模式是简化版的Builder模式,省略了抽象建造者和指挥者
  2. 不同的配置会对Retrofit产生不同的影响,如果通过addCallAdapterFactory()配置CallAdapterFactory和不配置CallAdapterFactory会对Retrofit产生完全不同的影响。
  3. 如果Retrofit中使用构造方法的方式创建对象,则需要实现多个不同参数的构造方法,而使用构造方法创建对象时如果参数太多,很多时候参数代表的意思是不太理解的,总归来说就是创建过程不直观。

Builder模式优缺点

  • 优点:
    1. 不需要知道产品内部的组成细节,产品与创建过程解耦
    2. 分步组装产品,使得产品的创建过程更精细更清晰
    3. 容易扩展,新产品只需要新建一个建造者即可
  • 缺点:
    1. Builder模式创建的产品差异性小,使用范围受限制
    2. 不同的产品会产生多个建造者和指挥者

Retrofit创建流程 >> Platform

在创建Retrofit过程中有这样一行代码:

1
2
3
Retrofit retrofit = new Retrofit.Builder()
...
.build();

从代码可以看到在创建Retrofit时得先根据Retrofit.Builder内部类的默认构造方法Retrofit.Builder()创建一个Builder对象,所以我们来看看这个默认构造方法里都做了些什么事:

1
2
3
public Builder() {
this(Platform.get());
}

OK,我们再来看看我们前面说到的Platform这个平台类的静态方法get()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//静态实例对象,类加载就确定了
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();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("org.robovm.apple.foundation.NSObject");
return new IOS();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
...
}

通过上面的代码我们可以很明确的知道,在Platform类加载的时候它就通过反射的机制确定了当前运行的平台是属于哪一个,是Android,是Java8还是IOS,并生成对应的平台类的实例,get()方法是用来获取当前的平台类的实例。

目前,我们只关注Android平台下的Platform实例,我们也来看看Android平台类中做了些什么:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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 {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}

可以看到Android类中重写了Platform类的两个方法defaultCallbackExecutor()defaultCallAdapterFactory(Executor callbackExecutor)

  1. 前者就是用来返回当前平台下默认的Executor,这Android平台下就是MainThreadExecutor这个类的实例,可以看到这个执行器主要就是用来进行线程切换的,因为我们知道安卓平台下所有的UI操作都必须在UI线程中执行。
  2. 后者就是用来返回当前平台下默认的CallAdapter.Factory
  3. 当然你也可以不使用这两个默认值,都可以在创建Retrofit过程中自定义配置自己需要的相关实例

Retrofit创建流程 >> ExecutorCallAdapterFactory

看完Platform之后紧接着我们再来看看Android平台下默认的CallAdapter.Factory实现ExecutorCallAdapterFactory都做了些什么,这里只贴关键代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public interface CallAdapter<T> {
abstract class Factory {
public abstract CallAdapter<?> get(Type returnType, Annotation[] annotations,
Retrofit retrofit);
...
}
}
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
final Executor callbackExecutor;//对应默认的MainThreadExecutor
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
@Override
public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
...
return new CallAdapter<Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public <R> Call<R> adapt(Call<R> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
...
}

大家看源码可以发现CallAdapter.Factory工厂是通过get()方法来创建CallAdapter的,所以ExecutorCallAdapterFactory关键代码也是在get()方法的实现上,上面的代码中我们可以看到get()方法返回一个CallAdapter实例,这就是我前面介绍关键类作用时说到的CallAdapter.Factory主要负责生成CallAdapter的实现。

该类中,我们从其类的命名以及代码实现结构上来看,ExecutorCallAdapterFactory其实也使用了一种设计模式,那就是工厂方法模式,其实Retrofit中还有一个地方也使用了工厂方法模式,那就是Converter & Converter.Factory它的实现方式和CallAdapter & CallAdapter.Factory是一样样的。

工厂方式模式(创建CallAdapter & Converter)

本文我就已CallAdapter进行举例,看懂CallAdapter的创建原理之后,再看Converter的创建也就比较简单,都是一样的道理。

Retrofit场景

Retrofit中使用工厂方式模式的场景我在前面讲ExecutorCallAdapterFactory实现的时候已经讲过了,这里就不重复举例了,大家可以对照着源码看下。

工厂方法模式定义

一个用于创建对象的接口,让子类决定实例化哪个类

工厂方法模式使用场景

  1. 不需要知道其具体的类名,只需要知道生成它的工厂
  2. 一个类通过其子类来决定创建哪个对象

工厂方法模式类图

Retrofit中的工厂方法

  1. Retrofit中使用工厂方法模式可以讲CallAdapter的创建与具体实现充分解耦,对于创建我们只需要知道其工厂即可,不需要关注是如何实现
  2. 所以我们可以通过addCallAdapterFactory()addConverterFactory()很方便的自定义我们自己所需要的适配器工厂和数据转换工厂
  3. 通过addCallAdapterFactory()可以很方便的让Retrofit支持RxJava特性,而通过addConverterFactory()可以自定义配置们想要的转换器,让我们可以将请求数据结果转换成我们想要的任意类型。

这些就是Retrofit使用工厂方法模式带来的好处。

工厂方法模式优缺点

  • 优点
    1. 只关注产品工厂即可,不需要关注产品如何创建,由工厂确定如何创建
    2. 扩展性好,新增产品时,只需要新增一个具体工厂和具体产品
  • 缺点
    1. 新增产品时,需要新增具体工厂和具体产品类,使系统变得庞大
    2. 系统中加入抽象层,增加了系统的抽象性和理解难度

适配器模式 >> CallAdapter

Retrofit场景

先来看看CallAdapterRetrofit中的使用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface CallAdapter<T> {
public Type responseType();
public <R> Call<R> adapt(Call<R> call);
}
//ExecutorCallAdapterFactory中生成CallAdapter实例
return new CallAdapter<Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public <R> Call<R> adapt(Call<R> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};

前面讲到ExecutorCallAdapterFactory会生成一个CallAdapter实例。而CallAdapter这个名字看着是不是也很眼熟,也有种似曾相识的感觉,没错,CallAdapter与我们在Android中使用ListViewRecyclerView时经常用到的各种Adapter一样也是一个适配器。

CallAdapter是来适配什么的呢?

还记得前面介绍关键类的时候说到的OkHttpCall吗?CallAdapter就是来适配OkHttpCall实例的,结合上面的代码来说的话在调用CallAdapter.adapt方法时OkHttpCall实例会作为参数传递给adapt方法从而交给CallAdapter去进行适配。

在我前面举的登录示例中,我们调用login()方法得到的Call实例就是CallAdapter适配OkHttpCall之后得到的一个新Call实例对象,至于为什么是这样,我后面会一一讲解,各位看官不要离开

所以Retrofit在这个地方又使用了一种设计模式:适配器模式

适配器模式定义

将一个类的接口变成客户端所需要的另一个接口,从而使原本因接口不匹配而无法一起工作的两个类可以在一起工作

适配器模式使用场景

  1. 需要复用现有类,而现有类不符合系统需求
  2. 需要一个统一的输出接口,而输入端类型不可预知

适配器模式类图

Retrofit中的适配器模式

1
2
3
4
5
6
7
8
9
10
//ExecutorCallAdapterFactory中生成CallAdapter实例
return new CallAdapter<Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public <R> Call<R> adapt(Call<R> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};

Android平台下默认的CallAdapter会将OkHttpCallMainThreadExecutor两个实例对象适配成一个新的Call实例,这个新的Call实例在执行过程中就具备了切换到UI线程的功能。

Retrofit在这个地方为什么要使用适配器模式将OkHttpCall进行适配了,直接拿过来用不就可以了吗?

前面讲过OkHttpCall仅仅只是对OkHttp.Call执行网络请求操作的封装,没有其他功能,也就是说OkHttpCall也只有网络请求的功能,而Retrofit是支持多个平台的(安卓,Java8,IOS,甚至包括支持RxJava特性),而不同的平台可能具有不同的特性。

如果在请求过程中需要用到这些特性的话,那么单靠OkHttp.Call是无法完成的,而如果在其他地方柔和进这些特性的支持可能就会使得框架结构不那么严谨平台解耦性比较差,甚至有可能会增加更多的接口。

Retrofit通过使用适配器模式将平台特性与OkHttpCall适配成一个最终我们需要的Call实例,这样的话我们在使用过程中只需要关注最后拿到的Call对象,而不需要关注底层这个Call实例到底是什么样的,这也就为我们支持更多的特性提供了可能。比如对RxJava特性的支持,我们只需要提供一个支持RxJava特性的CallAdapter适配器即可,所以我们就可以通过addCallAdapterFactory()配置我们提供的支持RxJava特性的CallAdapter.Factory

适配器模式优缺点

  • 优点
    1. 复用性好,引入适配器类来重用适配者类,无需修改原有代码
    2. 增加类的透明性,将适配过程封装在适配器类中,对使用者来说相对透明
    3. 灵活性扩展性好,通过配置可以随时更换适配器
  • 缺点
    1. 使用适配器会使系统整体不好把握,调的是A接口,却被适配成了B接口的实现

静态代理模式 >> ExecutorCallbackCall

Retrofit场景

还是先来看看Retrofit中使用ExecutorCallbackCall的场景

1
2
3
4
5
6
7
//ExecutorCallAdapterFactory中生成CallAdapter实例
return new CallAdapter<Call<?>>() {
...
@Override public <R> Call<R> adapt(Call<R> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};

在上面CallAdapter实现中,可以发现它将OkHttpCall适配成了一个新的Call实例:ExecutorCallbackCall,所以我们接着看看ExecutorCallbackCall的具体实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;//Android平台下的Executor:MainThreadExecutor
final Call<T> delegate;//网络实际执行者OkHttpCall实例
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
//Android平台下此处进行了线程切换
callbackExecutor.execute(new Runnable() {
@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) {
//Android平台下此处进行了线程切换
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
@Override public boolean isExecuted() {
return delegate.isExecuted();
}
@Override public Response<T> execute() throws IOException {
return delegate.execute();
}
@Override public void cancel() {
delegate.cancel();
}
@Override public boolean isCanceled() {
return delegate.isCanceled();
}
@SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
@Override public Call<T> clone() {
return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
}
@Override public Request request() {
return delegate.request();
}
}
}

可以看到我们通过login()方法拿到Call实例(也就是ExecutorCallbackCall)之后,在执行网络请求时,在ExecutorCallbackCall的实现中其实都是将具体操作委托给OkHttpCall在执行。所以RetrofitExecutorCallbackCall中又使用了一种设计模式:静态代理模式

静态代理模式定义

为其他对象提供一种代理以控制对这个对象的访问

静态代理模式使用场景

无法访问或不想直接访问某个对象

静态代理模式类图

Retrofit中的静态代理

Retrofit中使用ExecutorCallbackCall代理OkHttpCall具体请求操作,可以将Call的使用与底层实现进行解耦,不用关心底层具体请求接口的实现,所以如果将来出现了一个比OkHttp更好的网络请求库,我们完全可以将OkHttp替换掉,即便这样也不会影响外部API接口在项目中的使用。

静态代理的优缺点

  • 优点
    1. 协调调用者与被调用者,降低系统耦合度
    2. 减小外部接口与内部接口实现的关联,降低耦合
  • 缺点
    1. 委托对象与代理对象需要实现相同的接口,当接口类增加方法时,除了所有实现类需要增加该方法外,所有代理类也需要实现此方法,增加了维护难度
    2. 一个代理类只能代理一种类型的对象

动态代理 >> Retrofit.create()

先看下Retrofit.create()方法的具体实现代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public <T> T create(final Class<T> service) {
return (T) Proxy.newProxyInstance(service.getClassLoader(),
new Class<?>[] { service }, new InvocationHandler() {
private final Platform platform = Platform.get();
@Override
public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
...
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}

相信很多人在刚开始用Retrofit时都会有一点疑问,我们明明声明的是接口,为什么通过create()方法就能创建出一个对象实例呢?
通过上面的实现源码我们找到了答案,那就是使用了JDK中提供的动态代理机制,它会在运行过程中为我们声明的服务接口动态的创建出一个代理对象,以便实现我们的请求操作。我个人认为这是Retrofit框架得以实现的一个核心之处,另外一个核心之处就是其完善的注解机制,关于其注解本文就不说,主要就是一些注解的声明和解析,比较简单,感兴趣的可以去看看。

上面的源码中我们可以看到,运行过程中得到服务接口的代理对象之后,当我们调用login()这样的接口方法时,其实真实执行的是上面源码中写的invoke()方法,所以我们调用login()方法时其实是执行了如下三步:

  1. 根据反射得到接口方法Method对象生成对应的ServiceMethod对象,该对象会对该声明方法上的所有方法注解、参数注解进行解析以得到一个请求所需要的所有信息
  2. 得到ServiceMethod对象之后,会根据该对象和方法调用时传递的参数生成OkHttpCall对象,也就是具体的网络实施者
  3. OkHttpCall作为CallAdapter适配器中adapt()方法的参数传递给CallAdapter进行适配,最后得到我们所需要的ExecutorCallbackCall对象,也就是调用login()方法得到的Call实例对象

动态代理使用场景

静态代理特点一个代理对应一种类型,如果有多个类需要代理则需要多个代理,而且维护成本高,而动态代理就是来解决此类问题

动态代理特点

运行期由JVM通过反射机制动态生成,可以代理多种类型,代码复用性高。但是只能代理Java接口,不能代理Java实现类。

Call.enqueue() & Call.execute()实现

前面从Retrofit的配置、创建、调用接口方法得到Call实例,基本用法都已经讲的差不多了,现在我们来看基本用法的最后一步Call.enqueue() & Call.execute()

前面讲过调用接口方法比如login()时,Android平台下默认得到的是ExecutorCallbackCall实例,而ExecutorCallbackCall实例中执行网络请求的实际上又是OkHttpCall,所以我们来看OkHttpCall中的Call.enqueue() & Call.execute()两个方法的实现,我以Call.enqueue()为例,另外一个大家可以自己去看看

下面是该方法实现的关键代码:

OkHttpCall.enqueue()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@Override public void enqueue(final Callback<T> callback) {
...
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) {
failure = creationFailure = t;
}
}
}
...
//又讲网络执行转交给okhttp3.Call实例来执行
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
try {
//将okhttp3.Response结果包装成Retrofit中的结果对象Response
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
...
}
private void callFailure(Throwable e) {
...
}
private void callSuccess(Response<T> response) {
...
}
});
}

前面介绍关键类时说过OkHttpCall底层网络执行其实是OkHttp.Call在执行,从上面的代码我们就可以看出来(代码关键地方我加了注释),上面代码关键第一步是先创建一个okhttp3.call实例,所以我们同样看看创建okhttp3.call实例的代码是怎么实现的

1
2
3
4
5
6
private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
...
return call;
}

通过上面的createRawCall()方法实现我们可以发现,它会首先通过ServiceMethod.toRequest()方法生成一个OkHttp.Request对象(这部分代码比较简单,我就不细说了),然后根据ServiceMethod中的成员变量CallFactory创建一个okhttp3.Call实例。但是这个CallFactory是怎么来的呢?其实我们可以猜到这个CallFactory实例就是OkHttpClient实例。但是我们还是看看ServiceMethod的创建过程

ServiceMethod创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//在Retrofit.create()方法实现的第一步就是通过loadServiceMethod()方法创建ServiceMethod,这是其实现
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
//下面是ServiceMethod相关关键代码
final class ServiceMethod<T> {
final okhttp3.Call.Factory callFactory;
ServiceMethod(Builder<T> builder) {
this.callFactory = builder.retrofit.callFactory();
this.callAdapter = builder.callAdapter;
this.baseUrl = builder.retrofit.baseUrl();
this.responseConverter = builder.responseConverter;
...
}
static final class Builder {
public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
...
}
public ServiceMethod build() {
//创建CallAdapter
callAdapter = createCallAdapter();
//得到请求结果返回类型,接口方法声明
responseType = callAdapter.responseType();
...
//创建得到Converter结果转换器
responseConverter = createResponseConverter();
...
return new ServiceMethod<>(this);
}
}
}

通过上面的ServiceMethod创建过程的相关代码可以看出,ServiceMethod中的实例变量callFactory其实是调用Retrofit.callFactory()方法所得,大家也可以看看上面我注释的CallAdapterConverter的创建过程,所以我们再来看看这个方法的实现

1
2
3
public okhttp3.Call.Factory callFactory() {
return callFactory;
}

可以看到该方法只是返回了Retrofit中的callFactory实例,同样,我们再来看看Retrofit中的callFactory实例是怎么来的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public final class Retrofit {
private final okhttp3.Call.Factory callFactory;
...
Retrofit(okhttp3.Call.Factory callFactory, ...) {
this.callFactory = callFactory;
...
}
public static final class Builder {
private okhttp3.Call.Factory callFactory;
...
public Builder client(OkHttpClient client) {
return callFactory(checkNotNull(client, "client == null"));
}
public Builder callFactory(okhttp3.Call.Factory factory) {
this.callFactory = checkNotNull(factory, "factory == null");
return this;
}
public Retrofit build() {
...
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
...
return new Retrofit(callFactory, ...);
}
}
}

通过上面的代码,我们可以看出Retrofit中的callFactory实例就是我们使用的OkHttpClient实例,所以这就验证了我们前面猜测的serviceMethod.callFactory就是OkHttpClient实例的猜想。

Ok,回到我们前面将的OkHttpCall.equeue()方法的实现流程上来。

请求结果解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
try {
//将okhttp3.Response结果包装成Retrofit中的结果对象Response
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
...
}

创建完okhttp3.call实例之后,调用该实现的equeue()方法开始执行网络请求,请求执行完成之后,会调用parseResponse方法,我们来看看这个方法实现的关键代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
...
//上面省略的这段代码是对请求失败时的结果处理,大家可以自行查看源码
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
catchingBody.throwIfCaught();
throw e;
}
}

这个方法中,当请求成功时,会调用serviceMethod.toResponse()这个方法,我们来看看这个方法又做了哪些事情:

1
2
3
T toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}

很明显,上面方法中就直接调用了ServiceMethod中的Converter实例进行结果转换,也就是说在这个地方Retrofit会帮我们把网络请求结果转换成我们所需要的类型,转换成功之后会调用Response.success(body, rawResponse)将转换后的结果包装成Retrofit中的Response对象。

获取配置的Converter

问题又来了,上面的Converter是怎么来的呢?

在前面给出的ServiceMethod创建过程的代码块中,我对ServiceMethod中创建Converter实例的代码进行了注释,我们再回过头来看看这段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//ServiceMethod.Buibler中的方法
private Converter<ResponseBody, T> createResponseConverter() {
...
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);
}
}
//Retrofit中的方法
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast,
Type type, Annotation[] annotations) {
...
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
return (Converter<ResponseBody, T>) converter;
}
}
...
throw new IllegalArgumentException(builder.toString());
}

通过上面的代码我们可以看到会从RetrofitconverterFactories转换器工厂集合中去查找当前接口方法对应的转换器工厂。其实这也告诉我们可以在创建Retrofit时配置多个Converter.Factory转换器工厂,也就是说我们一个接口服务中如果声明的多个接口方法的返回值不一样时,我们可以针对性的配置多个不一样的结果转换器工厂去进行结果解析,而不用为了保持结果类型一致对接口进行其他处理。

上面创建ServiceMethod时得到CallAdapter的过程与得到Converter的过程基本一样,我就不赘述了。

到这里,Retrofit的实现原理、实现流程以及其源码实现过程中用到的设计模式就介绍完了。

内容好长,时间好长~~~~


原创文章,本文采用知识共享署名 2.5(中国大陆许可协议)进行许可,欢迎转载,但转载请注明来自ittiger.cn,并保证转载后文章内容的完整性。本人(laohu)保留所有版权相关权利。



评论