前言
每次看完Retrofit的源碼,下次再看時很容易就忘記了,Retrofit的源碼中用了大量的設計模式,剛開始看時感覺就是代碼中調來調去。。。繞來繞去。。。真的。。。沒有點到即止的話~很容易就暈了,所以這次我從使用的API的角度出發,將對Retrofit的解析寫成筆記.
Retrofit源碼基於版本2.4.0
首先看下Retrofit的基本使用:
-
1.首先創建用於網絡請求的API接口:
public interface GitHub { @GET("/repos/{owner}/{repo}/contributors") Call<List<Contributor>> contributors( @Path("owner") String owner, @Path("repo") String repo); }
-
2.創建用於接收響應實體的類
public static class Contributor { public final String login; public final int contributions; public Contributor(String login, int contributions) { this.login = login; this.contributions = contributions; } }
-
3.創建Retrofit實例併發起請求
public static void main(String... args) throws IOException { Retrofit retrofit = new Retrofit.Builder() .baseUrl(API_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build(); GitHub github = retrofit.create(GitHub.class); Call<List<Contributor>> call = github.contributors("square", "retrofit"); //同步請求 List<Contributor> contributors = call.execute().body(); //異步請求 call.enqueue(new Callback<List<Contributor>>() { @Override public void onResponse(Call<List<Contributor>> call, Response<List<Contributor>> response) { } @Override public void onFailure(Call<List<Contributor>> call, Throwable t) { } });
2.從Retrofit的基本API入手:
a.Retrofit構建過程
-
1.Retrofit.Builder(): 獲取對應平臺的Platform實例,這裏是獲取到Android類的實例.
public final class Retrofit { public static final class Builder { Builder(Platform platform) { this.platform = platform; } public Builder() { //Platform是獲取相應的平臺,有Android、Java等 this(Platform.get()); } } }
在Android類裏主要是維護了MainThreadExecutor類,來將子線程切換到主線程
//適配平臺 class Platform { private static final Platform PLATFORM = findPlatform(); static Platform get() { return PLATFORM; } //尋找對應的平臺 private static Platform findPlatform() { try { //通過JVM加載類的方式判斷是否是Android平臺 Class.forName("android.os.Build"); if (Build.VERSION.SDK_INT != 0) { return new Android(); } } catch (ClassNotFoundException ignored) { } try { Class.forName("java.util.Optional"); return new Java8(); } catch (ClassNotFoundException ignored) { } return new Platform(); } } //Android平臺對應的類 static class Android extends Platform { //返回可以將子線程切換到主線程的線程池 @Override public Executor defaultCallbackExecutor() { return new MainThreadExecutor(); } //工廠方法模式,將Executor實例裝載進工廠類 @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) { if (callbackExecutor == null) throw new AssertionError(); return new ExecutorCallAdapterFactory(callbackExecutor); } static class MainThreadExecutor implements Executor { //Android主線程的Hnadler private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute(Runnable r) { //將子線程切換到主線程 handler.post(r); } } }
-
2.baseUrl( ): 判斷基礎的url不能爲空,將String類型的url轉化成HttpUrl實例
public final class Retrofit { public static final class Builder { public Builder baseUrl(String baseUrl) { //基礎的url不能爲空 checkNotNull(baseUrl, "baseUrl == null"); //將String類型的url 轉化成 HttpUrl實例 HttpUrl httpUrl = HttpUrl.parse(baseUrl); if (httpUrl == null) { throw new IllegalArgumentException("Illegal URL: " + baseUrl); } return baseUrl(httpUrl); } } }
HttpUrl類用了Build模式來創建
public final class HttpUrl { public static final class Builder { @Nullable public static HttpUrl parse(String url) { //build模式創建HttpUrl HttpUrl.Builder builder = new HttpUrl.Builder(); HttpUrl.Builder.ParseResult result = builder.parse((HttpUrl)null, url); return result == HttpUrl.Builder.ParseResult.SUCCESS ? builder.build() : null; } } }
-
3.addConverterFactory(): 將數據轉換器工廠添加到converterFactories這個存放數據轉換器工廠(集合的元素類型爲Converter.Factory)的集合中
//將數據轉換器工廠添加到converterFactories這個存放數據轉換器工廠(集合的元素類型爲Converter.Factory)的集合中 // 比如 GsonConverterFactory這個Gson數據轉換器 public Builder addConverterFactory(Converter.Factory factory) { converterFactories.add(checkNotNull(factory, "factory == null")); return this; }
-
4.addCallAdapterFactory(): 將網絡請求適配器工廠添加到callAdapterFactories這個存放網絡請求適配器工廠(集合的元素類型爲CallAdapter.Factory)的集合中
//將網絡請求適配器工廠添加到callAdapterFactories這個存放網絡請求適配器工廠(集合的元素類型爲CallAdapter.Factory)的集合中 //比如 開發者可添加 RxJavaCallAdapterFactory 這個RX網絡請求適配器 public Builder addCallAdapterFactory(CallAdapter.Factory factory) { callAdapterFactories.add(checkNotNull(factory, "factory == null")); return this; }
-
5.build():
-
檢查了OkHttpClient和回調線程池類Executor是否傳入值,未傳入則創建默認的值,已傳入則使用開發者設置的值
-
往存放數據轉換器工廠的集合存入開發者設置的數據轉換器工廠(例如GsonConverterFactory)和系統默認的數據轉換器工廠(BuiltInConverters)
-
往存放網絡請求適配器工廠的集合存入開發者設置的網絡請求適配器工廠(例如RxJavaCallAdapterFactory)和系統默認的網絡請求適配器工廠(ExecutorCallAdapterFactory)
- ExecutorCallAdapterFactory裏存了MainThreadExecutor實例
-
返回Retrofit實例
public Retrofit build() { //必須調用 baseUrl() 這個函數傳入基本的url,這裏纔不會拋異常 if (baseUrl == null) { throw new IllegalStateException("Base URL required."); } //開發者是否傳入OkHttpClient實例,未傳入則創建 okhttp3.Call.Factory callFactory = this.callFactory; if (callFactory == null) { callFactory = new OkHttpClient(); } //開發者是否傳入 用於回調的線程池類,未傳入則獲取對應平臺(這裏是Android類)的回調線程池實例 Executor callbackExecutor = this.callbackExecutor; if (callbackExecutor == null) { //這裏的Platform = Android //platform.defaultCallbackExecutor()獲取的是MainThreadExecutor實例 callbackExecutor = platform.defaultCallbackExecutor(); } // Make a defensive copy of the adapters and add the default Call adapter. List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories); //將MainThreadExecutor裝載進ExecutorCallAdapterFactory工廠實例裏,並將工廠實例添加進 網絡請求適配器的集合裏 callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)); // Make a defensive copy of the converters. List<Converter.Factory> converterFactories = new ArrayList<>(1 + this.converterFactories.size()); // Add the built-in converter factory first. This prevents overriding its behavior but also // ensures correct behavior when using converters that consume all types. //將默認的數據轉換器和開發者設置的數據轉換器裝載進工廠實例裏,並添加數據轉換器工廠到集合裏 converterFactories.add(new BuiltInConverters()); converterFactories.addAll(this.converterFactories); //Collections.unmodifiableList()函數是將集合轉化成只讀的 return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories), unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly); }
-
b. 創建請求接口的實例
-
1.retrofit.create(): 使用動態代理模式對網絡請求接口類進行代理,返回代理接口的實例,這裏invoke函數的代碼在下面調用網絡請求接口的函數時會被執行,重點在下面
public <T> T create(final Class<T> service) { //檢查網絡請求接口類是不是接口,有沒繼承其他接口 等 Utils.validateServiceInterface(service); //判斷是否需要提前緩存ServiceMethod對象, validateEagerly默認爲false if (validateEagerly) { eagerlyValidateMethods(service); } // 使用動態代理模式拿到 網絡請求接口類的函數的註解、函數參數、函數返回值等相關信息 // 返回"接口調用實例Call",其實這個Call是ExecutorCallbackCall類(Retrofit的Call的實現類)的實例,這裏只要先記得返回值是ExecutorCallbackCall類的實例即可 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); } //註釋1:ServiceMethod接口負責存 網絡請求接口類的函數的註解、函數參數、函數返回值等相關信息 ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method); //註釋2:OkHttpCall是對Retrofit.Call的實現,實際該類主要用到OkHttp.Call(rawCall這個變量) 來進行enqueue、execute請求 OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args); //註釋3:這裏實際上返回的是ExecutorCallbackCall類(Retrofit的Call的實現類)的實例 return serviceMethod.adapt(okHttpCall); } }); }
c. 調用網絡請求接口的函數
-
1.github.contributors(): 這裏會回調到上一步返回的代理接口中的InvocationHandler中的invoke函數
-
在invoke函數裏拿到網絡請求接口類的函數的註解、函數參數、函數返回值等相關信息,存入ServiceMethod裏
-
給ServiceMethod設置合適的數據轉換器和網絡請求適配器
-
創建OkHttpCall,OkHttpCall是對Retrofit.Call的實現,實際該類主要用到OkHttp.Call(rawCall這個變量) 來進行enqueue、execute請求
-
最後返回 ExecutorCallbackCall類(Retrofit的Call的實現類)的實例
在上面的invoke函數中,最重要的是標有 “註釋1”、“註釋2” 和 “註釋3” 這3行代碼,先看註釋1的代碼
//註釋1:ServiceMethod接口負責存 網絡請求接口類的函數的註解、函數參數、函數返回值等相關信息 ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method); public final class Retrofit { /** * 該函數主要加載網絡請求接口類的函數的註解、函數參數、函數返回值等相關信息 * 先從緩存中查找是否有該method對應的ServiceMethod實例,有則返回,沒有則創建之後返回 */ ServiceMethod<?, ?> loadServiceMethod(Method method) { ServiceMethod<?, ?> result = serviceMethodCache.get(method); if (result != null) return result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { //解析註解配置得到了ServiceMethod,ServiceMethod同樣是Build模式創建 result = new ServiceMethod.Builder<>(this, method).build(); //存進緩存裏 serviceMethodCache.put(method, result); } } return result; } }
上面的ServiceMethod是通過Build模式創建的
final class ServiceMethod<R, T> { static final class Builder<T, R> { Builder(Retrofit retrofit, Method method) { this.retrofit = retrofit; this.method = method; //獲取網絡請求接口裏函數的註解 this.methodAnnotations = method.getAnnotations(); //獲取網絡請求接口裏函數的參數類型 this.parameterTypes = method.getGenericParameterTypes(); //獲取網絡請求接口裏函數的參數註解 this.parameterAnnotationsArray = method.getParameterAnnotations(); } public ServiceMethod build() { //createCallAdapter函數是從callAdapterFactories集合裏找到合適的網絡請求適配器 callAdapter = createCallAdapter(); //獲取網絡請求接口類的函數的返回值 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?"); } //createResponseConverter函數是從converterFactories集合裏找到合適的數據轉換器 responseConverter = createResponseConverter(); for (Annotation annotation : methodAnnotations) { parseMethodAnnotation(annotation); } ...省略部分代碼 } } }
上面build函數中調用createCallAdapter函數生成callAdapter,調用createResponseConverter函數生成responseConverter,這兩個函數留到下一篇再去剖開,有時就應該點到即止,不然太多的細節繞着繞着就暈了,先記住這兩個函數是獲取了網絡請求適配器和數據轉換器,
根據上面的請求函數的返回值Call<List< Contributor >>,這裏獲取到的網絡請求適配器是ExecutorCallAdapterFactory(封裝MainThreadExecutor的工廠類),獲取到的數據轉換器是開發者通過api設置的GsonConverterFactory
.addConverterFactory(GsonConverterFactory.create())
接着回到註釋2的代碼,可以看到主要創建了OkHttpCall,而OkHttpCall是實現了Retrofit.Call接口, 實際上該類主要用到OkHttp.Call(rawCall這個變量) 來發起enqueue(異步)或execute(同步)請求,所以OkHttpCall是封裝了OkHttp框架的enqueue(異步)和execute(同步)請求
final class OkHttpCall<T> implements Call<T> { //...省略部分代碼 private @Nullable okhttp3.Call rawCall; //異步請求 @Override public void enqueue(final Callback<T> callback) { checkNotNull(callback, "callback == null"); okhttp3.Call call; Throwable failure; synchronized (this) { if (executed) throw new IllegalStateException("Already executed."); executed = true; call = rawCall; failure = creationFailure; if (call == null && failure == null) { try { //createRawCall() 返回的是 OkHttp.RealCall類的實例 call = rawCall = createRawCall(); } catch (Throwable t) { throwIfFatal(t); failure = creationFailure = t; } } } if (failure != null) { callback.onFailure(this, failure); return; } if (canceled) { call.cancel(); } //發起異步請求 call.enqueue(new okhttp3.Callback() { @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) { Response<T> response; try { //解析服務端的響應數據 response = parseResponse(rawResponse); } catch (Throwable e) { callFailure(e); return; } try { //將響應結果回調返回 callback.onResponse(OkHttpCall.this, response); } catch (Throwable t) { t.printStackTrace(); } } @Override public void onFailure(okhttp3.Call call, IOException e) { callFailure(e); } private void callFailure(Throwable e) { try { callback.onFailure(OkHttpCall.this, e); } catch (Throwable t) { t.printStackTrace(); } } }); } //同步請求 @Override public Response<T> execute() throws IOException { okhttp3.Call call; synchronized (this) { if (executed) throw new IllegalStateException("Already executed."); executed = true; if (creationFailure != null) { if (creationFailure instanceof IOException) { throw (IOException) creationFailure; } else if (creationFailure instanceof RuntimeException) { throw (RuntimeException) creationFailure; } else { throw (Error) creationFailure; } } call = rawCall; if (call == null) { try { //createRawCall() 返回的是 OkHttp.RealCall類的實例 call = rawCall = createRawCall(); } catch (IOException | RuntimeException | Error e) { throwIfFatal(e); // Do not assign a fatal error to creationFailure. creationFailure = e; throw e; } } } if (canceled) { call.cancel(); } //解析服務端的響應數據 return parseResponse(call.execute()); } private okhttp3.Call createRawCall() throws IOException { //serviceMethod.toCall 返回的是 OkHttp.RealCall類的實例 // 所以這裏的call可以直接發起同步或異步請求 okhttp3.Call call = serviceMethod.toCall(args); if (call == null) { throw new NullPointerException("Call.Factory returned null."); } return call; } }
上面的代碼看起來還是很順的,但還是忍不住扔出幾個疑問,
- createRawCall函數中的call=OkHttp.RealCall類是如何創建的?
- 還有enqueue函數和execute函數中調用的parseResponse(rawResponse)函數,是怎麼解析響應數據的?
這兩個問題留到下一篇再去剖開,先記住createRawCall函數中生成的是OkHttp.RealCall類的實例即可
接着來到註釋3的代碼,調用了serviceMethod.adapt(okHttpCall),跟進去ServiceMethod類的adapt函數,發現調用到了CallAdapter接口的adapt函數,這裏就得去找CallAdapter接口的實現類,才能知道adapter函數返回的具體實現類是什麼,這個問題留到下一篇再去剖開,先記住這裏是返回了ExecutorCallbackCall類的實例
d. call發起異步請求
-
1.call.enqueue(): 此處的call = ExecutorCallbackCall類,這裏要結合上面的OkHttpCall類,來理清異步請求從Retrofit框架遞交到OkHttp框架的流程
-
在ExecutorCallbackCall類裏,通過OkHttpCall類發起異步請求,其中OkHttpCall類的createRawCall函數返回的是OkHttp.RealCall類的實例, 所以這裏實際上是RealCall.enqueue(),也就是將異步請求交給OkHttp框架去發起;
-
在OkHttpCall類中解析服務端返回的響應數據,轉換爲網絡請求函數中定義的返回類型,其中涉及到的數據轉換器類是BuiltInConverters 或 GsonResponseBodyConverter
-
通過MainThreadExecutor將子線程回調到主線程,在主線程中將響應結果回調返回
final class ExecutorCallAdapterFactory extends CallAdapter.Factory { static final class ExecutorCallbackCall<T> implements Call<T> { final Executor callbackExecutor; final Call<T> delegate; //這裏傳入的delegate = OkHttpCall實例,callbackExecutor = MainThreadExecutor實例 ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) { this.callbackExecutor = callbackExecutor; this.delegate = delegate; } @Override public void enqueue(final Callback<T> callback) { checkNotNull(callback, "callback == null"); //這裏的delegate = OkHttpCall實例 //OkHttpCall是對Retrofit.Call的實現,實際該類主要用到OkHttp.Call(rawCall這個變量) 來進行enqueue、execute請求 delegate.enqueue(new Callback<T>() { @Override public void onResponse(Call<T> call, final Response<T> response) { //callbackExecutor = MainThreadExecutor, 主要從子線程切換到主線程並返回響應結果 callbackExecutor.execute(new Runnable() { @Override public void run() { 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(new Runnable() { @Override public void run() { callback.onFailure(ExecutorCallbackCall.this, t); } }); } }); } @Override public Response<T> execute() throws IOException { //這裏的delegate = OkHttpCall實例 return delegate.execute(); } } }
3.總結
a. Retrofit構建過程
- 1.Retrofit.Builder(): 獲取對應平臺的Platform實例,這裏是獲取到Android類的實例. 在Android類裏提供生成網絡請求適配器MainThreadExecutor的函數
- 2.baseUrl(): 判斷基礎的url不能爲空,將String類型的url 轉化成 HttpUrl實例, HttpUrl類用了Build模式來創建
- 3.addConverterFactory(): 將數據轉換器添加到converterFactories這個存放數據轉換器(集合的元素類型爲Converter.Factory)的集合中
- 4.addCallAdapterFactory(): 將網絡請求適配器添加到callAdapterFactories這個存放網絡請求適配器(集合的元素類型爲CallAdapter.Factory)的集合中
- 5.build():
- 檢查了OkHttpClient和回調線程池類Executor是否傳入值,未傳入則創建默認的值,已傳入則使用開發者設置的值
- 往存放數據轉換器的集合 存入 開發者設置的數據轉換器(例如GsonConverterFactory) 和 系統默認的數據轉換器(BuiltInConverters)
- 往存放網絡請求適配器的集合 存入 開發者設置的網絡請求適配器(例如RxJavaCallAdapterFactory) 和系統默認的網絡請求適配器(ExecutorCallAdapterFactory)
- ExecutorCallAdapterFactory裏 存了 MainThreadExecutor實例
- 返回Retrofit實例
b. 創建請求接口的實例
-
1.retrofit.create():
- 使用動態代理模式對網絡請求接口類進行代理,返回代理接口的實例
c. 調用網絡請求接口的函數
-
1.github.contributors(): 這裏會回調到上一步返回的代理接口中的 InvocationHandler中的invoke函數
- 在invoke函數裏拿到網絡請求接口類的函數的註解、函數參數、函數返回值等相關信息,存入ServiceMethod裏
- 給ServiceMethod設置合適的數據轉換器和網絡請求適配器
- 創建OkHttpCall,OkHttpCall是對Retrofit.Call的實現,實際該類主要用到OkHttp.Call(rawCall這個變量) 來進行enqueue、execute請求
- 最後返回 ExecutorCallbackCall類(Retrofit的Call的實現類)的實例
d. call發起異步請求
-
1.call.enqueue(): 這裏的call = ExecutorCallbackCall類
- 通過OkHttpCall類發起異步請求,其中OkHttpCall類的createRawCall函數返回的是OkHttp.RealCall類的實例, 所以這裏是RealCall.enqueue()
- 解析服務端返回的響應數據,轉換爲網絡請求函數中定義的返回類型,其中涉及到的數據轉換器類是BuiltInConverters 或 GsonResponseBodyConverter
- 通過MainThreadExecutor將子線程回調到主線程,在主線程中將響應結果回調返回
4. 補充
Retrofit的Converter類可以使得請求函數的入參和返回類型豐富起來,比如請求函數的參數中有文件類型的,我們可以通過定製Converter類,使得入參時可直接傳File類型之類的元素. 同樣也可以根據返回類型,定製類似GsonResponseBodyConverter這樣的數據轉化器,具體的參考 深入淺出 Retrofit,這麼牛逼的框架你們還不來看看?