Retrofit设计模式
本文主要介绍Retrofit用到的设计模式,包括代理模式,工厂方法模式,抽象工厂模式,适配器模式,建造者模式,策略模式。
1、Retrofit基本使用
1.1、定义Service
interface Service {
@Headers(
"Cache-Control: max-age=640000, max-stale=864000",
"Authorization: APPCODE " + APP_CODE,
)
@GET("/{path}")
fun getDate(
@Path("path") path: String,
@QueryMap() map: MutableMap<String, String>
): Observable<Any>
}
1.2、创建代理对象,执行请求
val executorService = Executors.newCachedThreadPool();
var okHttpClient = OkHttpClient.Builder().dispatcher(Dispatcher(executorService))
.addInterceptor label@{
Log.d(TAG, "getNetWork1: 数据请求发起线程 " + Thread.currentThread().name)
return@label it.proceed(it.request())
}
.addNetworkInterceptor(object : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
Log.d(TAG, "intercept: ------进行了网络请求" + Thread.currentThread().name)
var request = chain.request()
Log.d(TAG, "intercept: " + request.toString())
return chain.proceed(request)
}
}).cache(Cache(file, 10 * 1024 * 1024))
.build()
var retrofit = Retrofit.Builder().baseUrl(RetrofitActivity.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(okHttpClient)
//异步结果返回的线程。就是enqueue的caback所在线程,默认主线程。
.callbackExecutor(Executors.newCachedThreadPool())
.build()
// retrofit.callFactory().newCall()
var service = retrofit.create(Service::class.java)
service.getDate4(
path = "area-to-weather-date",
map = mutableMapOf<String, String>(
"area" to "丽江",
"areaCode" to "530700",
"date" to "20200319",
"need3HourForcast" to "1"
)
).observeOn(Schedulers.newThread()).subscribe {
Log.d(TAG, "onResponse: exec数据返回线程 " + Thread.currentThread().name + " ")
tvContent?.setText("" + it.toString())
}
2、Retrofit调用流程
调用流程 创建Service代理对象,调用Service中的方法,解析注解,构建RequestFactroy,这个用于创建request,解析注解包括解析方法注解,解析使用的请求方式,GET、POST请求,解析参数注解,传参如FieldMap注解,通过传入的CalladapterFactroy拿到CallAdapter,通过传入的ConvertFactroy拿到Convert,返回HttpServiceMethod的子类CallAdapted<>。
invoke创建OKhttpCall,执行同步和异步请求,使用上面解析完成的RequestFactroy创建Request,创建okhttp的call,执行请求,返回ResponseBody,body再通过转化为Response<JavaBean>,再通过callBack回调给RxJavaCalladapter处理成Observable对象,最终用Object接收,返回给动态代理中作为方法的返回值。
2.1、创建代理对象,解析注解。
// Retrofit
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
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 {
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
2.2、创建OkhttpCall
// HttpServiceMethod
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
2.3、以RxJava2CallAdapter为例,执行请求
final class RxJava2CallAdapter<R> implements CallAdapter<R, Object> {
@Override public Type responseType() {
return responseType;
}
@Override public Object adapt(Call<R> call) {
Observable<Response<R>> responseObservable = isAsync
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);
return observable;
}
}
final class CallEnqueueObservable<T> extends Observable<Response<T>> {
private final Call<T> originalCall;
CallEnqueueObservable(Call<T> originalCall) {
this.originalCall = originalCall;
}
@Override protected void subscribeActual(Observer<? super Response<T>> observer) {
Call<T> call = originalCall.clone();
CallCallback<T> callback = new CallCallback<>(call, observer);
observer.onSubscribe(callback);
call.enqueue(callback);
}
}
这里的Call是OKHttpCall,调用enqueue,执行真正的call请求,返回结果给CallEnqueueObservable 的callback,调用 observer.onNext(response)向下传递,包装成了Observable对象。
2.4、执行真正的请求
//OkHttp
public void enqueue(final Callback<T> callback) {
synchronized (this) {
try {
call = rawCall = createRawCall();
}
}
call.enqueue(
new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
response = parseResponse(rawResponse);
}
try {
callback.onResponse(OkHttpCall.this, response);
}
}
});
}
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
return call;
}
requestFactory.create(args)构建request,将方法参数解析的结果添加到request里面。
2.5、返回ResponseBody转化成Response<DataBean>
// OkHttpCall
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
rawResponse =
rawResponse
.newBuilder()
.body(new OkHttpCall.NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
T body = responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
}
}
3、动态代理模式
执行Service方法使用了代理模式。
好处1、 比如使用某个网络框架请求数据,后来换成其他网络请求框架,如果不使用代理模式,需要将使用的地方删除,可能很多。使用代理,只会改掉代理里面的就可以了。
好处2、如果被代理者3个方法,被代理者只授权使用2个,那么就可以使用代理模式了,避免客户直接访问被代理者的受限方法。
代理模式.png
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
4、建造者模式
创建Retrofit、RequestFactroy使用了建造者模式。
好处: 将对象的实现细节,封装在内部,高内聚。相同的构建过程,可以创建不同的产品。
建造者.png
// RequestFactory
RequestFactory(Builder builder) {
method = builder.method;
baseUrl = builder.retrofit.baseUrl;
httpMethod = builder.httpMethod;
relativeUrl = builder.relativeUrl;
headers = builder.headers;
contentType = builder.contentType;
hasBody = builder.hasBody;
parameterHandlers = builder.parameterHandlers;
}
//Builder
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
parameterHandlers[p] =
parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
}
return new RequestFactory(this);
}
5、工厂模式
1.1、创建CallAdapter使用了工厂方法模式
相比较简单工厂,简单工厂再创建adapter,需要修改factroy类,所以一般框架都是使用工厂方法和抽象工厂,避免修改,对修改关闭,对扩展开放。
工厂方法模式
abstract class Factory {
public abstract @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit);
}
public final class RxJava2CallAdapterFactory extends CallAdapter.Factory {
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,
isSingle, isMaybe, false);
}
}
final class RxJava2CallAdapter<R> implements CallAdapter<R, Object> {
@Override public Object adapt(Call<R> call) {
}
}
每一个CallAdapter的子类型Adapter对应一个Factroy的子类型工厂。 CallAdapter主要负责在adapt方法中请求数据,配置Retrofit时,传递的不同Factroy,决定了不同的Adpter。
1.2、创建Converter对象使用了抽象工厂模式
Factory创建同一类的多个相类似的产品,也避免了在Factory中修改。
抽象工厂模式
public final class GsonConverterFactory extends Converter.Factory {
@Override
public Converter<ResponseBody, ?> responseBodyConverter(
Type type, Annotation[] annotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);
}
@Override
public Converter<?, RequestBody> requestBodyConverter(
Type type) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonRequestBodyConverter<>(gson, adapter);
}
}
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final TypeAdapter<T> adapter;
@Override
public T convert(ResponseBody value) throws IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
T result = adapter.read(jsonReader);
return result;
}
}
}
可以看到每个工厂可以创建2个Converter,以GsonConverterFactory为例,一个工厂创建了GsonRequestBodyConverter和GsonResponseBodyConverter对象。GsonRequestBodyConverter负责将ResponseBody通过Gson转化成ResponType类型。GsonRequestBodyConverter将传入的java对象写入到RequestBody中。
6、适配器模式
将某个类的接口转化为客户端期望的另一个接口表示,主要的目的是兼容性,让原本不匹配不能一起工作的两个类可以协同工作。
适配器模式
// 创建
new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
}
final class RxJava2CallAdapter<R> implements CallAdapter<R, Object> {
@Override public Type responseType() {
return responseType;
}
@Override public Object adapt(Call<R> call) {
Observable<Response<R>> responseObservable = isAsync
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);
return observable;
}
}
final class CallEnqueueObservable<T> extends Observable<Response<T>> {
private final Call<T> originalCall;
@Override protected void subscribeActual(Observer<? super Response<T>> observer) {
Call<T> call = originalCall.clone();
CallCallback<T> callback = new CallCallback<>(call, observer);
observer.onSubscribe(callback);
call.enqueue(callback);
}
private static final class CallCallback<T> implements Disposable, Callback<T> {
CallCallback(Call<?> call, Observer<? super Response<T>> observer) {
this.call = call;
this.observer = observer;
}
@Override public void onResponse(Call<T> call, Response<T> response) {
try {
observer.onNext(response);
}
}
}
}
HttpServiceMethod类通过CallFactroy、responseConverter、callAdapter创建OkhttpCall对象,并且抽象了adapt方法,这个方法负责请求数据。
子类CallAdapted 实现adapt方法,执行Call请求,但是该方法的具体实现在CallAdapter中的adapt中实现的。
比如上述的CallAdapter为RxJava2CallAdapter时,执行Call请求在RxJava2CallAdapter的adapt方法中,执行adapt方法返回了Observable<Response<R>>类型。
适配器模式
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final TypeAdapter<T> adapter;
@Override
public T convert(ResponseBody value) throws IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
T result = adapter.read(jsonReader);
return result;
}
}
}
基类中Convert中将ResponseBody转化成泛型T,子类GsonResponseConverter实现了Convert方法,该类持有TypeAdapter对象,真正转化是在ObjectTypeAdapter中实现的。
// OkHttpCall
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
rawResponse =
rawResponse
.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
T body = responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
}
}
Adapter将stream转化成需要的对象,比如DateBean,包转成Response<DateBean>返回。
7、策略模式
策略模式3.1、解析注解,生成ParameterHandler
private ParameterHandler<?> parseParameterAnnotation(
int p, Type type, Annotation[] annotations, Annotation annotation) {
if (annotation instanceof FieldMap) {
validateResolvableType(p, type);
Class<?> rawParameterType = Utils.getRawType(type);
Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
ParameterizedType parameterizedType = (ParameterizedType) mapType;
Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
Converter<?, String> valueConverter = retrofit.stringConverter(valueType, annotations);
gotField = true;
return new ParameterHandler.FieldMap<>(
method, p, valueConverter, ((FieldMap) annotation).encoded());
} else if (annotation instanceof Body) {
validateResolvableType(p, type);
Converter<?, RequestBody> converter;
try {
converter = retrofit.requestBodyConverter(type, annotations, methodAnnotations);
}
gotBody = true;
return new ParameterHandler.Body<>(method, p, converter);
}
}
3.2、实现ParameterHandler接口,重写apply()方法
static final class FieldMap<T> extends ParameterHandler<Map<String, T>> {
private final Converter<T, String> valueConverter;
private final boolean encoded;
@Override
void apply(RequestBuilder builder, @Nullable Map<String, T> value) throws IOException {
for (Map.Entry<String, T> entry : value.entrySet()) {
String entryKey = entry.getKey();
T entryValue = entry.getValue();
String fieldEntry = valueConverter.convert(entryValue);
builder.addFormField(entryKey, fieldEntry, encoded);
}
}
}
3.3、使用ParameterHandler对象。
// OkHttpCall
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
return call;
}
// RequestFactory
okhttp3.Request create(Object[] args) throws IOException {
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args.length;
RequestBuilder requestBuilder =
new RequestBuilder(
httpMethod,
baseUrl,
relativeUrl,
headers,
contentType,
hasBody,
isFormEncoded,
isMultipart);
List<Object> argumentList = new ArrayList<>(argumentCount);
for (int p = 0; p < argumentCount; p++) {
argumentList.add(args[p]);
handlers[p].apply(requestBuilder, args[p]);
}
return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();
}
okhttp执行同步或者异步请求时,调用createRawCall方法,接着调用create方法,调用handlers[p].apply,将参数设置给requestBuilder,返回request。
总结
Retrofit使用到了很多模式,除了上述,还使用了比如常见模板设计模式,装饰设计模式,原型模式、门面模式、观察者模式等。