Retrofit

整体认识

Retrofit 用接口中的方法和注解来描述一个HTTP请求,用户只用关注接口如何描述这个请求,而不用关注内部的具体实现。它将网络请求中,封装Request 对象,解析Response对象等模板代码封装了起来,使得使用者只要描述做什么,而无需关心怎么做

内部网络请求部分依赖了OkHttp,这样,解析方法后,就是OkHttp的工作了,创建Request,解析Response,而在这两个过程,涉及到 数据(json, xml, 二进制(protobuf))与Java对象的转换,即数据序列化/反序列,这里Retrofit没有新造轮子,而是提供一个适配器,让用户选择合适 自己需求的工具,完美践行了对扩展开放的原则。

动态代理

关于这个设计模式,说下自己的理解。

代理,需要一个服务ServiceA,存在现有的类(代理目标类Obj)可以满足或满足部分需求,这时,假设想让User也拥有提供该服务的能力, 我们不是直接继承Obj, 而时将该服务抽象为一个接口ProvideServiceA,表示具备可以提供这个服务A,此时,真正提供具备这个服务实现类为Obj, 而我们的User也想拥有这份能力,可User又不但仅有这份能力,它还可能拥有A,B,C能力,故,它在是实现了 ProviderServiceA接口,但不是自己 实现,而是直接使用Obj来提供该服务。

简单说,就是声明了具备某个服务的能力后,内部提供该接口的实现类的实例,在方法中转发该消息到实例来完成。

可以发现,当有一个类可以提供某个服务后,我们不是简单继承它来表示具备有该服务能力,而是添加一个接口,表示是是实现该接口的类都具备有这份能力,这样, 我们会发现,我们需要额外引入一个接口类,这是不是Java不支持多继承导致的额外成本呢?

这个问题我无法判断。

在Java的概念中,接口表示一份契约,只是表示提供了某个服务,具体的实现延迟到了具体的实现类实现。

一个复杂的类,可以实现多个接口,它表示可以提供一系列服务的类,这些服务对外形成了一个整体的概念,而在实现方法中,又可以划分为子服务,在内部使用 其他自服务的实例来完成,以这个概念来看,我觉得这样的思考方法非常符合分治的思维,将大问题拆分为子问题,在子问题的实现上,可能又会继续拆分。 大问题和子问题之间的关系,完成依照它们的接口来完成,不会跟他们的子问题实现产生联系,这样,在查看代码时,使得我们很容易在了解这一个层次上类关系, 而不是陷入子问题实现的细节中。

好吧,扯得有点远了。
代理模式在印象中有一个案例是,在Android插件化中,对于Android四大组件类,我们会对他们进行插桩,在Manifest清单文件中 声明一个ProxyActivity,而在我们得插件类PluginActivity中,虽然我们实现了Activity得方法,但是其具体得实现是转发给ProxyActivity来是实现的, 比如 findViewById(),getAssertManager()方法,因为即使我们在插件模块中创建了Activity实例,我们也不能直接使用相关的方法,因为这个 Activity是没有在Android系统中注册,系统在处理Intent时是找不到该Activity。

而动态代理,区别于静态代理需要声明一个接口,在目标类和代理中都要是实现接口方法,动态代理不需要在编译时引入接口类,在调用代理类方法时,除了转发给 目标类对应方法,也可以添加自己的增强代码(日志、额外操作等)。

感叹细节实现

1
2
3
4
5
6
7
8
9
10
11
12
13
 
// 描述业务上需要Http方法
interface Service {
@GET("/") Call<ResponseBody> getBody();
}


// 用于创建一个Retrofit实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(server.url("/"))
.build();
// 为描述接口方法创建具体的代理实例
Service example = retrofit.create(Service.class);

