??? ??本文研究范圍僅限Android或者Java。?
??? ? 在研究Android插件化技術的時候,看到一句話:J2EE框架Spring通過動態代理的Hook機制優雅地實現了AOP編程,同樣,插件框架也廣泛使用了代理機制來增強系統API從而達到插件化的目的。
?????? 在這句話里,包含了本文標題中提到的四個關鍵字:動態代理、Hook、AOP、插件化技術。
?????? 這句話,提煉一下:AOP編程與插件化的具體實現用到了動態代理的Hook機制。
?????? 再分析一下:AOP與插件化應該是一種抽象的概念或者叫做思想,而實現這種思想,需要有具體的方式,動態代理正好是實現這種思想的一種極好選擇,然后在實現過程中,動態代理又需要利用一種叫做Hook的機制。
?????? 分析到此處,應該大概能了解了四者的聯系與區別:AOP與插件化技術是兩個抽象概念,二者沒有直接聯系,但有間接聯系,即都需要用動態代理或者準確點說是可以用動態代理加上Hook機制來實現;Hook與動態代理不是一個維度的,Hook是一種程序的運行機制,這種機制也能用動態代理來實現。????
?????? 有了上面的分析,其實理解的還是很糊糢,主要是我們對四者的了解太少。
四者的定義:
?????? Hook:又叫鉤子,通常是指對一些方法進行攔截,具體一點來說就是程序運行中,創建代理對象,然后把原始對象替換為代理對象。
?????? 動態代理:代理設計模式的一種實現,即代理類在程序運行時創建的代理方式被稱為動態代理。
??????? AOP:面向切面編程,是一種編程思想,也就是說面向某個功能模塊編程,在代碼層面上將該模塊與其它有交叉的模塊進行隔離。
??????? 插件化技術:也叫動態加載技術,將整個app拆分成很多模塊,這些模塊包括一個宿主和多個插件,每個模塊都是一個apk,插件模塊無需安裝,由宿主模塊動態加載。
回答幾個問題:
1.Hook是不是只能采用動態代理實現?
?????? ?Hook主要是程序行的過程中使用代理對象來替換被Hook的對象,動態代理也是在運行中,但強調的代理類的創建,既然代理類能被創建,那代理對象肯定也能被創建,所以Hook肯定能采用動態代理來實現,但是否是唯一方式,就需要考查是否能不通過動態代理在程序運行時創建代理對象。顯然是可以的,比如采用靜態代理,即代理類在程序編譯之前就提前寫好,完全能達到Hook的目的,只是沒有動態代理靈活而已。
???????? 所以Hook不只是能采用動態代理實現。
2.Hook是不是只能采用代理方式實現?
???????? 上面說了Hook還可以采用靜態代理來實現,那么還沒有其它方式實現Hook,完全不使用動態或靜態代理?
????????? 個人認為是不可能的,因為我們可以把Hook理解為鉤子,這個鉤子其實就是一個代理,雖然實現時可能會不完全符合代理模式的定義(比如可能并沒有在代理對象里訪問原對象),但是從本質上來說,這還是一種代理方式。
????????? 所以說Hook只能采用代理方式實現,更準確來說,Hook就是一種代理機制。
2.AOP是不是只能采用動態代理實現?
???? ?AOP是一種可以通過預編譯和運行期動態代理實現而不用修改源代碼的情況下給程序動態添加功能的一種技術。
??????本質上就是動態代理,只不過有各種實現技術而已。
????? 所以AOP只能采用動態代理實現。
3.插件化技術是不是只能采用動態代理來實現?
???????目前有很多插件化框架,基本上都用到了動態代理,比如DroidPlugin,但是否只能用動態代理來實現,回答是否定的。
?????? 插件化即宿主APK動態加載插件APK,而插件APK是不需要安裝的,所以插件化主要解決兩個問題:代碼加載與資源加載。其中的資源加載就不需要使用動態代理。
????? 代碼加載是否一定要使用動態代理?回答也是否定的。
????? 因為我們只要能實現動態加載代碼就能達到目的,如果假設Android的Activity不需要在Manifest中注冊,那么完全可以直接采用反射加載Activity類,但是實際上Android有一套組件訪問機制,正因為這套訪問機制會限制對非安裝APK的加載,所以很多框架才需要使用動態代理的Hook機制來繞過系統的訪問機制。而且除了動態代理,靜態代理方式也能達到Hook的目的。
????? 總結一下就是說,插件化與動態代理沒有直接聯系,只要我們能想辦法解決好代碼加載與資源加載的問題,就能實現插件化技術,動態代理的Hook機制只是提供了一種解決問題的思路,而且這種思路使問題的解決比較簡單。
4.AOP是不是必須用到Hook機制?
?????? AOP實現時有三種方式:生成子類字節碼、生成代理類字節碼、直接修改原類的字節碼。
?????? Hook機制關注點在于對象的替換,如果我們直接修改了原類的字節碼加入切面邏輯,是不存在Hook的,因為連Class都被修改了。如果生成了代理類的字節碼,再由字節碼生成代理類的對象,然后用代理類的對象來替換原對象,這是一個標準的Hook過程,肯定使用了Hook機制。
????? 所以AOP實現采用Hook機制只是其中一種方式,不是必須的方式。
最后再理一下四者具體的實現方法方式:
Hook的步驟:
1.尋找適合Hook點,它應該是一個成員變量,并且應該在我們需要注入的方法中調用過它的方法或者使用了它的的值。
2.創建繼承自Hook點的對象的子類,根據需求修改其相應的方法。
3.使用反射將我們自己創建的對象替換對象實例中的對象,達到偷梁換柱的目的。
動態代理三種實現方法:
1.JDK的動態代理:就是在程序運行的過程中,根據被代理的接口來動態生成代理類的class文 件,并加載運行的過程。
?2.cglib動態代理:cglib封裝了asm,可以在運行期動態生成新的class,以此來實現動態代理。
?3.Javassist:Javassist是一個開源的分析、編輯和創建Java字節碼的類庫。
AOP有兩類實現方式:
1.運行時AOP:運行時動態生成子類字節碼(Cglib)或代理類字節碼(JDK動態代理)或直接修改字節碼(Javassist、ASM、AspectJ)
?2.編譯時AOP:編譯時,修改字節碼(ASM、AspectJ)或生成代理類(APT)
Android插件技術實現過程:
使用動態加載,就是使用類加載器加載相應的apk、dex、jar(必須含有dex文件),再通過反射獲得該apk、dex、jar內部的資源(class、圖片、color等等)進而供宿主app使用。