//代理委托类
class ProxyHandler(private val proxyObject:Any): InvocationHandler {
//代理方法,p1为目标类方法、p2为目标类参数。调用proxyObject任一方法时都会执行invoke
override fun invoke(p0: Any, p1: Method, p2: Array<out Any>): Any {
//执行Dao各个方法(CRUD)
val result = p1.invoke(proxyObject,p2)
//上报
post()
return result
}
}
}
//此处规范上应该使用基于接口而非实现编程。如果要替换Dao通过接口编程可提高扩展性
val dao:Dao = DaoProxy().createProxy() as Dao
dao.insert()
dao.update()
其中Proxy是JDK中用于创建动态代理的类,InvocationHandler是一个委托类, 内部的invoke(代理方法)方法会随着目标类(Dao)任一方法的调用而调用,所以在其内部实现上报操作即可消除大量模版代码。
动态代理与静态代理核心思想一致,区别是动态代理可以在运行时通过反射动态创建一个切面(InvocationHandler#invoke),用来消除模板代码。喜欢思考的同学其实已经发现,代理模式符合面向切面编程(AOP)思想,而代理类就是切面
================================================================================
2.2小节有提到可以通过retrofit.create()创建ApiService,跟一下retrofit的create()
#Retrofit.class
public T create(final Class service) {
//第一处
validateServiceInterface(service);
return (T) Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
//第二处
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
...
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
create()大致可以分为两部分:
-
第一部分为validateServiceInterface()内容,用来验证ApiService合法性,比较简单就不多描述,感兴趣的同学可自行查看。
-
第二部分就是invoke(),通过3.2小节可知这是一个代理方法,可通过调用ApiService中的任一方法执行,其中参数method和args代表ApiService对应的方法和参数。返回值中有一个isDefaultMethod,这里如果是Java8的默认方法直接执行,毕竟我们只需要代理ApiService中方法即可。经过反复筛选最后重任落在了loadServiceMethod,这也是Retrofit中最核心的一个方法,下面我们来跟一下
#Retrofit.class
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
大致就是对ServiceMethod做一个很常见的缓存操作,这样做的目的是为了提升运行效率,毕竟创建一个ServiceMethod会用到大量反射。创建ServiceMethod对象是通过其静态方法parseAnnotations实现的,再跟一下这个方法:
#ServiceMethod.class
static ServiceMethod parseAnnotations(Retrofit retrofit, Method method) {
//第一步
RequestFactory requestFactory =
RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
...
//第二步
return HttpServiceMethod.parseAnnotations(retrofit,
method, requestFactory);
}
第一步:
通过RequestFactory的parseAnnotations()解析method(ApiService的method)中的注解信息,具体代码很简单就不再贴了。不过需要注意这一步只是解析注解并保存在RequestFactory工厂中,会在请求时再通过RequestFactory将请求信息做拼装。
第二步:
调用HttpServiceMethod的parseAnnotations创建ServiceMethod,这个方法很长并且信息量很大,下一小节我再详细描述,此处你只需知道它做了什么即可。其实到这方法调用链已经很绕了,我先帮大家捋一下 HttpServiceMethod其实是ServiceMethod的子类,Retrofit动态代理里面的loadServiceMethod就是HttpServiceMethod类型对象,最后来看一下它的invoke()方法。
#HttpServiceMethod.class
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
创建了一个OkHttpCall实例,它内部其实就是对OkHttp的一系列操作,这里先按住不表后面我会再提到。把关注点切到返回值,返回的Call对象没做任何操作,而是传入到adapter()方法一并返回来,字面意思应该是一个适配操作,那究竟如何适配?这里再埋一个伏笔与3.1结尾相呼应,下一小节我们再一一揭开。
动态代理讲完了,那么它解决了什么问题?
假如不使用代理模式,那关于ApiService中方法注解解析的操作势必会浸入到业务当中,一旦对其修改就有可能影响到业务,其实也就是也违背了我们前面所说的门面模式和迪米特法则,通过代理模式做一个切面操作(AOP)可以完美规避了这一问题。可见这里的门面模式和代理模式是相辅相成的
Retrofit事先都不知道ApiService方法数量,就算知道也避免不了逐一解析而产生大量的模版代码,此时可通过引入动态代理在运行时动态解析 从而解决这一问题。
4. ReturnT、ResponseT做一次适配的意义何在?
============================================================================================
ResponseT、ReturnT是 Retrofit 对响应数据类型和返回值类型的简称
===================================================================================
上一小节我们跟到了adapter(),这是一个抽象方法,其实现类是通过HttpServiceMethod的parseAnnotations创建的,继续跟下去:
#HttpServiceMethod.class
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
Annotation[] annotations = method.getAnnotations();
Type adapterType;
//1.获取adapterType,默认为method返回值类型
if (isKotlinSuspendFunction) {
Type[] parameterTypes = method.getGenericParameterTypes();
Type responseType =
Utils.getParameterLowerBound(
0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
// Unwrap the actual body type from Response.
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
} else {
}
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
adapterType = method.getGenericReturnType();
}
//2.创建CallAdapter
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
//3.创建responseConverter
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
//4.创建HttpServiceMethod类型具体实例
if (!isKotlinSuspendFunction) {
return new HttpServiceMethod.CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
}
//兼容kotlin suspend方法
else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new HttpServiceMethod.SuspendForResponse<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call>) callAdapter);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new HttpServiceMethod.SuspendForBody<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call>) callAdapter,
continuationBodyNullable);
}
}
注释1:获取adapterType,这里的adapter指的是Retrofit构建时通过addCallAdapterFactory()添加的类型,如果添加的是RxJava那adapterType便是Observable。默认是method返回值,同时也会做kotlin suspend适配
注释2:创建callAdapter,暂时掠过,下面详细描述
注释3:创建responseConverter,暂时掠过,下面详细描述
注释4:这里会创建具体的HttpServiceMethod类型实例,总共有三种类型CallAdapted、SuspendForResponse、SuspendForBody,第一种为默认类型,后两种可兼容kotlin suspend。内部主要做的事情其实很简单,就是通过内部的adapter()调用callAdapter->adapter(),具体代码就不贴了,感兴趣的自行查看
4.2 如何管理callAdapter、responseConverter?
==================================================================================================
创建创建callAdapter
#HttpServiceMethod.class
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
...
}
通过retrofit#callAdapter()获取CallAdapter,继续跟
#Retrofit.class
public CallAdapter callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
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++) {
//通过returnType在callAdapterFactories获取adapter工厂,再get adapter
CallAdapter adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
...
}
先通过returnType在callAdapterFactories获取adapter工厂,再通过工厂get()获取CallAdapter实例。callAdapterFactories是3.1结尾build()中初始化的,通过platform添加默认类型,也可以通过addCallAdapterFactory()添加RxJava之类的适配器类型。
这里用到了两个设计模式适配器跟策略
- 适配器模式
返回的CallAdapter其实就是Call的适配器,假如你想让Retrofit配合RxJava使用,常规方式只能在业务中单独创建Observable并与Call融合,关于Observable与Call融合(适配)其实是与业务无关的,此时可以引入适配器模式将Call适配成Observable,将适配细节从业务层挪到Retrofit内部,符合迪米特法则
- 策略模式
通过ReturnT获取对应的CallAdapter,如果ReturnT是Call那获取的是DefaultCallAdapterFactory创建的实例,如果是Observable则获取的是RxJava2CallAdapterFactory创建的实例。假如想新增一种适配器只需明确ReturnT,创建对应工厂再通过addCallAdapterFactory添加即可,Retrofit会通过ReturnT自动寻找对应CallAdapter,符合开闭原则(扩展开放)
创建responseConverter
关于responseConverter其实是做数据转换的,可以将ResponseT适配成我们想要的数据类型,比如Gson解析只需通过addConverterFactory添加GsonConverterFactory创建的Converter实例即可 具体添加、获取流程与CallAdapter基本一致,感兴趣的同学可自行查看
====================================================================
到上一小结我们已经创建了所有需要的内容,再回到HttpServiceMethod的invoke,这里会将OkHttpCall传入到adapt执行并返回,HttpServiceMethod的实现类的adapter会执行对应CallAdapter的adapter我们就取默认的CallAdapter 即DefaultCallAdapterFactory通过get获取的CallAdapter,代码如下:
DefaultCallAdapterFactory.class
public @Nullable CallAdapter get(
return new CallAdapter<Object, Call<?>>() {
@Override
public Type responseType() {
return responseType;
}
@Override
public Call adapt(Call call) {
return executor == null ? call : new DefaultCallAdapterFactory.ExecutorCallbackCall<>(executor, call);
}
};
}
内部adapt即ApiService method最终返回的ExecutorCallbackCall是OkHttpCall装饰类,最后可通过OkHttpCall的execute发起请求,代码如下:
#OkHttpCall.class
public Response execute() throws IOException {
okhttp3.Call call;
...
return parseResponse(call.execute());
}
OkHttp常规操作,再把关注点放到onResponse的parseResponse
#OkHttpCall.class
Response parseResponse(okhttp3.Response rawResponse) throws IOException {
...
T body = responseConverter.convert(catchingBody);
...
return Response.success(body, rawResponse);
}
responseConverter会对Body做一个适配,如果addConverterFactory添加了GsonConvert那解析操作就会在此处进行
至此Retrofit全部流程分析完毕
综上所述
-
Retrofit通过REST ful API从范式层面约束代码
-
通过门面模式设计ApiService可以让开发者更专注于业务
-
动态代理只是将功能代码从业务剥离,并解决了模板代码问题
-
ReturnT、ResponseT引入适配器模式可以让结果更加灵活
==============================================================
在这里我再分享一份由多位大佬亲自收录整理的Android学习PDF+架构视频+面试文档+源码笔记,高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料
这些都是我现在闲暇时还会反复翻阅的精品资料。里面对近几年的大厂面试高频知识点都有详细的讲解。相信可以有效地帮助大家掌握知识、理解原理,帮助大家在未来取得一份不错的答卷。
当然,你也可以拿去查漏补缺,提升自身的竞争力。
如果你有需要的话,只需 点击这里快速免费获取
本文在开源项目:Android开发不会这些?如何面试拿高薪! 中已收录,里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中...