创建一个代理实例

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
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
return (T)
// 返回一个代理实例,代理实现interfaces中的方法
// 所有方法都会通过InvocationHandler来实现
// 被代理的接口,仅是描述了要干什么,怎么干委托给了handler
// 原本接口的方法实现仅是 method.invoke(proxy, args),或者为abstract方法无法直接调用
// 而在handler中我们可以在基于该方法默认实现之上,可以做AOP类似的骚操作,比如修改参数、修改返回值,插入日志、甚至替换原来的实现
// 而在这个库中,只是提取方法中信息(主要是注解),创建一个ServiceMethod,而在这个方法后
Proxy.newProxyInstance(
service.getClassLoader(),
// 被代理额目标类,所有的方法都会转发给下面的Handler处理
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.
// 正常调用Object的方法
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method)
// 若是Java8提供的默认方法,直接调用
? platform.invokeDefaultMethod(method, service, proxy, args)
// 解析该方法并执行
: loadServiceMethod(method).invoke(args);
}
});
}

以下就是解析方法,执行方法了

解析方法

使用缓存避免解析多次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ServiceMethod<?> loadServiceMethod(Method method) {
// 解析方法费时,缓存下来
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;

// 这里为什么需要加锁呢?
// 在添加方法时,避免解析多次
synchronized (serviceMethodCache) {
// 假设由两个线程A,B都调用同一个方法,且该方法未解析
// A解析后修改map,退出
// B等到A释放锁后,再次检验该map,来确认是否要解析
result = serviceMethodCache.get(method);
if (result == null) {
// 见下解析方法2
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}

解析出信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
// 只是解析注解信息出来
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

// 判断方法的返回值
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
method,
"Method return type must not include a type variable or wildcard: %s",
returnType);
}
// 注意定义的接口时不能返回值为空的,
// 那么怎么不判断Kotlin的Unit? todo
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}

// Http方法具体实现,见下
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}

HttpServiceMethod.java

解析注解信息后,依据返回值类型,选择可用的 CallAdapter、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
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
Annotation[] annotations = method.getAnnotations();
// 获取返回值类型
Type adapterType;
adapterType = method.getGenericReturnType();


// 根据解析出来了方法返回值类型,选择合适的CallAdapter
// 何为CallAdapter, 将
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
// 返回确切的Response类型
// 比如在RxJava Complete会是Void.class, Observable<User>,则是User
Type responseType = callAdapter.responseType();


if (responseType == Response.class) {
throw methodError(method, "Response must include generic type (e.g., Response<String>)");
}

// OKHttp返回一个ResponseBody,选择一个Converter来转换

Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);

okhttp3.Call.Factory callFactory = retrofit.callFactory;
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
}

执行方法

在真正执行该方法时,跳到这里

1
2
3
4
5
6
7
@Override
final @Nullable ReturnT invoke(Object[] args) {
// 创建一个OkHttpCall
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
// 准备一切后,真正开始调用方法
return adapt(call, args);
}

比如在Rxjava中的 adapt方法实现

原本一个Call的返回只是一个Response,通过适配adapt,将其转换成我们想要的东西。

在RxJava中将Response创建了一个可以观察的源,

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

@Override
public Object adapt(Call<R> call) {

Observable<Response<R>> responseObservable =
isAsync ? new CallEnqueueObservable<>(call) : new CallExecuteObservable<>(call);

Observable<?> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}

// 不为空,还为其切换到响应的线程执行
if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
}

if (isFlowable) {
return observable.toFlowable(BackpressureStrategy.LATEST);
}
if (isSingle) {
return observable.singleOrError();
}
if (isMaybe) {
return observable.singleElement();
}
if (isCompletable) {
return observable.ignoreElements();
}
return RxJavaPlugins.onAssembly(observable);
}
}

总结

整体下来,看得挺懵逼的~

基本思路,解析方法上的信息后,尤其时返回值类型,判断其需要的CallAdapter,用于将请求返回值构建成对应的实例。默认下,返回一个定义Call,表示了一个 请求,包括发送一个request和返回一个Response,当RxJava的适配器时则返回一个Observable。

另一个就是Converter,将对象转换成http协议支持的类型,比如Json,普通文本,或数据流。转换时,包括创建请求时的requestBodyConverter以及responseBodyConverter。

无论是CallAdapter,还是Converter,两者都是可以配置补充的。当解析接口方法时,检查到其类型时,在Retrofit配置的Factory支持集合中选择合适的类型。