本文目标
Retrofit的源码设计模式分析
1.Builder 设计模式
static {
OkHttpClient httpClient = new OkHttpClient.Builder()
// 添加日志打印
.addInterceptor(new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
Log.d("TAG", message);
}
}).setLevel(HttpLoggingInterceptor.Level.BODY))
.build();
Retrofit retrofit = new Retrofit.Builder()
// 主路径
.baseUrl("http://ppw.zmzxd.cn/index.php/api/v1/")
// 添加转换工厂
.addConverterFactory(GsonConverterFactory.create())
// 配置 OkHttpClient
.client(httpClient).build();
// 创建 ServiceApi
mServiceApi = retrofit.create(ServiceApi.class);
}
2.动态代理设计模式
public <T> T create(final Class<T> 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 {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
create()这个方法,个人认为 Retrofit 能做到解耦就是因为动态代理的设计模式用得好,这种模式我们也是经常用到,有很多的体现形式.
3.工厂设计模式
abstract class Factory {
/**
* Returns a {@link Converter} for converting an HTTP response body to {@code type}, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for
* response types such as {@code SimpleResponse} from a {@code Call<SimpleResponse>}
* declaration.
*/
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type,
Annotation[] annotations, Retrofit retrofit) {
return null;
}
/**
* Returns a {@link Converter} for converting {@code type} to an HTTP request body, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for types
* specified by {@link Body @Body}, {@link Part @Part}, and {@link PartMap @PartMap}
* values.
*/
public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return null;
}
/**
* Returns a {@link Converter} for converting {@code type} to a {@link String}, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for types
* specified by {@link Field @Field}, {@link FieldMap @FieldMap} values,
* {@link Header @Header}, {@link HeaderMap @HeaderMap}, {@link Path @Path},
* {@link Query @Query}, and {@link QueryMap @QueryMap} values.
*/
public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
}
工厂设计模式又分为:简单工厂模式,工厂方法模式,抽象工厂模式。addConverterFactory(GsonConverterFactory.create())
好处就不用说了吧?当然这个地方还影藏着另一种设计模式,如有不了解你可以点击标题进入相应的链接。
4.Adapter 适配器模式
public interface CallAdapter<T> {
// 返回请求后,转换的参数Type类型
Type responseType();
// 接口适配
<R> T adapt(Call<R> call);
}
我们都知道 Retrofit 是支持 RxJava 的,我们看下是怎么办到的:
final class RxJavaCallAdapter<R> implements CallAdapter<R, Object> {
RxJavaCallAdapter(Type responseType, @Nullable Scheduler scheduler, boolean isAsync,
boolean isResult, boolean isBody, boolean isSingle, boolean isCompletable) {
}
@Override public Type responseType() {
return responseType;
}
@Override public Object adapt(Call<R> call) {
OnSubscribe<Response<R>> callFunc = isAsync
? new CallEnqueueOnSubscribe<>(call)
: new CallExecuteOnSubscribe<>(call);
// 省略代码
OnSubscribe<?> func;
if (isResult) {
func = new ResultOnSubscribe<>(callFunc);
} else if (isBody) {
func = new BodyOnSubscribe<>(callFunc);
} else {
func = callFunc;
}
Observable<?> observable = Observable.create(func);
if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
}
return observable;
}
}
这里用自己的话总结就是 RxJavaCallAdapter 实现了 CallAdapter 目标接口,调用 adapt 方法把 Call 转换适配成了 Observable。再通俗一点就是我想要的是 RxJava 的 Observable 对象,但是我只有 Call 这个怎么办?所以采用适配器模式。
5.模板设计模式
abstract class ParameterHandler<T> {
abstract void apply(RequestBuilder builder, @Nullable T value) throws IOException;
static final class Query<T> extends ParameterHandler<T> {
private final String name;
private final Converter<T, String> valueConverter;
private final boolean encoded;
Query(String name, Converter<T, String> valueConverter, boolean encoded) {
this.name = checkNotNull(name, "name == null");
this.valueConverter = valueConverter;
this.encoded = encoded;
}
@Override void apply(RequestBuilder builder, @Nullable T value) throws IOException {
if (value == null) return; // Skip null values.
String queryValue = valueConverter.convert(value);
if (queryValue == null) return; // Skip converted but null values
builder.addQueryParam(name, queryValue, encoded);
}
}
}
不到 20 个类,23 种设计模式 Retrofit 运用占了一大半,像 观察者设计模式 、策略设计模式 ,享元设计模式、门面设计模式、单例设计模式、原型设计模式 、装饰设计模式 等等都在其源码中有体现。
2.基本流程
App
应⽤程序通过Retrofit
请求⽹络,实际上是使⽤Retrofit
接⼝层封装请求参数,之后由OkHttp
完成后续的请求。
在服务端返回数据之后,OkHttp
将原始的结果交给Retrofit
,Retrofit
根据⽤户的需求对结果进⾏解析。
2.核心原理
通过 Retrofit.create(Class)
⽅法创建出 Service interface
的实例,从⽽使得Service
中配置的⽅法变得可⽤。这是 Retrofit
代码结构的核⼼;
Retrofit.create()
⽅法内部使⽤了 Proxy.newProxyInstance()
⽅法来创建Service
实例。(通过在运⾏时访问代理对象的⽅式来间接访问⽬标对象)
然后这个Proxy.newProxyInstance()
方法有3个参数,
第1个参数:接口的classLoader
对象,
第2个参数:接口的class对象
,这里支持传数组class对象进去,不过具体到Retrofit
来说,是固定传⼊⼀个 interface
就好了,
第3个参数:InvocationHandler
这个接口的实现类对象,然后里面会实现其方法叫做invoke()
这个Proxy.newProxyInstance()
方法一写,运行的时候就能为我们生成一个代理对象了,可以理解为new了一个Interface对象给了我们
然后重点就是这个invoke()方法
了,当调用了接口中的方法的时候就会回调invoke
这个方法,该方法有这么几个参数
第1个参数: proxy
:接口的代理实现对象,(ApiService的实现类对象)
第2个参数:method
:调用的方法(getList方法)
第3个参数:args
:调用的方法的入参getList(@Path("id") groupId: Int,@Filed("page") page: Int)
返回值:就是定义接口中方法的返回值,是泛型,支持任意类型,ICall<List<User>>
这个方法内部会创建一个ServiceMethod
对象,其实就是解析请求方法的各种注解然后封装到 Retrofit
的RequestBuilder
中。
最后当我们主动发起⽹络请求的时候会调⽤okhttp
发起⽹络请求,
okhttp
的配置包括请求⽅式,URL等在Retrofit
的RequestBuilder
的build()
⽅法中实现,并发起真正的⽹络请求。
总结一下就是,
1.定义接口和接口中的方法
2.然后通过动态代理得到这个接口的代理对象
3.然后当调用了接口中的方法的时候就会回调invoke
这个方法,该invoke
方法会解析具体的网络请求方法上的所有东西(注解,参数,返回值)
4.解析完毕后会封装到对象中
5.最后利用okhttp去发起真正的网络请求
3.你从这个库中学到什么有价值的或者说可借鉴的设计思想?
Retrofit 内部合理地使⽤了多种优秀的设计模式进⾏封装解耦,提⾼了易⽤性和灵活性。下⾯我简单说⼀说:
1、创建Retrofit
实例:
使⽤建造者模式通过内部Builder
类建⽴了⼀个Retroifit
实例。call.enqueue(new retrofit2.Callback() { } )
:这就是观察者模式的⼀种变体,retrofit2.Callback()
就是观察者,⽽call
是被观察者。观察者会根据我们的Call
的反应来做出相应的变化。⽹络请求⼯⼚使⽤了⼯⼚⽅法模式
2、创建⽹络请求接⼝的实例:
⾸先,使⽤外观模式统⼀调⽤创建⽹络请求接⼝实例和⽹络请求参数配置的⽅法。然后,使⽤动态代理动态地去创建⽹络请求接⼝实例。接着,使⽤了建造者模式 & 单例模式创建了serviceMethod
对象。然后,使⽤了策略模式对serviceMethod
对象进⾏⽹络请求参数配置,即通过解析⽹络请求接⼝⽅法的参数、返回值和注解类型,从Retrofit对象
中获取对应的⽹络url地址、⽹络请求执⾏器、⽹络请求适配器和数据转换器。最后,使⽤了装饰者模式ExecuteCallBack
为serviceMethod
对象加⼊线程切换的操作,便于接受数据后通过Handler
从⼦线程切换到主线程从⽽对返回数据结果进⾏处理。
3、发送⽹络请求:
在异步请求时,通过静态代理对⽹络请求接⼝中⽅法的每个参数使⽤对应的ParameterHandler
进⾏解析。
4、得到响应并解析得到数据后,再切换线程:使⽤了适配器模式通过检测不同的Platform使⽤不同的回调执⾏器,然后使⽤回调执⾏器切换线程,这⾥同样是使⽤了装饰模式。
5、最后,就是交给开发者来处理响应结果。