1.開發(fā)中一個常見網(wǎng)絡(luò)請求過程
url,參數(shù)---> request ---> 轉(zhuǎn)化成Http協(xié)議 -->請求執(zhí)行 ---> 返回結(jié)果--> 轉(zhuǎn)化成response ---> response轉(zhuǎn)化成我們的對象
只有頭和尾是我們?nèi)粘i_發(fā)進行自定義的,中間的其他過程都是網(wǎng)絡(luò)框架進行的。
2.Retrofit做的事情
1.url,參數(shù)Retrofit主要采用接口+注解方式
2.中間網(wǎng)絡(luò)請求框架采用動態(tài)代理去使用某個框架
3.response轉(zhuǎn)化成我們的對象采用adapter模式進行適配
3.Retrofit的實現(xiàn)過程
1)toRequest,url,參數(shù)Retrofit主要采用接口+注解方式
我們以一個簡單的POST請求為例
@POST("ssoService/v1/logoutByCTGT")
Call<BaseResponseBean> logout(@Body LogoutRequest logoutRequest);
@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface POST {
String value() default "";
}
@Documented
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface Body {
}
<u>注解知識點解析</u>
- 注解的定義
- @Documented
Documented注解表明這個注釋是由 javadoc記錄的,在默認(rèn)情況下也有類似的記錄工具。 如果一個類型聲明被注釋了文檔化,它的注釋成為公共API的一部分。
-
@Target(METHOD)
注釋可能出現(xiàn)在Java程序中的語法位置,TYPE,F(xiàn)IELD,METHOD,PARAMETER等
@Retention(RUNTIME)
描述保留注釋的各種策略,SOURCE(源碼期,編譯的時候會被忽略),CLASS(會被編譯到類文件中,但是JVM中沒有),RUNTIME(各個階段都存在)
- 注解的獲取(ServiceMethod.Builder類)
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
獲取注解的方法
this.methodAnnotations = method.getAnnotations();
this.parameterAnnotationsArray = method.getParameterAnnotations();
注解獲取相對還是比較簡單的,Method方法可以直接獲取各種注解,一個是方法上面的注解,一個是參數(shù)上的注解
- Retrofit對于獲取到的注解的處理(ServiceMethod.Builder.build())
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
......
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.");
}
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
注解處理后轉(zhuǎn)化成相關(guān)屬性
private final String httpMethod;
private final String relativeUrl;
private final Headers headers;
private final MediaType contentType;
private final boolean hasBody;
private final boolean isFormEncoded;
private final boolean isMultipart;
private final ParameterHandler<?>[] parameterHandlers;
然后在ServiceMethod.toRequest方法里轉(zhuǎn)換成 Request
Request toRequest(@Nullable Object... args) throws IOException {
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args != null ? args.length : 0;
if (argumentCount != handlers.length) {
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
}
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
return requestBuilder.build();
}
以上分析了注解到toRequest,接下去我們分析下代碼的調(diào)用過程
同步請求過程
OkHttpCall.execute()->OkHttpCall.createRawCall()->serviceMethod.toRequest()
異步過程
OkHttpCall.enqueue()->OkHttpCall.createRawCall()->serviceMethod.toRequest()
2)toResponse
優(yōu)先解析toResponse的使用,可以方便我們反推Retrofit如何使用動態(tài)代理進行網(wǎng)絡(luò)框架的調(diào)用
相比toRequest,toResponse則簡單很多,日常工作當(dāng)中我們也是經(jīng)常使用Gson進行結(jié)果的轉(zhuǎn)化,我們通過轉(zhuǎn)化器的添加,以及轉(zhuǎn)化的調(diào)用流程對toResponse進行一次分析
- 我們先來下轉(zhuǎn)化成我們自己的對象的方法是什么時候添加的
public static <T> T createJsonApi(@Url String baseUrl, Class<T> service) {
if (!checkUrl(retrofitRxJson, baseUrl)) {
retrofitRxJson = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(okHttpClient)
.build();
}
return retrofitRxJson.create(service);
}
.addConverterFactory(GsonConverterFactory.create())
采用Gson把平臺返回的內(nèi)容轉(zhuǎn)化成我們的對象
public class BaseResponseBean<T> {
public Integer type;
public String code;
public String msg;
public T data;
}
- toResponse整個調(diào)用過程
- 同步請求
OkHttpCall.excute()-> OkHttpCall.parseResponse()->serviceMethod.toResponse()->serviceMethod.responseConverter.convert()
- 異步請求
OkHttpCall.enqueue()-> hik.lib.okhttp3.Callback.onResponse()->OkHttpCall.parseResponse()->serviceMethod.toResponse()->serviceMethod.responseConverter.convert()
- responseConverter的初始化
ServiceMehtond.Builder.build()->ServiceMehtond.Builder.createResponseConverter()->retrofit.responseBodyConverter()-> retrofit.nextResponseBodyConverter()
<u>這里有個比較好的設(shè)計,看代碼</u>
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter<ResponseBody, T>) converter;
}
}
StringBuilder builder = new StringBuilder("Could not locate ResponseBody converter for ")
.append(type)
.append(".\n");
if (skipPast != null) {
builder.append(" Skipped:");
for (int i = 0; i < start; i++) {
builder.append("\n * ").append(converterFactories.get(i).getClass().getName());
}
builder.append('\n');
}
builder.append(" Tried:");
for (int i = start, count = converterFactories.size(); i < count; i++) {
builder.append("\n * ").append(converterFactories.get(i).getClass().getName());
}
throw new IllegalArgumentException(builder.toString());
}
<font color="Hotpink"><u>如果返回轉(zhuǎn)換的類型有多個,會根據(jù)接口的返回類型進行匹配</u></font>
3)動態(tài)代理進行網(wǎng)絡(luò)框架的使用
我們分析了toRequest()與toResponse(),以及從OkHttpCall網(wǎng)絡(luò)請求調(diào)用兩個方法的過程,接下去我們分析動態(tài)代理如何調(diào)用OkHttpCall里的execute()與enqueue()
我們在使用的時候都是定義接口,但是并沒有定義實現(xiàn)類,這里就是使用動態(tài)代理方式實現(xiàn)了接口的實現(xiàn)類
這里有個要注意的地方*******************
<u>接口返回的是一個對網(wǎng)絡(luò)請求進行了封裝的對象,并沒有進行網(wǎng)絡(luò)請求</u>
- 動態(tài)代理的創(chuàng)建
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);
}
});
}
從代碼來說,動態(tài)代理是比較簡單的。
<u>動態(tài)代理知識點解析</u>
動態(tài)代理(dynamic proxy)
利用Java的反射技術(shù)(Java Reflection),在運行時創(chuàng)建一個實現(xiàn)某些給定接口的新類(也稱“動態(tài)代理類”)及其實例(對象),代理的是接口(Interfaces),不是類(Class),也不是抽象類。在運行時才知道具體的實現(xiàn),spring aop就是此原理。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)throws IllegalArgumentException
newProxyInstance,方法有三個參數(shù):
loader: 用哪個類加載器去加載代理對象
interfaces:動態(tài)代理類需要實現(xiàn)的接口
h:動態(tài)代理方法在執(zhí)行時,會調(diào)用h里面的invoke方法去執(zhí)行
<u>結(jié)合我們Retrofit.create方法以及動態(tài)代理的知識,也就是我們接口里的所有方法最后都是調(diào)用</u>
serviceMethod.callAdapter.adapt(okHttpCall);
這里返回了一個包裹OkHttpCall的對象
這里又有一個知識點
Retrofit
final hik.lib.okhttp3.Call.Factory callFactory;
final HttpUrl baseUrl;
final List<Converter.Factory> converterFactories;
final List<CallAdapter.Factory> adapterFactories;
final @Nullable Executor callbackExecutor;
final boolean validateEagerly;
adapterFactories 返回的對象到底是RxJava2CallAdapterFactory,還是默認(rèn)的DefaultCallAdapterFactory
我們看下serviceMethod中callAdapter屬性的初始化
ServiceMethod.Builder.buid()->ServiceMethod.Builder.createCallAdapter->retrofit.callAdapter->retrofit.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;
}
}
StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
.append(returnType)
.append(".\n");
if (skipPast != null) {
builder.append(" Skipped:");
for (int i = 0; i < start; i++) {
builder.append("\n * ").append(adapterFactories.get(i).getClass().getName());
}
builder.append('\n');
}
builder.append(" Tried:");
for (int i = start, count = adapterFactories.size(); i < count; i++) {
builder.append("\n * ").append(adapterFactories.get(i).getClass().getName());
}
throw new IllegalArgumentException(builder.toString());
}
<font color="Hotpink"><u>最后是根據(jù)接口的返回類型去匹配使用那個AdapterFactory</u></font>
- 接下去我們看下AdaperFactory的實現(xiàn)
我們先看默認(rèn)的一個DefaultCallAdapterFactory的實現(xiàn)
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return call;
}
};
}
}
直接返回的是OkHttpCall 所以網(wǎng)絡(luò)請求是 execute,enqueue。
如果是RxJava2CallAdapter 則返回的是Observable,然后通過RXJava方法進行網(wǎng)絡(luò)請求調(diào)用,上代碼
public static void asyHttpRequest(Observable observable , BaseNetCallback netCallback){
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
observable.subscribe(new BaseNetObserver<>(netCallback));
}
設(shè)置執(zhí)行的線程,監(jiān)聽結(jié)果的線程,然后發(fā)起信號執(zhí)行
我們在看下信號執(zhí)行里的代碼
@Override protected void subscribeActual(Observer<? super Response<T>> observer) {
// Since Call is a one-shot type, clone it for each new observer.
Call<T> call = originalCall.clone();
CallCallback<T> callback = new CallCallback<>(call, observer);
observer.onSubscribe(callback);
call.enqueue(callback);
}
到這里的話我們基本已經(jīng)了解了Retrofit2 整個代碼的過程了
4.Retrofit的代碼總結(jié)
Retrofit 主要的代碼實現(xiàn)
-
OKHttpCall 主要是網(wǎng)絡(luò)請求實際實現(xiàn)的地方,主要有
execute
enqueue
createRawCall
-
ServiceMethod
toRequest
toResponse
Builder.build()
-
Retrofit
create
nextCallAdapter
nextResponseBodyConverter