說明:
本文的源碼分析較為粗淺,和其他源碼“解析”的文章相比并未特別詳細,個人覺得看別人的源碼,將整體的思路和大框架了解了,理解了其思想原理足矣
很重要的一點:
一定要帶著質疑別人所謂的的“解析”去分析,一定要結合源碼有自己的理解,不能完全相信他人的觀點,即便是所謂的“大神”,人,總有犯錯的時候。
如果文中有哪里不對的地方,請多指教。
從調用的流程開始分析
一、Retrofit的初始化
// 初始化配置Retrofit
retrofit = new Retrofit.Builder()
.baseUrl(AppConfig.BASE_URL)
//可設置自定義的client
.client(getOkHttpClient())
//可設置自定義的執行類CallAdapterFactory,可多個
.addCallAdapterFactory(new CustCallAdapterFactory())
//可設置自定義的解析類ConverterFactory,可多個
.addConverterFactory(new CustConvertFactory())
.build();
private OkHttpClient getOkHttpClient() {
if (okHttpClient == null) {
okHttpClient = new OkHttpClient().newBuilder()
.connectTimeout(15 * 1000, TimeUnit.MILLISECONDS)
.readTimeout(15 * 1000, TimeUnit.MILLISECONDS)
.retryOnConnectionFailure(true)
.addInterceptor(xxxInterceptor)
.build();
}
return okHttpClient;
}
- 這里對Retrofit進行初始化,是通過構造者模式進行構建相關的參數數據
-
addConverterFactory
:為對象的序列化和反序列化添加轉換器工廠 -
addCallAdapterFactory
:添加調用適配器工廠以支持除Call之外的服務方法返回類型
1、baseUrl:
-
baseUrl的方法有多個重載,最終通過構造HttpUrl傳入,一直傳遞給
okhttp3.Request
中public Builder baseUrl(HttpUrl baseUrl) //最終的調用 public Builder baseUrl(String baseUrl)
Request build() { HttpUrl url; HttpUrl.Builder urlBuilder = this.urlBuilder; if (urlBuilder != null) { url = urlBuilder.build(); } else { // No query parameters triggered builder creation, just combine the relative URL and base URL. url = baseUrl.resolve(relativeUrl); if (url == null) { throw new IllegalArgumentException( "Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl); } } //省略好多... return requestBuilder .url(url) .method(method, body) .build(); }
-
如何動態切換Retrofit的BaseURL?
Retrofit中接收的baseUrl(String),最終是作為HttpUrl(okhttp3包里的)的類型參數傳入的,在HttpUrl中有個host的字段,可以通過反射進行修改public Builder baseUrl(String baseUrl) { checkNotNull(baseUrl, "baseUrl == null"); HttpUrl httpUrl = HttpUrl.parse(baseUrl); if (httpUrl == null) { throw new IllegalArgumentException("Illegal URL: " + baseUrl); } return baseUrl(httpUrl); } public Builder baseUrl(HttpUrl baseUrl) { checkNotNull(baseUrl, "baseUrl == null"); List<String> pathSegments = baseUrl.pathSegments(); if (!"".equals(pathSegments.get(pathSegments.size() - 1))) { throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl); } this.baseUrl = baseUrl; return this; }
二、Retrofit的請求和響應
// ① 獲取接口實現
GitHubService service = retrofit.create(GitHubService.class);
// ② 調用(下面同步或異步請求選其一)
Call<List<Repo>> repos = service.listRepos("octocat");
// ③ 同步請求
Response<ResponseBody> res = repos.execute();
// ③ 異步請求
repos.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
try {
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
t.printStackTrace();
}
});
// 或者通過使用Observable,需要在初始化時進行配置:
// addCallAdapterFactory(RxJava3CallAdapterFactory.createSynchronous())
Observable<UserBean> call = mRetrofit.create(GitHubService.class).getUserData();
call.subsribe(Xxx)
1、接口的實現類:
從Retrofit
的示例來看,只需要一個接口及接口方法即可,調用者無需實現接口的具體實現類,就可以調用其內的方法,接口的實現類是從哪來的呢?
通過Retrofit#create
方法獲得了接口的實現類,其內部是通過 動態代理(模式) Proxy.newProxyInstance
來實現的:
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 {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method) //對default方法進行判斷
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
-
動態代理
Proxy.newProxyInstance
的參數和返回結果:-
classLoader
[參數]:類加載器會產生新類(實現的是傳入的接口) -
class[]
[參數]:新類實現的接口,傳進來(放到數組中) -
invocationHandler 接口
[參數]:執行方法體 -
T
[返回值]:一個封裝了請求參數的接口的類,來發起網絡請求
通過字節碼(或打印其getClass())可得出類似于:class com.sun.proxy.$Proxy0
-
-
獲?。▌討B代理)接口的實例對象
在Proxy
中,通過newProxyInstance
獲取對象時,其中維護了一個代理類的緩存集合proxyClassCache
【是WeakCache
,其內部通過ConcurrentMap
進行實際的緩存】,從此緩存中獲取生成的接口實現類。
而實現類的創建,是通過其固定的名稱組裝的類名://Proxy中: //固定規則 if (proxyPkg == null) { // if no non-public proxy interfaces, use com.sun.proxy package proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; //com.sun.proxy } String proxyName = proxyPkg + proxyClassNamePrefix + num; byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags); try { //這里返回結果,加載byte[]來獲取對象 return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { throw new IllegalArgumentException(e.toString()); }
-
InvocationHandler#invoke
內部解析:
1】Retrofit#loadServiceMethod
:
在每次調用請求接口方法的時候,每次都會通過調用invocationHandler
中的loadServiceMethod
方法,
在loadServiceMethod
方法內部,會解析得到具體的接口方法的實現(如例子中的listRepos
),進行調用invoke(args)
執行方法,發起網絡請求。
2】platform.isDefaultMethod(method)
invocationHandler
中對default
方法進行了判斷。如果是默認方法則對默認方法進行調用
default
是Java8的特性,在接口中可定義一些默認的方法:interface GithubApi { //默認方法 default void hello() { //do something... } }
注:其中
loadServiceMethod
返回的類型是ServiceMethod
,其具體實現類為HttpServiceMethod
。(似乎在之前的版本,2.2.0吧,ServiceMethod
是final
的,沒有實現類。)
2、解析并裝配參數(Okhttp請求)
在發送請求的時候,需要傳入一些參數,對于Retrofit
,其請求的參數是放到注解上的,那它是如何對其進行解析的呢?是通過loadServiceMethod
方法內部對接口方法的注解及參數的解析而得。
-
Retrofit#loadServiceMethod
在loadServiceMethod
方法中,通過傳入的Method
類型的參數來封裝成ServiceMethod
對象。
獲取具體的ServiceMethod對象流程(復用):
1】先從serviceMethodCache
緩存集合(ConcurrentHashMap
)中根據Method
取出ServiceMethod
對象,有則直接返回
2】若無,加鎖,通過ServiceMethod#parseAnnotations
解析方法的注解信息,創建對應的接口方法的實現;
并緩存到集合中
ConcurrentHashMap
是個線程安全的集合(數組 + 鏈表 + 紅黑樹),因為網絡請求都是在線程中去做的ServiceMethod
對象(具體實現為HttpServiceMethod
)中封裝了各種解析工廠類等請求和響應的數據類信息(CallAdapter
和Converter
等等)。
ServiceMethod#parseAnnotations
1】通過RequestFactory
獲取接口方法(如listRepos
方法)上的注解和參數等信息
如:baseUrl
、headers
等等
2】獲取返回值的泛型參數類型:
method.getGenericReturnType()
3】最后返回具體的注解信息結果:
HttpServiceMethod.parseAnnotations
通過HttpServiceMethod
(ServiceMethod
的實現類)進行返回值包裝類
和返回值
類的處理。HttpServiceMethod#parseAnnotations
1】通過HttpServiceMethod#createCallAdapter
得到CallAdapter
對象,方法內部根據參數進行匹配而得
2】通過createResponseConverter
得到Converter
對象,方法內部根據參數匹配而得
3】通過CallAdapter
和Converter
等對象構造出HttpServiceMethod
具體實現的子類對象并返回
① 若不是kotlin協程的方法,則返回CallAdapted
對象
② 否則返回協程方法相關的對象實例:SuspendForResponse
或SuspendForBody
ServiceMethod#invoke(args)
執行接口方法的調用,進而發起網絡請求
invoke
是ServiceMethod
的抽象方法,由其直接子類HttpServiceMethod
實現HttpServiceMethod.invoke(args)
1】實現了父類ServiceMethod
的方法
2】創建Call對象
:
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
3】在實現的invoke
方法中,又轉交給HttpServiceMethod.adapt
的抽象方法去完成的HttpServiceMethod.adapt
:
適配數據類型,并執行網絡請求。
1】具體如何將Call
轉換為指定的返回值包裝類
的,最終是交給實現了HttpServiceMethod
的子類去完成的。
2】如在CallAdapted
中,其adapt
方法是直接交由傳入的CallAdapter
的實現類來處理的
在使用的例子中是RxJava3CallAdapterFactory
內的具體實現RxJava3CallAdapter
3、“處理器”工廠:
這里我將類型適配器CallAdapter和解析轉換器Converter稱之為處理器,兩者都用了 抽象工廠模式。
CallAdapter
:是對響應的數據進行轉換,由T類型轉換為R類型,這里用了 適配器模式
Converter
:是對請求數據和響應結果進行處理的數據類型轉換的處理類。
-
CallAdapter
1】Retrofit
中定義了接口CallAdapter<R, T>
,并由具體的子類實現如下方法:
①Type responseType();
:返回具體的內部類型,如UserBean
②T adapt(Call<R> call);
:用于將retrofit2.Call
轉換為 返回值包裝類,如Observable
,并執行請求
2】Retrofit
默認只支持retrofit2.Call
作為接口方法的 返回值包裝類,
可通過實現CallAdapter
接口進行擴展Call
,適配器的添加是通過在初始化Retrofit
時配置的:
Retrofit.Builder.addCallAdapterFactory
方法,可加多個適配器來轉換 返回值包裝類,
如可設置RxJava2CallAdapterFactory的Adapter
3】而真正使用的只有一個,在Retrofit#nextCallAdapter
中處理了相關邏輯
根據類型和注解的相關信息,循環List<CallAdapter.Factory>
進行匹配,
根據returnType
(Type
)、annotations
(Annotation[]
)等信息,匹配到了適配器(即返回結果不為null),則終止循環,直接返回這個factory。public interface CallAdapter<R, T> { Type responseType(); T adapt(Call<R> call); }
-
Converter
1】Retrofit
中定義了接口Converter<F, T>
,并由具體的子類實現convert
方法:
①T convert(F value)
:即從F
到T
(數據Bean)之間的轉換操作。(多是處理POST
請求)
F
一般是RequestBody
(請求體)或是ResponseBody
(響應體),而T
是通過convert
方法返回的轉換類型(如UserBean
)。
2】Retrofit
提供了addConverterFactory
方法,來配置添加轉換實體的工廠對象,可加多個
① 在請求的時候,通過Retrofit#requestBodyConverter
方法(在構建RequestFactory
中調用的)獲取指定的 請求 數據解析器。
② 通過Retrofit#responseBodyConverter
方法(在HttpServiceMethod#createResponseConverter
中獲得的)獲取指定的 響應 數據解析器。
3】在HttpServiceMethod#parseAnnotations
方法中調用了HttpServiceMethod#createResponseConverter
,
并在其內部獲取到匹配的轉換器,實際調用了Retrofit#responseBodyConverter
方法
4】在獲取響應結果的轉換器Retrofit#responseBodyConverter
(實際調用了nextResponseBodyConverter
方法)中,會循環遍歷converterFactories
轉換器集合(addConverterFactory
方法添加)
直到根據type
(Type
)、annotations
(Annotation[]
)等信息,匹配到轉換器(即返回結果不為null),則終止循環,直接返回這個factory。public interface Converter<F, T> { T convert(F value) throws IOException; }
4、請求的發起OkHttpCall
Retrofit
中真正發起網絡請求的,最終還是通過的OkHttp
,所以要創建OkHttpCall
-
OkHttpCall
對象的創建:
在HttpServiceMethod.invoke(args)
的方法中,創建了OkHttpCall
對象
并將其實例傳給了抽象方法adapt
,是由子類決定如何通過OkHttp
的實例發起網絡請求@Override final @Nullable ReturnT invoke(Object[] args) { Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter); return adapt(call, args); }
-
OkHttpCall#getRawCall -> createRawCall
在方法中,創建了真正的請求調用對象,并傳入了請求的相關信息
返回的Call
實例,是OkHttp
中的請求對象,所以具體的請求還是由OkHttp
完成的。private okhttp3.Call createRawCall() throws IOException { okhttp3.Call call = callFactory.newCall(requestFactory.create(args)); if (call == null) { throw new NullPointerException("Call.Factory returned null."); } return call; }
OkHttpCall#enqueue / execute
方法:
1】OkHttpCall
類中是具體發起請求的地方,即重寫的enqueue / execute
方法
2】在接口(GitHubService)中定義的方法(listRepos
)的返回類型Call<ResponseBody>
,這里的Call
實際上就是OkHttpCall
類型
3】當調用call.enqueue(Callback)
時,enqueue
就是OkHttpCall
中的具體實現,而Callback
(retrofit2.Callback)會在okhttp3.Callback
回調時進行轉換。
4】HttpServiceMethod
的子類實現的adapt
方法中,根據傳入的Call
,又調用了其enqueue
來執行請求的異步任務。
5、結果返回類型
例子中的Call<List<Repo>>
是如何返回的呢?
-
類型說明
首先先明確一下,Retrofit中如何對這個返回類型中的各個部分定義的:- returnType:接口方法中的 返回值類型,如
Call<List<Repo>>
- rawType:接口方法中的 返回值包裝類,如
Call
- responseType:接口方法中返回的數據Bean類型,如
List<Repo>
- returnType:接口方法中的 返回值類型,如
-
創建對象后的類型返回
1】ReturnT invoke
:
上面1中說到,請求的方法通過invoke
方法來調用的,那返回類型就從這里入手,
而invoke
是在ServiceMethod
中定義的,具體實現在HttpServiceMethod
的invoke
中(之前ServiceMethod
無實現類的時候,代碼直接寫在Retrofit
中來實現的),
而HttpServiceMethod#invoke
中又包了一層了adapt
抽象方法,adapt
定義的返回值的類型ReturnT
就是接口方法的返回類型(如Call<List<Repo>>
)@Override final @Nullable ReturnT invoke(Object[] args) { Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter); return adapt(call, args); } protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);
2】
ReturnT adapt(Call<ResponseT> call, Object[] args)
adapt
方法的具體實現類是CallAdapted<ResponseT, ReturnT>
(非kotlin協程),就在HttpServiceMethod
中,是個內部類。此方法是通過CallAdapter
來實現的,它其中的adapt
方法就是一個類型轉換器,具體后面介紹。@Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) { return callAdapter.adapt(call); }
3】
CallAdapter
的具體實現有很多,其中有個最原始的支持:DefaultCallAdapterFactory
,
此類中直接創建的匿名內部類CallAdapter
的實現沒有具體轉換,只轉成了最基本的Call
類型,是因為要將線程中的請求結果,發送到主線程中,這其中就將Handler的消息發送包裝了起來:return new CallAdapter<Object, Call<?>>() { @Override public Type responseType() { return responseType; } @Override public Call<Object> adapt(Call<Object> call) { return executor == null ? call : new ExecutorCallbackCall<>(executor, call); } };
-
泛型類型的處理
在DefaultCallAdapterFactory
中,對相關的泛型參數類型進行了處理:@Override public @Nullable CallAdapter<?, ?> get( Type returnType, Annotation[] annotations, Retrofit retrofit) { if (getRawType(returnType) != Call.class) { return null; } if (!(returnType instanceof ParameterizedType)) { throw new IllegalArgumentException( "Call return type must be parameterized as Call<Foo> or Call<? extends Foo>"); } final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
1】先判斷
rawType
為Call
,在DefaultCallAdapterFactory
的只對Call
類型處理
2】然后判斷其中是否有泛型參數(即returnType
[如Call<List<Repo>>
] 是否是參數化類型ParameterizedType
)
3】再從參數化類型中取出泛型實參(responseType
[如List<Repo>
]),這里取的上限(Call<? extends Foo>
)的第一個(有可能有多個泛型實參)。 如何處理非原始支持的類型,如kotlin的
Deffered
:
同樣的,也是需要實現CallAdapter
來具體的進行轉換返回相應的類型。
6、如何獲取返回結果的泛型實參
問題:java泛型有類型擦除,那是如何在運行時獲得XxxBean(如List<Repo>)的呢?
上面說到,在獲取returnType
之后,判斷是否為泛型參數類型(ParameterizedType
),
然后再通過CallAdapter
中的getParameterUpperBound
(取類型的上限)
//Factory中
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
//Utils中
static Type getParameterUpperBound(int index, ParameterizedType type) {
//types即為<Xxx, Yyy, ...> 中的 Xxx, Yyy, ...這一數組
//獲取泛型實參,主要在這里:getActualTypeArguments
Type[] types = type.getActualTypeArguments();
if (index < 0 || index >= types.length) {
throw new IllegalArgumentException(
"Index " + index + " not in range [0," + types.length + ") for " + type);
}
Type paramType = types[index];
//對通配符的判斷
if (paramType instanceof WildcardType) {
return ((WildcardType) paramType).getUpperBounds()[0];
}
return paramType;
}
如果需要獲取泛型類型,就要在混淆的時候,保留相關的方法處理,不能進行混淆。
若混淆了,生成的如下面的字節碼上的注釋都會被干掉,因此這些泛型類型都會被去掉,就無法獲取到了。
- 原始代碼:
public static Map<List<String>, Set<Map<Number, String>>> test(Map<String, Set<Map<Number, String>>> map) { return null; }
- 編譯后的字節碼:
// access flags 0x9 // signature (Ljava/util/Map<Ljava/lang/String;Ljava/util/Set<Ljava/util/Map<Ljava/lang/Number;Ljava/lang/String;>;>;>;)Ljava/util/Map<Ljava/util/List<Ljava/lang/String;>;Ljava/util/Set<Ljava/util/Map<Ljava/lang/Number;Ljava/lang/String;>;>;>; // declaration: java.util.Map<java.util.List<java.lang.String>, java.util.Set<java.util.Map<java.lang.Number, java.lang.String>>> test(java.util.Map<java.lang.String, java.util.Set<java.util.Map<java.lang.Number, java.lang.String>>>) public static test(Ljava/util/Map;)Ljava/util/Map;
泛型擦除是一個無奈之舉,因為在java1.5出現泛型之前的1.4版本及之前的版本,已經使用的很廣泛了,為了兼容之前的代碼程序。
C#是將泛型作為一個真實的類型存在,沒有泛型擦除的問題。
7、Retrofit
中的kotlin協程
- 使用:可直接返回實體Bean,而不需要任何包裝類
interface GitHubService {
@GET("getUserData")
suspend fun getUserData(): UserBean
}
data class UserBean(val userName: String, val userAge: Long)
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
val service = retrofit.create(GitHubService::class.java)
val job: Job = launch {
try {
val userBean: UserBean = service.getUserData()
println("userBean: $userBean")
} catch (e: Throwable) {
println("onFailure: $e")
}
}
-
內部解析
1】Retrofit
是以Java語言實現的,而suspend
掛起函數只能用于ktolin,不過都會編譯為JVM
語言
通過將接口ApiService
反編譯得到的Java類,結果如下:public interface ApiService { @GET("getUserData") @Nullable Object getUserData1(@NotNull Continuation var1); }
2】在
RequestFactory
中包含一個isKotlinSuspendFunction
的成員,用來標記當前解析的Method
是否為suspend
函數。
而isKotlinSuspendFunction
的值,是在RequestFactory#build
方法中跟進方法參數的最后一個是否為Continuation.class
來判定的。3】在處理方法的解析中,
HttpServiceMethod#parseAnnotations
內,根據isKotlinSuspendFunction
來處理kotlin協程的接口方法的解析結果
如果是,則返回SuspendForResponse
(得到Response
對象)或SuspendForBody
(得到數據Bean對象,如UserBean)對象,皆為HttpServiceMethod
的子類4】
SuspendForBody
實現的adapt
方法中,
將接口方法(getUserData)最后一個參數強轉為Continuation<ResponseT>
最終會調用KotlinExtensions.await
這個kotlin擴展方法5】
KotlinExtensions.await
方法中,
以suspendCancellableCoroutine
支持cancel的CoroutineScope
為作用域,依舊以Call.enqueue
發起OkHttp
請求,得到responseBody
后將其回調出去。
8、Retrofit在Android中的支持
支持主要在兩方面:
① 是否支持Java8
,根據Android上是否啟用Java 8
來判斷,(Gradle中配置)
② 實現UI線程回調的Executor
,將回調結果切到UI線程
- 是否為Android平臺的判斷:
根據虛擬機的名稱來判斷,其中定義的Android
類,是Platform的唯一子類
private static Platform findPlatform() {
//根據 JVM 名字來判斷使用方是否是 Android 平臺
return "Dalvik".equals(System.getProperty("java.vm.name"))
? new Android()
: new Platform(true);
}
- 是否支持
Java 8
:
通過Platform
中的hasJava8Types
成員來判斷,在Platform#Android
類中,是通過構造方法傳入的條件判斷的:
Android() {
super(Build.VERSION.SDK_INT >= 24);
}
-
UI線程的回調實現:
1】在Platform#Android
中,重寫了defaultCallbackExecutor
方法,
返回了創建的MainThreadExecutor
對象,其中通過Handler
實現了將執行任務Runnable
轉發到UI線程的邏輯static final class MainThreadExecutor implements Executor { private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute(Runnable r) { handler.post(r); } }
2】上面說到的
CallAdapter.Factory
,是用于處理接口返回值包裝類(如Observable
)的適配器,在Retrofit#build
的時候,會將DefaultCallAdapterFactory
添加進去。而DefaultCallAdapterFactory
中就是處理對應的線程切換的操作。3】
DefaultCallAdapterFactory#get
方法返回的CallAdapter
對象,就是包裝了ExecutorCallbackCall
(實現了Call
接口)對象,即具體實現了執行請求的ExecutorCallbackCall#enqueue
方法,在此方法中,進行了任務的執行:@Override public void enqueue(final Callback<T> callback) { Objects.requireNonNull(callback, "callback == null"); delegate.enqueue( new Callback<T>() { @Override public void onResponse(Call<T> call, final Response<T> response) { callbackExecutor.execute( () -> { if (delegate.isCanceled()) { // Emulate OkHttp's behavior of throwing/delivering an IOException on // cancellation. callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled")); } else { callback.onResponse(ExecutorCallbackCall.this, response); } }); } @Override public void onFailure(Call<T> call, final Throwable t) { callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t)); } }); }
9、如何支持RxJava
-
在構建
Retrofit
時,通過添加CallAdapterFactory
:retrofit = new Retrofit.Builder() .client(OKHttpFactory.INSTANCE.getOkHttpClient()) .baseUrl(AppConfig.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) //看這里 .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build();
RxJava2CallAdapterFactory
內部實現:
RxJava2CallAdapterFactory
中對返回值類型進行一系列操作,處理泛型參數等,并處理返回
其中的returnType
就是Observable<XxxBean>
(XxxBean
就是自己定義的需要解析的類型),拿到returnType
之后,獲取rawType
并進行一系列判斷,判斷各種RxJava
中定義的類型,最終將Obervable
的這種rawType
類型進行處理,然后在對泛型參數類型(即Observable
尖括號中的泛型類型)進行獲取并處理,最終進行相關賦值,并返回CallAdapter<?>
-
還支持
Observable<Response<XxxBean>>
請求的時候,具體實現為BodyObservable
的類型返回,真正實現adapt
的相關工作Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType); Class<?> rawObservableType = getRawType(observableType); if (rawObservableType == Response.class) { if (!(observableType instanceof ParameterizedType)) { throw new IllegalStateException( "Response must be parameterized" + " as Response<Foo> or Response<? extends Foo>"); } responseType = getParameterUpperBound(0, (ParameterizedType) observableType); } else if (rawObservableType == Result.class) { if (!(observableType instanceof ParameterizedType)) { throw new IllegalStateException( "Result must be parameterized" + " as Result<Foo> or Result<? extends Foo>"); } responseType = getParameterUpperBound(0, (ParameterizedType) observableType); isResult = true; } else { responseType = observableType; isBody = true; } return new RxJava2CallAdapter( responseType, scheduler, isAsync, isResult, isBody, isFlowable, isSingle, isMaybe, false); }
10、如何在反序列化時實例化對象
具體處理類是GsonConverterFactory
其中在處理request請求和response響應時,通過 gson.getAdapter
來返回TypeAdapter
,并傳入 GsonRequestBodyConverter
或 GsonResponseBodyConverter
構造來處理解析的數據。在 TypeAdapterFactory
獲取的TypeAdapter
實現的,一般是ReflectiveTypeAdapterFactory
,而ObjectTypeAdapter
中的read
方法是對基本數據類型進行處理解析。
具體的實例化是,在 Gson
構造函數中,創建了一個ConstructorConstructor
構造器的構造器,接收一個instanceCreators
(調用者傳進來的):
Gson(final Excluder excluder, final FieldNamingStrategy fieldNamingStrategy, final Map<Type,
InstanceCreator<?>> instanceCreators,
..., ...//省略好多入參....
) {
//省略好多....
this.constructorConstructor = new ConstructorConstructor(instanceCreators);
//省略好多....
}
在ConstructorConstructor
中對對象的構造做了很多流程判斷(如圖),判斷了是否有無參構造(通過newDefaultConstructor)
終極方案就是使用newUnsafeAllocator
中的native
方法來開辟對象內存空間:
public native Object allocateInstance(Class<?> var1) throws InstantiationException;
在終極方案中,進行實例化對象:
private <T> ObjectConstructor<T> newUnsafeAllocator(
final Type type, final Class<? super T> rawType) {
return new ObjectConstructor<T>() {
private final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create();
@SuppressWarnings("unchecked")
@Override public T construct() {
try {
//看這里
Object newInstance = unsafeAllocator.newInstance(rawType);
return (T) newInstance;
} catch (Exception e) {
throw new RuntimeException(("Unable to invoke no-args constructor for " + type + ". "
+ "Registering an InstanceCreator with Gson for this type may fix this problem."), e);
}
}
};
}
最終實例化了對象,實例化的時機,是在read
的時候:
//ReflectiveTypeAdapterFactory <-- 大多數都是這個factory
public static final class Adapter<T> extends TypeAdapter<T> {
private final ObjectConstructor<T> constructor;
private final Map<String, BoundField> boundFields;
Adapter(ObjectConstructor<T> constructor, Map<String, BoundField> boundFields) {
this.constructor = constructor;
this.boundFields = boundFields;
}
@Override
public T read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
//看這里啊,這里啥都木有,就是實例化一個對象,字段全是默認值
T instance = constructor.construct();
//省略好多.....
return instance;
}
@Override
public void write(JsonWriter out, T value) throws IOException {
//省略好多.....
}
}
設計模式舉例:
1、Builder模式
2、工廠模式
- 抽象工廠模式:生產一系列的產品,關注的是一個大的集合
- 工廠方法模式:創建一類對象,一種產品
- 二者關聯:抽象工廠通常是工廠方法來實現的
-
簡單工廠:根據傳遞的參數(String、class等等)來創建對應的類對象(產品)
特點:接口較少,簡單方便
缺點:增加產品的時候,需要增加/修改simpleFactory的代碼
簡單工廠
3、適配器模式
-
adapt
接收一種類型(接口),讓實現者去轉換為具體的結果,接收的是R
類型,返回的是T
類型。
除了Retrofit的CallAdapter
,還有Gson中的TypeAdapter
同樣也是適配器模式
4、代理模式
訪問子類(真正實現類)不可直接訪問,要通過Proxy
的訪問策略,來對內部私有的子類成員來進行控制訪問。都實現了同樣的接口(父類Subject)
需要注意的是,在Retrofit中創建實例的時候,雖然用了java中的動態代理,但并不是嚴格意義上的代理?難道不是代理了傳入的接口service
么?
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() {
//省略好多...
}
- 代理模式 vs 裝飾模式
- 代理模式:控制訪問
- 裝飾模式:增強功能
如何分析源碼總結:
- 帶著問題入手
- 從最熟悉的部分切入
- 看看有哪些可擴展性設計
- 分析下運用了哪些設計模式