? ? ? ? 最近常常看到一些資料時,是不是會看到動態(tài)代理黎休,但是在項目中卻好像沒怎么使用過動態(tài)代理浓领,所以對動態(tài)代理的理解也大概只有一個概念,最近部門規(guī)定势腮,每兩周最好要有一次技術(shù)分享联贩,所以就借著這個機(jī)會,好好梳理一下動態(tài)代理到底是什么東西捎拯,下面是今天需要了解的相關(guān)知識點泪幌,讓我們由淺入深一步步的了解什么是代理模式吧。
知識點匯總:
一:什么是代理模式
二:代理模式的常見實現(xiàn)方式:基于接口的代理模式 和 基于類繼承的代理模式
三:靜態(tài)代理與動態(tài)代理的區(qū)別與實現(xiàn)
四:代理模式在Android中的使用場景
五:擴(kuò)展閱讀
一:什么是代理模式
簡介:在Java編程里就有一種設(shè)計模式署照,即代理模式祸泪,提供了一種對目標(biāo)對象的訪問方式,即通過代理對象訪問目標(biāo)對象建芙,代理對象是指具有與被代理對象相同的接口的類浴滴,客戶端必須通過代理對象與被代理的目標(biāo)類進(jìn)行交互。
? ? ? ?代理模式主要分為三個角色:客戶端岁钓,代理類升略,目標(biāo)類;而代理類需要與目標(biāo)類實現(xiàn)同一個接口屡限,并在內(nèi)部維護(hù)目標(biāo)類的引用品嚣,進(jìn)而執(zhí)行目標(biāo)類的接口方法,并實現(xiàn)在不改變目標(biāo)類的情況下前攔截钧大,后攔截等所需的業(yè)務(wù)功能翰撑。
代理模式的優(yōu)點:
中間隔離:某些情況下,客戶端不想或者不能直接引用一個目標(biāo)對象啊央,而代理類可以在客戶端和目標(biāo)類之前起到中介作用
開閉原則眶诈,擴(kuò)展功能:代理類除了是客戶類和目標(biāo)類的中介,還可以通過給代理類增加額外的功能來擴(kuò)展目標(biāo)類的功能瓜饥,這樣我們只需要修改代理類而不需要再修改目標(biāo)類逝撬,符合代碼設(shè)計的開閉原則(對擴(kuò)展開放,對修改關(guān)閉)乓土。代理類主要負(fù)責(zé)為目標(biāo)類預(yù)處理消息宪潮、過濾消息、把消息轉(zhuǎn)發(fā)給目標(biāo)類趣苏,以及事后對返回結(jié)果的處理等狡相。
? ? ? 代理類本身并不真正實現(xiàn)服務(wù),而是同過調(diào)用目標(biāo)類的相關(guān)方法食磕,來提供特定的服務(wù)尽棕。真正的業(yè)務(wù)功能還是由目標(biāo)類來實現(xiàn),但是可以在業(yè)務(wù)功能執(zhí)行的前后加入一些公共的服務(wù)彬伦。例如我們想給項目加入緩存滔悉、日志這些功能蟀悦,我們就可以使用代理類來完成,而沒必要打開已經(jīng)封裝好的目標(biāo)類氧敢。
代理模式的結(jié)構(gòu):
圖解:
代理模式的分類:(大概了解一下就好)
遠(yuǎn)程代理:為不同地理的對象提供局域網(wǎng)代表對象日戈。
虛擬代理:根據(jù)需要將資源消耗很大的對象進(jìn)行延遲,真正需要的時候再創(chuàng)建孙乖。
安全代理:控制用戶的訪問權(quán)限浙炼。
智能代理:提供對目標(biāo)對象額外的服務(wù)「使用最多的」。(靜態(tài)代理和動態(tài)代理)
二:代理模式的常見實現(xiàn)方式:基于接口的代理模式 和 基于類繼承的代理模式
基于接口的代理模式:
描述:一個比較直觀的方式唯袄,就是定義一個功能接口弯屈,然后讓Proxy和RealSubject來實現(xiàn)這個接口。
定義接口:
public interface ILogin {
voiduserLogin();
}
定義目標(biāo)類:(被代理類)
public class UserLogin implements ILogin {
@Override
public void userLogin() {
System.out.print("用戶登錄");
???}
}
定義代理類:
public classUserLoginProxyimplementsILogin{
privateUserLoginmLogin;
???publicUserLoginProxy() {
???????mLogin= newUserLogin();
???}
???@Override
???public voiduserLogin() {
???????System.out.print("登錄前恋拷。资厉。。");
???????mLogin.userLogin();
???????System.out.print("登錄后蔬顾。宴偿。。");
???}
}
客戶端:
public class Test {
???public static void main(String[]args){
???????ILoginloginProxy= newUserLoginProxy();
???????loginProxy.userLogin();
???}
}
基于類繼承的代理模式:
描述:還有比較隱晦的方式诀豁,就是通過繼承窄刘,因為如果Proxy繼承自RealSubject,這樣Proxy則擁有了RealSubject的功能舷胜,Proxy還可以通過重寫RealSubject中的方法娩践,來實現(xiàn)多態(tài)。
//定義目標(biāo)類:(被代理類)
???public classRealSubject{
???????public voiduserLogin() {
???????}
???}
???//定義代理類
???public class Proxy extendsRealSubject{
???????@Override
???????public voiduserLogin() {
???????????//todo:添加代理類代碼
???????????super.userLogin();
???????????//todo:添加代理類代碼
???????}
???}
三:靜態(tài)代理與動態(tài)代理的區(qū)別與實現(xiàn)
代理實現(xiàn)方式:如果按照代理創(chuàng)建的時期來進(jìn)行分類的話烹骨, 可以分為靜態(tài)代理翻伺、動態(tài)代理。
一:靜態(tài)代理是由程序員創(chuàng)建或特定工具自動生成代理類沮焕,再對其編譯吨岭,在程序運(yùn)行之前,代理類.class文件就已經(jīng)被創(chuàng)建了遇汞。
二:動態(tài)代理是在程序運(yùn)行時通過反射機(jī)制動態(tài)創(chuàng)建代理對象未妹。
圖解:
圖解二:
類加載詳細(xì)流程:
靜態(tài)代理總結(jié):
優(yōu)點:
1簿废、在符合開閉原則的情況下空入,對目標(biāo)對象功能進(jìn)行擴(kuò)展和攔截。
2族檬、在訪問無法訪問的資源歪赢,增強(qiáng)現(xiàn)有的接口業(yè)務(wù)功能方面有很大的優(yōu)點。
3单料、一個代理類只能代理一個真實的對象埋凯。
缺點:
1点楼、需要為每個目標(biāo)類創(chuàng)建代理類和接口,導(dǎo)致類的數(shù)量大大增加白对,工作量大掠廓,導(dǎo)致系統(tǒng)結(jié)構(gòu)比較臃腫和松散。
2甩恼、接口功能一旦修改蟀瞧,代理類和目標(biāo)類也得相應(yīng)修改,不易維護(hù)条摸。
動態(tài)代理實現(xiàn):
技術(shù)實現(xiàn):
簡述:動態(tài)代理是java設(shè)計模式中代理模式的另一種實現(xiàn)悦污,通過JVM在運(yùn)行期通過反射為委托的接口類動態(tài)的生成代理的一種技術(shù)。
目前動態(tài)代理技術(shù)主要分為:
1钉蒲、Java自己提供的JDK動態(tài)代理技術(shù)(只能實現(xiàn)基于接口的代理模式)
2切端、CGLIB技術(shù)(Android中不能使用,使用原理相似技術(shù):ASM和Javaasis)
一:基于接口的代理模式(動態(tài)實現(xiàn))
??在動態(tài)代理中顷啼,不需要我們再手動創(chuàng)建代理類踏枣,只需要編寫一個動態(tài)處理器及指定要代理的目標(biāo)對象實現(xiàn)的接口,真正的代理對象由JDK在運(yùn)行時為我們創(chuàng)建钙蒙;JDK提供了java.lang.reflect.InvocationHandler和java.lang.reflect.Proxy來實現(xiàn)動態(tài)代理椰于。
簡述:Proxy.getProxyClass(ClassLoader, interfaces)方法只需要接收一個類加載器和一組接口就可以返回一個代理Class對象,然后就可以通過反射創(chuàng)建代理實例仪搔,其原理就是從傳入的接口Class中瘾婿,拷貝類結(jié)構(gòu)信息到一個新的Class對象中,并繼承Proxy類烤咧,擁有構(gòu)造方法偏陪;站在我們的角度就是通過接口Class對象創(chuàng)建代理類Class對象。
代碼實現(xiàn):
方法一:代理類對象生成代碼
public static ObjectloadProxy(Object target) throws Exception {
???????//通過接口Class對象創(chuàng)建代理Class對象
???????Class?proxyClass=Proxy.getProxyClass(target.getClass().getClassLoader(),target.getClass().getInterfaces());
???????//拿到代理Class對象的有參構(gòu)造方法
???????Constructor<?> constructors =proxyClass.getConstructor(InvocationHandler.class);
???????//反射創(chuàng)建代理實例
???????Object proxy =constructors.newInstance(newInvocationHandler() {
???????????@Override
???????????public Object invoke(Object proxy, Methodmethod, Object[]args) throwsThrowable{
???????????????System.out.println("執(zhí)行前日志..."+"\n");
???????????????//執(zhí)行目標(biāo)類的方法
???????????????Object result =method.invoke(target,args);
???????????????System.out.println("執(zhí)行后日志..."+"\n");
???????????????return result;
???????????}
???????});
???????return proxy;
???}
客戶端調(diào)用:
public static void main(String[]args) throws Exception {
???????ILoginproxy = (ILogin)loadProxy(newUserLogin());
???????proxy.userLogin();
???}
方法二:代理類對象生成代碼(與retrofit類似)
Proxy類還有個更簡單的方法newProxyInstance煮嫌,直接返回代理對象笛谦,如下:
???public static ObjectloadProxy(Object object) {
???????returnProxy.newProxyInstance(
?????????????object.getClass().getClassLoader(), //和目標(biāo)對象的類加載器保持一致
?????????????object.getClass().getInterfaces(), //目標(biāo)對象實現(xiàn)的接口,因為需要根據(jù)接口動態(tài)生成代理對象
???????????????newInvocationHandler() { //事件處理器昌阿,即對目標(biāo)對象方法的執(zhí)行
???????????@Override
???????????publicObject invoke(Object proxy, Methodmethod, Object[]args) throwsThrowable{
???????????????????????System.out.println("執(zhí)行前日志...");
???????????????????????Object result =method.invoke(object,args);
???????????????????????System.out.println("執(zhí)行后日志...");
???????????????????????return result;
???????????????????}
???????????????});
???}
代理類:(動態(tài)生成基于接口的代理類代碼)
public final class $Proxy0 extends Proxy implementsILogin
{
???public $Proxy0(InvocationHandlerinvocationhandler){
???????super(invocationhandler);
???}
???public finalbooleanequals(Objectobj){
???????try{
???????????return ((Boolean)super.h.invoke(this, m1, new Object[] {
???????????????obj
???????????})).booleanValue();
???????}
???????catch(Error _ex) { }
???????catch(Throwablethrowable){
???????????throw newUndeclaredThrowableException(throwable);
???????}
???}???
?public final StringtoString(){
???????try{
???????????return (String)super.h.invoke(this, m2, null);
???????}
???????catch(Error _ex) { }
???????catch(Throwablethrowable){
???????????throw newUndeclaredThrowableException(throwable);
???????}
???}
???public final voiduserLogin(){
???????try{
???????????super.h.invoke(this, m3, null);
???????????return;
???????}
???????catch(Error _ex) { }
???????catch(Throwablethrowable){
???????????throw newUndeclaredThrowableException(throwable);}
???}
public finalinthashCode(){
???????try{
???????????return ((Integer)super.h.invoke(this, m0, null)).intValue();
???????}
???????catch(Error _ex) { }
???????catch(Throwablethrowable){
???????????throw newUndeclaredThrowableException(throwable);
???????}
???}
???private static Method m1;
???private static Method m2;
???private static Method m3;
???private static Method m0;
}
static{
???????try{
???????????m1 =Class.forName("java.lang.Object").getMethod("equals", new Class[] {
???????????????Class.forName("java.lang.Object")
???????????});
???????????m2 =Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
???????????m3 =Class.forName("com.mango.demo.proxy.ILogin").getMethod("userLogin", new Class[0]);
???????????m0 =Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
???????}
???????catch(NoSuchMethodExceptionnosuchmethodexception){
???????????throw newNoSuchMethodError(nosuchmethodexception.getMessage());
???????}
???????catch(ClassNotFoundExceptionclassnotfoundexception){
???????????throw newNoClassDefFoundError(classnotfoundexception.getMessage());
???????}
???}
生成代理類解析:
1饥脑、JDK為我們生成了一個$Proxy0(這個名字后面的0是編號,有多個代理類會一次遞增)的代理類懦冰。
2灶轰、代理類實現(xiàn)了ILogin接口,繼承了Proxy類刷钢,并有一個帶InvocationHandler參數(shù)的構(gòu)造方法笋颤,使用super調(diào)用Proxy類的構(gòu)造方法,證實了上面的分析内地。
3伴澄、實現(xiàn)了接口的userLogin方法赋除,并在其內(nèi)部調(diào)用InvocationHandler的invoke方法,其h正是Proxy類定義的成員變量非凌。
4举农、最下面是通過反射拿到類中的幾個方法,作為參數(shù)傳遞到InvocationHandler.invoke方法中敞嗡,即調(diào)用動態(tài)代理對象的任何方法并蝗,最終都是走到InvocationHandler.invoke方法中(所以在invoke方法中寫日志需要判斷下,是否是調(diào)用代理對象指定的方法走到這里)秸妥。
JDK主要會做以下工作:
1滚停、獲取 RealSubject上的所有接口列表。
2粥惧、確定要生成的代理類的類名键畴,默認(rèn)為:com.sun.proxy.$ProxyXXXX。
3突雪、根據(jù)需要實現(xiàn)的接口信息起惕,在代碼中動態(tài)創(chuàng)建該P(yáng)roxy類的字節(jié)碼。
4咏删、將對應(yīng)的字節(jié)碼轉(zhuǎn)換為對應(yīng)的class對象惹想。
5、創(chuàng)建InvocationHandler實例handler督函,用來處理Proxy所有方法調(diào)用嘀粱。
6、Proxy的class對象以創(chuàng)建的handler對象為參數(shù)辰狡,實例化一個proxy對象锋叨。
仔細(xì)觀察可以看出生成的動態(tài)代理類有以下特點:(并非上圖代碼demo)
1、繼承自java.lang.reflect.Proxy宛篇,實現(xiàn)了Rechargable,Vehicle這兩個ElectricCar實現(xiàn)的接口娃磺;
2、類中的所有方法都是final的叫倍;
3偷卧、所有的方法功能的實現(xiàn)都統(tǒng)一調(diào)用了InvocationHandler的invoke()方法。
JDK動態(tài)代理總結(jié):(基于接口的代理模式)
優(yōu)點:
1吆倦、相對于靜態(tài)代理听诸,極大的減少類的數(shù)量,降低工作量逼庞,減少對業(yè)務(wù)接口的依賴蛇更,降低耦合,便于后期維護(hù)赛糟;
2派任、同時在某些情況下是最大的優(yōu)勢,即可以統(tǒng)一修改代理類的方法邏輯璧南,而不需要像靜態(tài)代理需要修改每個代理類掌逛。
3、動態(tài)代理中所謂的“動態(tài)”司倚,是針對使用Java代碼實際編寫了代理類的“靜態(tài)”代理而言的豆混,它的主要優(yōu)勢不在于省去了編寫代理類那一點工作量,而是實現(xiàn)了可以在原始類和接口還未知的時候动知,就確定代理類的代理行為皿伺,當(dāng)代理類與原始類脫離直接聯(lián)系后,就可以很靈活地重用于不同的應(yīng)用場景之中盒粮。(深入理解Java虛擬機(jī))
缺點:
1鸵鸥、因為使用的是反射,所以在運(yùn)行時會消耗一定的性能丹皱;
2妒穴、同時JDK代理只支持interface的動態(tài)代理,如果你再繼續(xù)深究源碼摊崭,會發(fā)現(xiàn)讼油,所有動態(tài)生成的代理對象都有一個共同的父類,即都繼承于Proxy呢簸;
3矮台、Java的單繼承機(jī)制決定了無法支持class的動態(tài)代理,也就意味著你拿到動態(tài)生成的代理對象根时,只能調(diào)用其實現(xiàn)的接口里的方法嘿架,無法像靜態(tài)代理中的代理類可以在內(nèi)部擴(kuò)展更多的功能。
二:基于類的代理類實現(xiàn)(動態(tài)實現(xiàn))
簡述:JDK動態(tài)代理是實現(xiàn)AOP編程的一種途徑啸箫,可以在執(zhí)行指定方法前后貼入自己的邏輯耸彪,像Spring、Struts2就有用到該技術(shù)(攔截器設(shè)計就是基于AOP的思想)忘苛,只不過JDK動態(tài)代理只能實現(xiàn)基于接口的動態(tài)代理蝉娜,也算是一個遺憾,還有這種實現(xiàn)方式也不能避免類數(shù)量增加扎唾,因為你必須要為每個業(yè)務(wù)類編寫業(yè)務(wù)接口召川。
提問:那么有沒有不用寫代理類、也不用寫業(yè)務(wù)接口的代理方法呢胸遇?
解答:使用CGLib了荧呐,CGLIB(CodeGeneration Library)是一個強(qiáng)大的愁拭,高性能,高質(zhì)量的Code生成類庫梯皿,它可以在運(yùn)行期擴(kuò)展Java類與實現(xiàn)Java接口暑诸。
? ? ? CGLIB比JDK的代理更加強(qiáng)大,不只可以實現(xiàn)接口峰搪,還可以擴(kuò)展類岔冀,通過字節(jié)碼技術(shù)為一個類創(chuàng)建子類,并在子類中采用方法攔截的技術(shù)攔截所有父類方法的調(diào)用概耻,順勢植入橫切邏輯使套。但因為采用的是繼承,所以不能對final修飾的類進(jìn)行代理鞠柄。
? ? ? ?CGLIB底層封裝了ASM侦高,通過對字節(jié)碼的操作來生成類,具有更高的性能厌杜,但是CGLIB創(chuàng)建代理對象時所花費的時間卻比JDK多奉呛;ASM是一套JAVA字節(jié)碼生成架構(gòu),能夠動態(tài)生成.class文件并在加載進(jìn)內(nèi)存之前進(jìn)行修改期奔。
? ? ?使用CGLIB需要引用jar包cglib-nodep-3.2.5.jar(如果引入cglib.jar侧馅,還需要引入asm的jar包)。
? ? ? 但是在Android中的字節(jié)碼生成技術(shù)呐萌,一般使用:ASM和Javassist馁痴。
Java字節(jié)碼生成開源框架介紹--ASM:
簡述:ASM 是一個 Java 字節(jié)碼操控框架。它能夠以二進(jìn)制形式修改已有類或者動態(tài)生成類肺孤。ASM 可以直接產(chǎn)生二進(jìn)制 class 文件罗晕,也可以在類被加載入 Java 虛擬機(jī)之前動態(tài)改變類行為。ASM 從類文件中讀入信息后赠堵,能夠改變類行為小渊,分析類信息,甚至能夠根據(jù)用戶要求生成新類茫叭。
? ? ? ?不過ASM在創(chuàng)建class字節(jié)碼的過程中酬屉,操縱的級別是底層JVM的匯編指令級別,這要求ASM使用者要對class組織結(jié)構(gòu)和JVM匯編指令有一定的了解揍愁。
? ? ? ?使用ASM框架提供了ClassWriter接口呐萨,通過訪問者模式進(jìn)行動態(tài)創(chuàng)建class字節(jié)碼,看下面的例子:
ASM動態(tài)生成代碼:
public static void main(String[]args) throwsIOException{
???????????System.out.println();
???????????ClassWriterclassWriter= newClassWriter(0);
???????????//通過visit方法確定類的頭部信息
???????????classWriter.visit(Opcodes.V1_7,// java版本
???????????????????Opcodes.ACC_PUBLIC,//類修飾符
???????????????????"Programmer", //類的全限定名
???????????????????null, "java/lang/Object", null);
???????????//創(chuàng)建構(gòu)造函數(shù)
???????????MethodVisitormv =classWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
???????????mv.visitCode();
???????????mv.visitVarInsn(Opcodes.ALOAD, 0);
???????????mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>","()V");
???????????mv.visitInsn(Opcodes.RETURN);
???????????mv.visitMaxs(1, 1);
???????????mv.visitEnd();
}
ASM動態(tài)生成代碼:(合并上面代碼)?????????
??????????//定義code方法
???????????MethodVisitormethodVisitor=classWriter.visitMethod(Opcodes.ACC_PUBLIC, "code", "()V",
???????????????????null, null);
???????????methodVisitor.visitCode();
???????????methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out",
???????????????????"Ljava/io/PrintStream;");
???????????methodVisitor.visitLdcInsn("I'm aProgrammer,JustCoding.....");
???????????methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println",
???????????????????"(Ljava/lang/String;)V");
???????????methodVisitor.visitInsn(Opcodes.RETURN);
???????????methodVisitor.visitMaxs(2, 2);
???????????methodVisitor.visitEnd();
???????????classWriter.visitEnd();
???????????//使classWriter類已經(jīng)完成
???????????//將classWriter轉(zhuǎn)換成字節(jié)數(shù)組寫到文件里面去
???????????byte[] data =classWriter.toByteArray();
???????????Filefile= new File("D://Programmer.class");
???????????FileOutputStreamfout= newFileOutputStream(file);
???????????fout.write(data);
???????????fout.close();
Java字節(jié)碼生成開源框架介紹--Javassist:
簡述:Javassist是一個開源的分析莽囤、編輯和創(chuàng)建Java字節(jié)碼的類庫谬擦。是由東京工業(yè)大學(xué)的數(shù)學(xué)和計算機(jī)科學(xué)系的 Shigeru Chiba(千葉滋)所創(chuàng)建的。它已加入了開放源代碼JBoss應(yīng)用服務(wù)器項目,通過使用Javassist對字節(jié)碼操作為JBoss實現(xiàn)動態(tài)AOP框架朽缎。javassist是jboss的一個子項目惨远,其主要的優(yōu)點谜悟,在于簡單,而且快速北秽。直接使用java編碼的形式葡幸,而不需要了解虛擬機(jī)指令,就能動態(tài)改變類的結(jié)構(gòu)羡儿,或者動態(tài)生成類礼患。
Javassist動態(tài)生成代碼:
publicstatic void main(String[]args) throws Exception {
???????????ClassPoolpool =ClassPool.getDefault();
???????????//創(chuàng)建Programmer類?
???????????CtClasscc=pool.makeClass("com.samples.Programmer");
???????????//定義code方法
???????????CtMethodmethod =CtNewMethod.make("public void code(){}", cc);
???????????//插入方法代碼
???????????method.insertBefore("System.out.println(\"I'm aProgrammer,JustCoding.....\");");
???????????cc.addMethod(method);
???????????//保存生成的字節(jié)碼
???????????cc.writeFile("d://temp");
???????}
四:代理模式在Android中的使用場景
一:Retrofit中的動態(tài)代理
二:AIDL實現(xiàn)進(jìn)程之間的通信(底層使用Binder實現(xiàn))
三:Android的插件化實現(xiàn)原理之--hook機(jī)制
一:Retrofit中的動態(tài)代理
調(diào)用代碼:GitHubServiceservice =retrofit.create(GitHubService.class);
?????????????????????Call<List<Repo>> repos =service.listRepos("octocat");
Retrofit源碼實現(xiàn):
public<T> T create(final Class<T> service) {
???????Utils.validateServiceInterface(service);
???????if (validateEagerly) {
???????????eagerlyValidateMethods(service);
???????}
???????return (T)Proxy.newProxyInstance(service.getClassLoader(), new Class[] { service },
???????????????newInvocationHandler() {
???????????????????private final Platformplatform=Platform.get();
???????????????????@Override public Object invoke(Object proxy, Methodmethod, @NullableObject[]args)
???????????????????????????throwsThrowable{
???????????????????????// If the method is a method from Object then defer to normal invocation.
???????????????????????if (method.getDeclaringClass() ==Object.class) {
???????????????????????????returnmethod.invoke(this,args);
???????????????????????}
???????????????????????if (platform.isDefaultMethod(method)) {
???????????????????????????returnplatform.invokeDefaultMethod(method, service, proxy,args);
???????????????????????}
???????????????????????ServiceMethod<Object, Object>serviceMethod=
???????????????????????????????(ServiceMethod<Object, Object>)loadServiceMethod(method);
???????????????????????OkHttpCall<Object>okHttpCall= newOkHttpCall<>(serviceMethod,args);
???????????????????????returnserviceMethod.adapt(okHttpCall);
???????????????????}
???????????????});
???}
Retrofit動態(tài)代理實現(xiàn)流程圖:
二:AIDL實現(xiàn)進(jìn)程之間的通信(底層使用Binder實現(xiàn))
自定義通信接口:
interfaceIMyAidlInterface{
???????intgetBookCount();
???????voidaddBook(String book,intprice);
???}
生成的代理類代碼:(去除部分代碼是钥,僅保留關(guān)鍵代碼)
publicinterfaceIMyAidlInterfaceextendsandroid.os.IInterface{
???public static abstract class Stub extendsandroid.os.Binderimplementscom.jerey.learning.IMyAidlInterface{
???????private static finaljava.lang.StringDESCRIPTOR = "com.jerey.learning.IMyAidlInterface";
???????publicStub(){
???????????this.attachInterface(this, DESCRIPTOR);
???????}
???????public staticcom.jerey.learning.IMyAidlInterfaceasInterface(android.os.IBinderobj) {
???????}
???????@Override publicandroid.os.IBinderasBinder(){
???????????return this;
???????}
???????@Override publicbooleanonTransact(intcode,android.os.Parceldata,android.os.Parcelreply,intflags) throwsandroid.os.
???????RemoteException{
???????????returnsuper.onTransact(code, data, reply, flags);
???????}
????????//多么熟悉的Proxy
???????private static class Proxy implementscom.jerey.learning.IMyAidlInterface{
???????????privateandroid.os.IBindermRemote;
???????????Proxy(android.os.IBinderremote){
???????????????mRemote= remote;?
}
@Override publicandroid.os.IBinderasBinder(){
???????????????returnmRemote;
}
???????????publicjava.lang.StringgetInterfaceDescriptor(){
???????????????return DESCRIPTOR;
???????????}
???????????@Override publicintgetBookCount() throwsandroid.os.RemoteException{?//.........................
???????????}
???????????@Override public voidaddBook(java.lang.Stringbook,intprice) throwsandroid.os.RemoteException{?//........................
???????????}
???????}
???????static finalintTRANSACTION_getBookCount= (android.os.IBinder.FIRST_CALL_TRANSACTION+ 0);
???????static finalintTRANSACTION_addBook= (android.os.IBinder.FIRST_CALL_TRANSACTION+ 1);
???}
???publicintgetBookCount() throwsandroid.os.RemoteException;
???public voidaddBook(java.lang.Stringbook,intprice) throwsandroid.os.RemoteException;
}
附加:生成的代理類請參考網(wǎng)址:https://www.reibang.com/p/5646b9b7b898
三:Android的插件化實現(xiàn)原理之--hook機(jī)制
解析:調(diào)用采用了動態(tài)代理的辦法掠归,如果我們自己創(chuàng)建代理對象,然后把原始對象替換為我們的代理對象悄泥,那么就可以在這個代理對象為所欲為了虏冻,修改參數(shù),替換返回值弹囚,我們稱之為Hook厨相。
???首先我們得找到被Hook的對象,我稱之為Hook點鸥鹉;什么樣的對象比較好Hook呢蛮穿?自然是容易找到的對象。什么樣的對象容易找到毁渗?
1践磅、靜態(tài)變量和單例,在一個進(jìn)程之內(nèi)灸异,靜態(tài)變量和單例變量是相對不容易發(fā)生變化的府适,因此非常容易定位,而普通的對象則要么無法標(biāo)志肺樟,要么容易改變檐春。
2、盡量Hookpulic的對象和方法么伯,非public不保證每個版本都一樣疟暖,需要適配。
??找到了Hook點之后田柔,這個hook點就是一個被代理對象俐巴,我們就可以動態(tài)的生成代理類,創(chuàng)建代理類對象凯楔,并通過反射獲取被代理對象窜骄,然后把被代理對象替換成我們的代理類對象,從而達(dá)到擴(kuò)展被代理對象的功能摆屯,甚至完全修改相關(guān)操作行為邻遏。??
五:擴(kuò)展閱讀
1糠亩、https://blog.csdn.net/qq_30993595/article/details/90796869(Android開發(fā)如何理解Java靜態(tài)代理 動態(tài)代理及動態(tài)生成代理對象原理 看這篇就夠了)
2、http://www.reibang.com/p/64d205a159e6(一次Android權(quán)限刪除經(jīng)歷)
3准验、https://blog.csdn.net/sinat_23092639/article/details/102237404(從動態(tài)代理角度看Retrofit)
4赎线、http://www.reibang.com/p/7068295be51a(Android中使用Java的動態(tài)代理)
5、http://weishu.me/2016/01/28/understand-plugin-framework-proxy-hook/(Android插件化原理解析——Hook機(jī)制之動態(tài)代理)
6糊饱、http://www.reibang.com/p/08203d371f1c(將cglib動態(tài)代理思想帶入Android開發(fā))
7垂寥、http://www.reibang.com/p/e709aff78a53(Java動態(tài)代理機(jī)制詳解)
8、https://segmentfault.com/a/1190000012278673(人人都會設(shè)計模式:代理模式--Proxy)
9另锋、https://blog.csdn.net/yingpaixiaochuan/article/details/85232965(動態(tài)代理在Retrofit中的使用)
10滞项、https://www.ibm.com/developerworks/cn/java/j-lo-proxy1/index.html(Java動態(tài)代理機(jī)制分析及擴(kuò)展,第1部分)
11夭坪、http://weishu.me/2016/01/28/understand-plugin-framework-proxy-hook/(Android插件化原理解析——Hook機(jī)制之動態(tài)代理)
12文判、http://weishu.me/2016/01/28/understand-plugin-framework-overview/(Android插件化原理解析——概要)