以前一系列的關於Retrofit
使用和封裝的講解事後,想必對Retrofit
的靈活性和擴展性有何深刻的瞭解,既然如此咱們就對於Retrofit
內部實現原理來深刻的學習,既然要用就要理解怎麼用和怎麼能用的的更好,不能侷限在使用的層面上,接下來的文章從源碼的角度去思考和借鑑如何才能寫出一個好的開源框架。html
RxRetrofit封裝-專欄java
Retrofit
2.0是如何進行網絡請求的呢?主要是用到了Java
的動態代理,因此在深刻學習以前,先來了解下Java
的動態代理git
Java
動態代理其實Java
動態代理就是設計模式中的代理模式,特徵是代理類與委託類有一樣的接口,代理類主要負責爲委託類預處理消息、過濾消息、把消息轉發給委託類,以及過後處理消息等。代理類與委託類之間一般會存在關聯關係,一個代理類的對象與一個委託類的對象關聯,代理類的對象自己並不真正實現服務,而是經過調用委託類的對象的相關方法,來提供特定的服務。 程序員
通俗來講:好比登陸以前須要判斷用戶信息是否完整、請求以前須要配置請求數據等等,動態代理就是來處理這樣的需求,讓用戶只須要關心事件處理github
按照代理的建立時期,代理類能夠分爲兩種。 設計模式
靜態代理:由程序員建立或特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了。 網絡
動態代理:在程序運行時,運用反射機制動態建立而成。 框架
靜態代理其實就是按照代理模式,在實現了代理類和委託類以後的調用方式,能夠把它當作是代理模式的寫法eclipse
/** * 接口 * Created by WZG on 2017/1/19. */
public interface HttpRequest {
/** * 請求 */
void request();
}複製代碼
/** * 委託類 * Created by WZG on 2017/1/19. */
public class HttpRequestImpl implements HttpRequest {
@Override
public void request() {
Log.e("tag","-------->htt請求");
}
}複製代碼
/** * 代理類-靜態 * Created by WZG on 2017/1/19. */
public class HttpRequestProxy implements HttpRequest {
HttpRequestImpl httpRequest;
public HttpRequestProxy(HttpRequestImpl httpRequest) {
this.httpRequest = httpRequest;
}
@Override
public void request() {
Log.e("tag","靜態--------->http請求前");
httpRequest.request();
Log.e("tag","靜態--------->http請求後");
}
}複製代碼
/*靜態代理*/
HttpRequestImpl request = new HttpRequestImpl();
HttpRequestProxy proxy = new HttpRequestProxy(request);
proxy.request();複製代碼
動態代理,字面可理解在代理類中委託類是動態生成的,及時一個動態代理類可處理多個委託類,從而簡化代理類的處理。ide
Java
動態代理分爲兩種
JDK
動態代理-自帶
CGlib
動態代理-第三方
JDK
動態代理JDK
動態代理加載器 Proxy
public class Proxy implements Serializable {
protected InvocationHandler h;
protected Proxy(InvocationHandler h) {
throw new RuntimeException("Stub!");
}
public static Class<?> getProxyClass(ClassLoader loader, Class... interfaces) throws IllegalArgumentException {
throw new RuntimeException("Stub!");
}
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
throw new RuntimeException("Stub!");
}
public static boolean isProxyClass(Class<?> cl) {
throw new RuntimeException("Stub!");
}
public static InvocationHandler getInvocationHandler(Object proxy) throws IllegalArgumentException {
throw new RuntimeException("Stub!");
}
}複製代碼
在Proxy類中的newProxyInstance()方法中須要一個ClassLoader類的實例,ClassLoader實際上對應的是類加載器,在Java中主要有一下三種類加載器;
Booststrap ClassLoader:此加載器採用C++編寫,通常開發中是看不到的;
Extendsion ClassLoader:用來進行擴展類的加載,通常對應的是jre\lib\ext目錄中的類;
AppClassLoader:(默認)加載classpath指定的類,是最常使用的是一種加載器。
這裏使用第三種AppClassLoader
,主要使用newProxyInstance
方法去加載
參數 | 含義 |
---|---|
ClassLoader loader | 指被代理的對象 |
Class<?>[] interfaces | 要調用的方法 |
InvocationHandler h | 方法調用時所須要的參數 |
JDK
動態代理類處理方法主要是依賴InvocationHandler
接口
public interface InvocationHandler {
Object invoke(Object var1, Method var2, Object[] var3) throws Throwable;
}複製代碼
invoke
方法是動態代理類處理的主要方法
參數 | 含義 |
---|---|
Object var1 | 指被代理的對象 |
Method var2 | 要調用的方法 |
Object[] var3 | 方法調用時所須要的參數 |
共用HttpRequest
接口,不在重複描述
/** * 動態代理-jdk * Created by WZG on 2017/1/19. */
public class HttpRequestJDKProxy implements InvocationHandler {
private Object target;
/** * 綁定委託對象並返回一個代理類 * @param target * @return */
public Object bind(Object target) {
this.target = target;
//取得代理對象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this); //要綁定接口(這是一個缺陷,cglib彌補了這一缺陷)
}
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
Log.e("tag","jdk--------->http請求前");
Object result=method.invoke(target, objects);
Log.e("tag","jdk--------->http請求後");
return result;
}
}複製代碼
/*jdk動態代理*/
HttpRequestJDKProxy jdkProxy = new HttpRequestJDKProxy();
HttpRequest httpRequest = (HttpRequest) jdkProxy.bind(request);
httpRequest.request();複製代碼
CGlib
動態代理CGlib
動態代理實際上是國外一個開源做者寫的一個開源庫,幫助完善jdk
動態代理中
要綁定接口(這是一個缺陷)
Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);複製代碼
JDK
的動態代理機制只能代理實現了接口的類,而不能實現接口的類就不能實現JDK的動態代理,cglib
是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現加強,但由於採用的是繼承,因此不能對final
修飾的類進行代理
CGlib
代理類/** * cglib動態代理類 * Created by WZG on 2017/1/19. */
public class HttpRequestCglibProxy implements MethodInterceptor {
/** * 建立代理對象 * * @param target * @return */
public Object getInstance(Object target) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
// 回調方法
enhancer.setCallback(this);
// 建立代理對象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Log.e("tag", "Cglib--------->http請求前");
Object result= methodProxy.invokeSuper(o, objects);
Log.e("tag", "Cglib--------->http請求後");
return result;
}
}複製代碼
/*cglib動態代理*/
HttpRequestCglibProxy httpRequestCglibProxy=new HttpRequestCglibProxy();
HttpRequest httpRequestCglib = (HttpRequest) httpRequestCglibProxy.getInstance(new HttpRequestCglibImpl());
httpRequestCglib.request();複製代碼
可是因爲Android
中和java
環境的不一,致使在Android項目中其實並不能使用CGlib
這種動態代理方式,在java
環境中是可使用這個動態庫,因此這裏沒有顯示最後的輸出結果,eclipse
的java
項目是徹底能夠的(驗證過)
動態代理其實主流的使用是在Spring
中,最近一段時間纔剛剛流行到Android
,其實除了CGlib
動態代理之外,還有另一種好用的動態生成思路AOP
面向切片
AOP
面向切片想必對OOP
再熟悉不過了,那AOP
是什麼呢?AOP就是把涉及到衆多模塊的某一類問題進行統一管理,橫向的思考需求,而後統一管理處理通用的或者是公用的邏輯,下降項目耦合度,提高效率,簡化多餘代碼,通常AOP
結合Aspect
(也是Spring技術中大量使用),可是在Android中也有對應的變種AspectJ
.
固然因爲本文是Retrofit源碼解析-動態代理
這裏就不過多的闡述關於AOP
的技術了,有興趣的同窗能夠參考JakeWharton
-hugo
Retrofit
源碼解析-動態代理其中使用的就是本文中的第二種動態代理JDK
動態代理,因此使得Retrofit
在擴展性和維護行方面獲得很大的提高,可是其實也是有缺點的,由於JDK
動態代理裏面過多的使用了反射的機制,因此在效率方面是不及CGlib
代理處理的,估計也是因爲不支持Android
項目,因此被迫選擇這種方法,我的理解