前言
源码解析看别人的就够了?我有几句话想说
这段时间在对项目进行组件化改造,期间又穿插了对各种设计模式的复习。于是想到别人的源码解析看了很多,一些作者写的也非常详细,包含了类图到时序图,但只有从自己出发感受一遍,才能体悟优秀框架蕴含的代码设计。网络框架是每个应用都会使用到的,故这次先拿Retrofit 2.0
开刀,发现其中的闪光点。
框架介绍与体悟
Retrofit adapts a Java interface to HTTP calls by using annotations on the declared methods to
define how requests are made. Create instances using {@linkplain Builder
the builder} and pass your interface to {@link #create} to generate an implementation.
以前翻看源码时,喜欢直接顺着方法调用查找,忽略了每个类中作者详细的注释。其实除了代码,注释也是一种方便我们学习框架的重要资源,尤其是优秀的框架。如同Retrofit
开头所介绍的,他与其他网络框架最与众不同的一点便是利用了注解——在给定的方法上添加注解,框架便会将接口转换为一个个HTTP请求。其次,我们也清晰了解到最终的调用分为两步:使用Builder
构建Retrofit客户端;传入我们定义的接口,并调用create
方法生成对应的请求实例。我们就会自然的产生两个疑问,即这两步具体是如何生成的?接下来,我们就从这两个疑问出发,进行源码的拆解
主要类拆解
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
MyApi api = retrofit.create(MyApi.class);
这是一段注释中的代码,也是我们大家都会使用的操作,这几个方法都在Retrofit.java
中,接下来就结合代码进行具体分析。
Retrofit实例构建
public static final class Builder {
//操作平台
//具体见后续分析
private final Platform platform;
//网络请求的工厂(Retrofit默认使用okhttp)
private @Nullable okhttp3.Call.Factory callFactory;
//网络请求的baseUrl
private HttpUrl baseUrl;
//数据转换器工厂的集合
//作用:放置数据转换器工厂
private final List converterFactories = new ArrayList<>();
//请求适配器工厂的集合
private final List adapterFactories = new ArrayList<>();
//回调方法执行器
private @Nullable Executor callbackExecutor;
//标志位
//作用:根据业务接口创建请求时是否提前解析注解
private boolean validateEagerly;
public Builder() {
this(Platform.get());
}
Builder(Platform platform) {
this.platform = platform;
// 提前添加build-in converter factory
converterFactories.add(new BuiltInConverters());
}
//构建Retrofit实例
public Retrofit build() {
//必须传入baseUrl
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//默认使用OkHttpClient作为网络请求器工厂
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//根据平台决定默认回调执行器
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
//创建了请求适配器工厂的保护性拷贝,并把默认请求适配器添加到列表末尾
List adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
//创建了数据适配器工厂的保护性拷贝
List converterFactories = new ArrayList<>(this.converterFactories);
//根据建造者模式配置的参数创建Retrofit实例
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
...
}
可以知道Retrofti
在这里使用了建造者模式完成实例的初始化配置,其中包含了以下重要的参数:
- 平台类型(platform)
- 网络请求器工厂(callFactory)
- 网络请求的baseUrl(baseUrl)
- 数据适配器工厂的集合(converterFactories)
- 请求适配器工厂的集合(adapterFactories)
- 回调执行器(callbackExecutor)
- 标志位(validateEagerly)
请求实例创建
//根据请求接口创建对应的网络请求
@SuppressWarnings("unchecked") //
public T create(final Class service) {
//验证类必须为接口,且不能继承于其他接口
Utils.validateServiceInterface(service);
//是否提前解析注解
if (validateEagerly) {
eagerlyValidateMethods(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, @Nullable Object[] args)
throws Throwable {
//如果Method源自于普通Object类,则定义一个普通的调用
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//若为Android平台,默认范围false
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//根据method加载对应的ServiceMethod,注意loadServiceMethod方法
ServiceMethod
可以知道创建请求时,采用了动态代理设计模式,最终得到了网络请求接口的实例。当设置了标志位后,则会提前加载注解的方法,从而在invoke
时确保serviceMethod
可以直接从缓存读取。
private void eagerlyValidateMethods(Class> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) {
loadServiceMethod(method);
}
}
}
不管哪种方式,都调用了loadServiceMethod
方法,我们继续进入方法体来看看
ServiceMethod, ?> loadServiceMethod(Method method) {
//首先从缓存中读取,若存在则直接返回
ServiceMethod, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
//同步锁
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//通过建造者模式创建serviceMethod,并存入缓存
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
此处出现了一个Retrofit全局的成员变量serviceMethodCache
,其实现由原来的LinkedHashMap
替换为了ConcurrentHashMap
,保证了并发情况下的线程安全。此处采用了享元设计模式,从而实现了serviceMethod
对象的共享而提高了系统性能
创建ServiceMethod
进入ServiceMethod
之后,我们还是继续从建造器出发进行分析
Builder(Retrofit retrofit, Method method) {
//传入Retrofit实例
this.retrofit = retrofit;
this.method = method;
//获取网络请求接口中的注解
this.methodAnnotations = method.getAnnotations();
//获取网络请求接口中的方法
this.parameterTypes = method.getGenericParameterTypes();
//获取网络请求接口中的注解内容
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
Builder的build
方法
public ServiceMethod build() {
//创建请求适配器
callAdapter = createCallAdapter();
//获取请求的responseType
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();
//根据方法中的注解,解析获取Http请求的方法
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
//获取当前方法的参数数量
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);
}
我们注解中的每一个value,最终也是利用retrofit
中的stringConverter
转化为了String
类型
创建请求适配器createCallAdapter()
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.");
}
//获取method中的注解
Annotation[] annotations = method.getAnnotations();
try {
//根据返回值类型和注解从Retrofit中获取对应的网络请求适配器
return (CallAdapter) 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);
}
}
接下来的方法调用为:retrofit.callAdapter()
->nextCallAdapter()
,我们着重分析nextCallAdapter
方法
public CallAdapter, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
//获取需要跳过的位次
int start = adapterFactories.indexOf(skipPast) + 1;
//遍历工厂集合,寻找匹配的工厂
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
至此,我们也获取到了指定的CallAdapter
,如未匹配则抛出异常
创建数据适配器createResponseConverter()
private Converter createResponseConverter() {
//获取方法注解
Annotation[] annotations = method.getAnnotations();
try {
//从retrofit实例中获取指定的适配器(具体流程类似CallAdapter的匹配,即遍历工厂集合寻找合适的工厂)
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);
}
}
最终获取给定工厂时,从实现Converter
接口的具体工厂中进行匹配(如GsonResponseBodyConverter
)。至此,ServiceMethod
的生成过程我们也已经分析完毕。显而易见,Converter.Factory
和CallAdapter.Factory
均使用了工厂模式
执行网络请求
我们知道调用create
方法创建的实例并非是真正网络接口创建的对象,而是动态代理对象Proxy.new ProxyInstance()
,可参见下面的截图
[图片上传失败...(image-7238c8-1545638741800)]
当调用apiService
的get
方法时会被动态代理对象拦截,并调用InvocationHandler
的invoke
方法,最终生成的是OkHttpCall
的包装对象(如可被RxJava2CallAdapter
包装为Observable
对象)
结合RxJava2CallAdapter
分析请求调用
直接进入最关键的adapt
方法
@Override public Object adapt(Call call) {
//根据是否同步创建对应的Observable
Observable> 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);
}
...
return observable;
}
此处举一个例子,若以此包装生成CallExecuteObservable
->BodyObservable
->FlowableFromObservable
调用
subscribe(observer)
时,subscribeActual()
被调用,层层传递至CallExecuteObserv[图片上传失败...(image-1a9275-1545638741801)]able
@Override protected void subscribeActual(Observer super Response> observer) {
//因为请求是一次性的,所以为每一个新的观察者克隆生成一个对象
Call call = originalCall.clone();
//回调给CallDisposable(该类包含了call.cancel等操作)
observer.onSubscribe(new CallDisposable(call));
boolean terminated = false;
try {
//划重点,终于执行了网络请求,并生成了返回数据对象response
Response response = call.execute();
if (!call.isCanceled()) {
//回调onNext()
observer.onNext(response);
}
if (!call.isCanceled()) {
terminated = true;
//订阅完成
observer.onComplete();
}
} catch (Throwable t) {
Exceptions.throwIfFatal(t);
if (terminated) {
RxJavaPlugins.onError(t);
} else if (!call.isCanceled()) {
try {
observer.onError(t);
} catch (Throwable inner) {
Exceptions.throwIfFatal(inner);
RxJavaPlugins.onError(new CompositeException(t, inner));
}
}
}
}
随着call.execute()
被调用,Response
被向下层层传递,最终整个订阅流程完成。所以,只有最后调用subscribe()
时,才会真正触发网络请求。
总结
不得不说,Retrofit
是一个非常优秀的框架,其中对于设计模式的应用可谓是炉火纯青,囊括了建造者、动态代理、享元、策略(生成platform对象时用到)、工厂等等。并且,创意性地将网络请求抽象为Java
接口,在接口中用注解配置请求参数,再利用动态代理把接口重新解析为网络请求。此次分析的Retrofit
整体的代码逻辑非常清晰,源码比较容易跟,希望自己也能继续坚持,深挖更多开源框架中的代码设计之美