從源碼的角度搞懂 Java 動(dòng)態(tài)代理!

Java技術(shù)棧
www.javastack.cn
關(guān)注閱讀更多優(yōu)質(zhì)文章
前言
最近,看了一下關(guān)于RMI(Remote Method Invocation)相關(guān)的知識(shí),遇到了一個(gè)動(dòng)態(tài)代理的問(wèn)題,然后就決定探究一下動(dòng)態(tài)代理。
這里先科普一下RMI。
RMI
像我們平時(shí)寫的程序,對(duì)象之間互相調(diào)用方法都是在同一個(gè)JVM中進(jìn)行,而RMI可以實(shí)現(xiàn)一個(gè)JVM上的對(duì)象調(diào)用另一個(gè)JVM上對(duì)象的方法,即遠(yuǎn)程調(diào)用。
接口定義
定義一個(gè)遠(yuǎn)程對(duì)象接口,實(shí)現(xiàn)Remote接口來(lái)進(jìn)行標(biāo)記。
public?interface?UserInterface?extends?Remote?{
????void?sayHello()?throws?RemoteException;
}
遠(yuǎn)程對(duì)象定義
定義一個(gè)遠(yuǎn)程對(duì)象類,繼承UnicastRemoteObject來(lái)實(shí)現(xiàn)Serializable和Remote接口,并實(shí)現(xiàn)接口方法。
public?class?User?extends?UnicastRemoteObject?implements?UserInterface?{
????public?User()?throws?RemoteException?{}
????@Override
????public?void?sayHello()?{
????????System.out.println("Hello?World");
????}
}
服務(wù)端
啟動(dòng)服務(wù)端,將user對(duì)象在注冊(cè)表上進(jìn)行注冊(cè)。
public?class?RmiServer?{
????public?static?void?main(String[]?args)?throws?RemoteException,?AlreadyBoundException,?MalformedURLException?{
????????User?user?=?new?User();
????????LocateRegistry.createRegistry(8888);
????????Naming.bind("rmi://127.0.0.1:8888/user",?user);
????????System.out.println("rmi?server?is?starting...");
????}
}
啟動(dòng)服務(wù)端:
客戶端
從服務(wù)端注冊(cè)表獲取遠(yuǎn)程對(duì)象,在服務(wù)端調(diào)用sayHello()方法。
public?class?RmiClient?{
????public?static?void?main(String[]?args)?throws?RemoteException,?NotBoundException,?MalformedURLException?{
????????UserInterface?user?=?(UserInterface)?Naming.lookup("rmi://127.0.0.1:8888/user");
????????user.sayHello();
????}
}
服務(wù)端運(yùn)行結(jié)果:
至此,一個(gè)簡(jiǎn)單的RMI demo完成。
動(dòng)態(tài)代理
提出問(wèn)題
看了看RMI代碼,覺(jué)得UserInterface這個(gè)接口有點(diǎn)多余,如果客戶端使用Naming.lookup()獲取的對(duì)象不強(qiáng)轉(zhuǎn)成UserInterface,直接強(qiáng)轉(zhuǎn)成User是不是也可以,于是試了一下,就報(bào)了以下錯(cuò)誤:
似曾相識(shí)又有點(diǎn)陌生的$Proxy0,翻了翻塵封的筆記找到了是動(dòng)態(tài)代理的知識(shí)點(diǎn),寥寥幾筆帶過(guò),所以決定梳理一下動(dòng)態(tài)代理,重新整理一份筆記。
動(dòng)態(tài)代理Demo
接口定義
public?interface?UserInterface?{
????void?sayHello();
}
真實(shí)角色定義
public?class?User?implements?UserInterface?{
????@Override
????public?void?sayHello()?{
????????System.out.println("Hello?World");
????}
}
調(diào)用處理類定義
代理類調(diào)用真實(shí)角色的方法時(shí),其實(shí)是調(diào)用與真實(shí)角色綁定的處理類對(duì)象的invoke()方法,而invoke()調(diào)用的是真實(shí)角色的方法。
這里需要實(shí)現(xiàn) InvocationHandler 接口以及invoke()方法。
public?class?UserHandler?implements?InvocationHandler?{
????private?User?user;
????public?UserProxy(User?user)?{
????????this.user?=?user;
????}
????@Override
????public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)?throws?Throwable?{
????????System.out.println("invoking?start....");
????????method.invoke(user);
????????System.out.println("invoking?stop....");
????????return?user;
????}
}
執(zhí)行類
public?class?Main?{
????public?static?void?main(String[]?args)?{
????????User?user?=?new?User();
????????//?處理類和真實(shí)角色綁定
????????UserHandler?userHandler?=?new?UserHandler(user);
????????//?開(kāi)啟將代理類class文件保存到本地模式,平時(shí)可以省略
????????System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles",?"true");
????????//?動(dòng)態(tài)代理生成代理對(duì)象$Proxy0
????????Object?o?=?Proxy.newProxyInstance(Main.class.getClassLoader(),?new?Class[]{UserInterface.class},?userHandler);
????????//?調(diào)用的其實(shí)是invoke()
????????((UserInterface)o).sayHello();
????}
運(yùn)行結(jié)果:
這樣動(dòng)態(tài)代理的基本用法就學(xué)完了,可是還有好多問(wèn)題不明白。
動(dòng)態(tài)代理是怎么調(diào)用的invoke()方法? 處理類UserHandler有什么作用? 為什么要將類加載器和接口類數(shù)組當(dāng)作參數(shù)傳入newProxyInstance?
假如讓你去實(shí)現(xiàn)動(dòng)態(tài)代理,你有什么設(shè)計(jì)思路?
猜想
動(dòng)態(tài)代理,是不是和靜態(tài)代理,即設(shè)計(jì)模式的代理模式有相同之處呢?
簡(jiǎn)單捋一捋代理模式實(shí)現(xiàn)原理:真實(shí)角色和代理角色共同實(shí)現(xiàn)一個(gè)接口并實(shí)現(xiàn)抽象方法A,代理類持有真實(shí)角色對(duì)象,代理類在A方法中調(diào)用真實(shí)角色對(duì)象的A方法。在Main中實(shí)例化代理對(duì)象,調(diào)用其A方法,間接調(diào)用了真實(shí)角色的A方法。
「實(shí)現(xiàn)代碼」
//?接口和真實(shí)角色對(duì)象就用上面代碼
//?代理類,實(shí)現(xiàn)UserInterface接口
public?class?UserProxy?implements?UserInterface?{
???//?持有真實(shí)角色對(duì)象
????private?User?user?=?new?User();
????@Override
????public?void?sayHello()?{
????????System.out.println("invoking?start....");
????????//?在代理對(duì)象的sayHello()里調(diào)用真實(shí)角色的sayHello()
????????user.sayHello();
????????System.out.println("invoking?stop....");
????}
}
//?運(yùn)行類
public?class?Main?{
????public?static?void?main(String[]?args)?{
???????//?實(shí)例化代理角色對(duì)象
????????UserInterface?userProxy?=?new?UserProxy();
????????//?調(diào)用了代理對(duì)象的sayHello(),其實(shí)是調(diào)用了真實(shí)角色的sayHello()
????????userProxy.sayHello();
????}
拿開(kāi)始的動(dòng)態(tài)代理代碼和靜態(tài)代理比較,接口、真實(shí)角色都有了,區(qū)別就是多了一個(gè)UserHandler處理類,少了一個(gè)UserProxy代理類。
接著對(duì)比一下兩者的處理類和代理類,發(fā)現(xiàn)UserHandler的invoke()和UserProxy的sayHello()這兩個(gè)方法的代碼都是一樣的。那么,是不是新建一個(gè)UserProxy類,然后實(shí)現(xiàn)UserInterface接口并持有UserHandler的對(duì)象,在sayHello()方法中調(diào)用UserHandler的invoke()方法,就可以動(dòng)態(tài)代理了。
「代碼大概就是這樣的」
//?猜想的代理類結(jié)構(gòu),動(dòng)態(tài)代理生成的代理是com.sun.proxy.$Proxy0
public?class?UserProxy?implements?UserInterface{
???//?持有處理類的對(duì)象
????private?InvocationHandler?handler;
????public?UserProxy(InvocationHandler?handler)?{
????????this.handler?=?handler;
????}
????//?實(shí)現(xiàn)sayHello()方法,并調(diào)用invoke()
????@Override
????public?void?sayHello()?{
????????try?{
????????????handler.invoke(this,?UserInterface.class.getMethod("sayHello"),?null);
????????}?catch?(Throwable?throwable)?{
????????????throwable.printStackTrace();
????????}
????}
}
//?執(zhí)行類
public?static?void?main(String[]?args)?{
????????User?user?=?new?User();
????????UserHandler?userHandler?=?new?UserHandler(user);
????????UserProxy?proxy?=?new?UserProxy(userHandler);
????????proxy.sayHello();
????}
輸出結(jié)果:
上面的代理類代碼是寫死的,而動(dòng)態(tài)代理是當(dāng)你調(diào)用Proxy.newProxyInstance()時(shí),會(huì)根據(jù)你傳入的參數(shù)來(lái)動(dòng)態(tài)生成這個(gè)代理類代碼,如果讓我實(shí)現(xiàn),會(huì)是以下這個(gè)流程。
根據(jù)你傳入的Class[]接口數(shù)組,代理類會(huì)來(lái)實(shí)現(xiàn)這些接口及其方法(這里就是sayHello()),并且持有你傳入的userHandler對(duì)象,使用文件流將預(yù)先設(shè)定的包名、類名、方法名等一行行代碼寫到本地磁盤,生成$Proxy0.java文件 使用編譯器將Proxy0.class 根據(jù)你傳入的ClassLoader將$Proxy0.class加載到JMV中 調(diào)用Proxy.newProxyInstance()就會(huì)返回一個(gè)$Proxy0的對(duì)象,然后調(diào)用sayHello(),就執(zhí)行了里面userHandler的invoke()
以上就是對(duì)動(dòng)態(tài)代理的一個(gè)猜想過(guò)程,下面就通過(guò)debug看看源碼是怎么實(shí)現(xiàn)的。
在困惑的日子里學(xué)會(huì)擁抱源碼

調(diào)用流程圖
這里先用PPT畫一個(gè)流程圖,可以跟著流程圖來(lái)看后面的源碼。

「從newProxyInstance()設(shè)置斷點(diǎn)」
newProxyInstance()
newProxyInstance()代碼分為上下兩部分,上部分是獲取類Proxy0對(duì)象。
「上部分代碼」

從名字看就知道getProxyClass0()是核心方法,step into
getProxyClass0()

里面調(diào)用了WeakCache對(duì)象的get()方法,這里暫停一下debug,先講講WeakCache類。
WeakCache
顧名思義,它是一個(gè)弱引用緩存。那什么是是弱引用呢,是不是還有強(qiáng)引用呢?
弱引用
WeakReference就是弱引用類,作為包裝類來(lái)包裝其他對(duì)象,在進(jìn)行GC時(shí),其中的包裝對(duì)象會(huì)被回收,而WeakReference對(duì)象會(huì)被放到引用隊(duì)列中。
舉個(gè)栗子:
?//?這就是強(qiáng)引用,只要不寫str1?=?null,str1指向的這個(gè)字符串不就會(huì)被垃圾回收
?String?str1?=?new?String("hello");
?ReferenceQueue?referenceQueue?=?new?ReferenceQueue();
?//?只要垃圾回收,這個(gè)str2里面包裝的對(duì)象就會(huì)被回收,但是這個(gè)弱引用對(duì)象不會(huì)被回收,即word會(huì)被回收,但是str2指向的弱引用對(duì)象不會(huì)
?//?每個(gè)弱引用關(guān)聯(lián)一個(gè)ReferenceQueue,當(dāng)包裝的對(duì)象被回收,這個(gè)弱引用對(duì)象會(huì)被放入引用隊(duì)列中
?WeakReference?str2?=?new?WeakReference<>(new?String("world"),?referenceQueue);
?//?執(zhí)行g(shù)c
?System.gc();
?Thread.sleep(3);
?//?輸出被回收包裝對(duì)象的弱引用對(duì)象:java.lang.ref.WeakReference@2077d4de
?//?可以debug看一下,弱引用對(duì)象的referent變量指向的包裝對(duì)象已經(jīng)為null
?System.out.println(referenceQueue.poll());
WeakCache的結(jié)構(gòu)
其實(shí)整個(gè)WeakCache的都是圍繞著成員變量map來(lái)工作的,構(gòu)建了一個(gè)一個(gè)
//?存放已回收弱引用的隊(duì)列
private?final?ReferenceQueue?refQueue?=?new?ReferenceQueue<>();
//?使用ConcurrentMap實(shí)現(xiàn)的二級(jí)緩存結(jié)構(gòu)
private?final?ConcurrentMap WeakCache的get()
回到debug,接著進(jìn)入get()方法,看看map二級(jí)緩存是怎么生成KV的。
?public?V?get(K?key,?P?parameter)?{
????????Objects.requireNonNull(parameter);
????????//?遍歷refQueue,然后將緩存map中對(duì)應(yīng)的失效value刪除
????????expungeStaleEntries();
????????//?以ClassLoader為key,構(gòu)建map的一級(jí)緩存的Key,是CacheKey對(duì)象
????????Object?cacheKey?=?CacheK.valueOf(key,?refQueue);
????????//?通過(guò)Key從map中獲取一級(jí)緩存的value,即ConcurrentMap
????????ConcurrentMap生成二級(jí)緩存Key
在get()中調(diào)用subKeyFactory.apply(key, parameter),根據(jù)你newProxyInstance()傳入的接口Class[]的個(gè)數(shù)來(lái)生成二級(jí)緩存的Key,這里我們就傳入了一個(gè)UserInterface.class,所以就返回了Key1對(duì)象。

不論是Key1、Key2還是KeyX,他們都繼承了WeakReference,都是包裝對(duì)象是Class的弱引用類。這里看看Key1的代碼。

生成二級(jí)緩存Value
在上面的while循環(huán)中,第一次循環(huán)只是生成了一個(gè)空的Factory對(duì)象放入了二級(jí)緩存的ConcurrentMap中。
在第二次循環(huán)中,才開(kāi)始通過(guò)get()方法來(lái)真正的構(gòu)建value。
別回頭,接著往下看。
Factory.get()生成弱引用value
「CacheValue」類是一個(gè)弱引用,是二級(jí)緩存的Value值,包裝的是class,在這里就是$Proxy0.class,至于這個(gè)類如何生成的,根據(jù)下面代碼注釋一直看完Class文件的生成
public?synchronized?V?get()?{
????????????//?檢查是否被回收,如果被回收,會(huì)繼續(xù)執(zhí)行上面的while循環(huán),重新生成Factory
????????????Supplier?supplier?=?valuesMap.get(subKey);
????????????if?(supplier?!=?this)?{
????????????????return?null;
????????????}
????????????//?這里的V的類型是Class
????????????V?value?=?null;
????????????//?這行是核心代碼,看后面,記住這里返回的是Class
????????????value?=?Objects.requireNonNull(valueFactory.apply(key,?parameter));
????????????//?將Class對(duì)象包裝成弱引用
????????????CacheValue?cacheValue?=?new?CacheValue<>(value);
????????????//?回到上面V?value?=?supplier.get();
????????????return?value;
????????}
????}

Class文件的生成
包名類名的定義與驗(yàn)證
進(jìn)入valueFactory.apply(key, parameter)方法,看看class文件是怎么生成的。
?private?static?final?String?proxyClassNamePrefix?=?"$Proxy";
?public?Class>?apply(ClassLoader?loader,?Class>[]?interfaces)?{
????????????Map,?Boolean>?interfaceSet?=?new?IdentityHashMap<>(interfaces.length);
????????????//?遍歷你傳入的Class[],我們只傳入了UserInterface.class
????????????for?(Class>?intf?:?interfaces)?{
????????????????Class>?interfaceClass?=?null;
?????????????????//?獲取接口類
????????????????interfaceClass?=?Class.forName(intf.getName(),?false,?loader);
?????????????????//?這里就很明確為什么只能傳入接口類,不是接口類會(huì)報(bào)錯(cuò)
????????????????if?(!interfaceClass.isInterface())?{
????????????????????throw?new?IllegalArgumentException(
????????????????????????interfaceClass.getName()?+?"?is?not?an?interface");
????????????????}
????????????String?proxyPkg?=?null;?
????????????int?accessFlags?=?Modifier.PUBLIC?|?Modifier.FINAL;
????????????for?(Class>?intf?:?interfaces)?{
????????????????int?flags?=?intf.getModifiers();
????????????????//?驗(yàn)證接口是否是public,不是public代理類會(huì)用接口的package,因?yàn)橹挥性谕话鼉?nèi)才能繼承
????????????????//?我們的UserInterface是public,所以跳過(guò)
????????????????if?(!Modifier.isPublic(flags))?{
????????????????????accessFlags?=?Modifier.FINAL;
????????????????????String?name?=?intf.getName();
????????????????????int?n?=?name.lastIndexOf('.');
????????????????????String?pkg?=?((n?==?-1)???""?:?name.substring(0,?n?+?1));
????????????????????if?(proxyPkg?==?null)?{
????????????????????????proxyPkg?=?pkg;
????????????????????}?else?if?(!pkg.equals(proxyPkg))?{
????????????????????????throw?new?IllegalArgumentException(
????????????????????????????"non-public?interfaces?from?different?packages");
????????????????????}
????????????????}
????????????}
?????????//?如果接口類是public,則用默認(rèn)的包
????????????if?(proxyPkg?==?null)?{
????????????????//?PROXY_PACKAGE?=?"com.sun.proxy";
????????????????proxyPkg?=?ReflectUtil.PROXY_PACKAGE?+?".";
????????????}
?????????//?原子Int,此時(shí)num?=?0
????????????long?num?=?nextUniqueNumber.getAndIncrement();
????????????// com.sun.proxy.$Proxy0,這里包名和類名就出現(xiàn)了?。?!
????????????String?proxyName?=?proxyPkg?+?proxyClassNamePrefix?+?num;
?????????//??。。?!生成class文件,查看后面?核心?。。?!
????????????byte[]?proxyClassFile?=?ProxyGenerator.generateProxyClass(proxyName,?interfaces,?accessFlags);
????????????//?!??!看完下面再回來(lái)看這行!?。?!
????????????//?獲取了字節(jié)數(shù)組之后,獲取了class的二進(jìn)制流將類加載到了JVM中
????????????//?并且返回了$Proxy0.class,返回給Factory.get()來(lái)包裝
????????????return?defineClass0(loader,?proxyName,proxyClassFile,?0,?proxyClassFile.length);
???????????
????????????}
????????}
????}
defineClass0()是Proxy類自定義的類加載的native方法,會(huì)獲取class文件的二進(jìn)制流加載到JVM中,以獲取對(duì)應(yīng)的Class對(duì)象,這一塊可以參考JVM類加載器。
class文件寫入本地
generateProxyClass()方法會(huì)將class二進(jìn)制文件寫入本地目錄,并返回class文件的二進(jìn)制流,使用你傳入的類加載器加載,「這里你知道類加載器的作用了么」。
?public?static?byte[]?generateProxyClass(final?String?name,
????????????????????????????????????????????Class[]?interfaces)
????{
????????ProxyGenerator?gen?=?new?ProxyGenerator(name,?interfaces);
????????//?生成class文件的二進(jìn)制,查看后面<生成class文件二進(jìn)制>
????????final?byte[]?classFile?=?gen.generateClassFile();
??????//?將class文件寫入本地??
????????if?(saveGeneratedFiles)?{
????????????java.security.AccessController.doPrivileged(
????????????new?java.security.PrivilegedAction()?{
????????????????public?Void?run()?{
????????????????????try?{
????????????????????????FileOutputStream?file?=
????????????????????????????new?FileOutputStream(dotToSlash(name)?+?".class");
????????????????????????file.write(classFile);
????????????????????????file.close();
????????????????????????return?null;
????????????????????}?catch?(IOException?e)?{
????????????????????????throw?new?InternalError(
????????????????????????????"I/O?exception?saving?generated?file:?"?+?e);
????????????????????}
????????????????}
????????????});
????????}
??????//?返回$Proxy0.class字節(jié)數(shù)組,回到上面
????????return?classFile;
????}
生成class文件二進(jìn)制流
generateClassFile()生成class文件,并存放到字節(jié)數(shù)組,「可以順便學(xué)一下class結(jié)構(gòu),這里也體現(xiàn)了你傳入的class[]的作用」。
????private?byte[]?generateClassFile()?{
??????//?將hashcode、equals、toString是三個(gè)方法放入代理類中
????????addProxyMethod(hashCodeMethod,?Object.class);
????????addProxyMethod(equalsMethod,?Object.class);
????????addProxyMethod(toStringMethod,?Object.class);
????????for?(int?i?=?0;?i?????????????Method[]?methods?=?interfaces[i].getMethods();
????????????for?(int?j?=?0;?j??????????????//?將接口類的方法放入新建的代理類中,這里就是sayHello()
????????????????addProxyMethod(methods[j],?interfaces[i]);
????????????}
????????}
????????for?(List?sigmethods?:?proxyMethods.values())?{
????????????checkReturnTypes(sigmethods);
????????}
????????//?給代理類增加構(gòu)造方法
????????methods.add(generateConstructor());
????????for?(List?sigmethods?:?proxyMethods.values())?{
????????????for?(ProxyMethod?pm?:?sigmethods)?{
???????????????????//?將上面的四個(gè)方法都封裝成Method類型成員變量
????????????????????fields.add(new?FieldInfo(pm.methodFieldName,
????????????????????????"Ljava/lang/reflect/Method;",
?????????????????????????ACC_PRIVATE?|?ACC_STATIC));
????????????????????//?generate?code?for?proxy?method?and?add?it
????????????????????methods.add(pm.generateMethod());
????????????????}
????????????}
??????//?static靜態(tài)塊構(gòu)造
????????methods.add(generateStaticInitializer());
????????cp.getClass(dotToSlash(className));
????????cp.getClass(superclassName);
????????for?(int?i?=?0;?i?????????????cp.getClass(dotToSlash(interfaces[i].getName()));
????????}
????????cp.setReadOnly();
????????ByteArrayOutputStream?bout?=?new?ByteArrayOutputStream();
????????DataOutputStream?dout?=?new?DataOutputStream(bout);
??????// !!!核心點(diǎn)來(lái)了!這里就開(kāi)始構(gòu)建class文件了,以下都是class的結(jié)構(gòu),只寫一部分
????????try?{???
????????????// u4 magic,class文件的魔數(shù),確認(rèn)是否為一個(gè)能被JVM接受的class
????????????dout.writeInt(0xCAFEBABE);
????????????//?u2?minor_version,0
????????????dout.writeShort(CLASSFILE_MINOR_VERSION);
????????????//?u2?major_version,主版本號(hào),Java8對(duì)應(yīng)的是52;
????????????dout.writeShort(CLASSFILE_MAJOR_VERSION);
????????????//?常量池
????????????cp.write(dout);
????????????//?其他結(jié)構(gòu),可參考class文件結(jié)構(gòu)
????????????dout.writeShort(ACC_PUBLIC?|?ACC_FINAL?|?ACC_SUPER);
????????????dout.writeShort(cp.getClass(dotToSlash(className)));
????????????dout.writeShort(cp.getClass(superclassName));
????????????dout.writeShort(interfaces.length);
????????????for?(int?i?=?0;?i?????????????????dout.writeShort(cp.getClass(
????????????????????dotToSlash(interfaces[i].getName())));
????????????}
????????????dout.writeShort(fields.size());
????????????for?(FieldInfo?f?:?fields)?{
????????????????f.write(dout);
????????????}
????????????dout.writeShort(methods.size());???????????
????????????for?(MethodInfo?m?:?methods)?{
????????????????m.write(dout);
????????????}
????????????dout.writeShort(0);?
????????}?catch?(IOException?e)?{
????????????throw?new?InternalError("unexpected?I/O?Exception",?e);
????????}
????????//?將class文件字節(jié)數(shù)組返回
????????return?bout.toByteArray();
????}
構(gòu)建$Proxy對(duì)象
newProxyInstance()上半部分經(jīng)過(guò)上面層層代碼調(diào)用,獲取了$Proxy0.class,接下來(lái)看下部分代碼:

cl就是上面獲取的Proxy0.class,h就是上面?zhèn)魅氲膗serHandler,被當(dāng)做構(gòu)造參數(shù)來(lái)創(chuàng)建$Proxy0對(duì)象。然后獲取這個(gè)動(dòng)態(tài)代理對(duì)象,調(diào)用sayHello()方法,相當(dāng)于調(diào)用了UserHandler的invoke(),「這里就是UserHandler的作用」!
$Proxy.class文件
我們開(kāi)啟了將代理class寫到本地目錄的功能,在項(xiàng)目下的com/sum/proxy目錄下找到了$Proxy0的class文件。
「看一下反編譯的class」
package?com.sun.proxy;
import?com.test.proxy.UserInterface;
import?java.lang.reflect.InvocationHandler;
import?java.lang.reflect.Method;
import?java.lang.reflect.Proxy;
import?java.lang.reflect.UndeclaredThrowableException;
public?final?class?$Proxy0?extends?Proxy?implements?UserInterface?{
????private?static?Method?m1;
????private?static?Method?m3;
????private?static?Method?m2;
????private?static?Method?m0;
????public?$Proxy0(InvocationHandler?var1)?throws??{
????????super(var1);
????}
????public?final?boolean?equals(Object?var1)?throws??{
????????try?{
????????????return?(Boolean)super.h.invoke(this,?m1,?new?Object[]{var1});
????????}?catch?(RuntimeException?|?Error?var3)?{
????????????throw?var3;
????????}?catch?(Throwable?var4)?{
????????????throw?new?UndeclaredThrowableException(var4);
????????}
????}
????public?final?void?sayHello()?throws??{
????????try?{
????????????super.h.invoke(this,?m3,?(Object[])null);
????????}?catch?(RuntimeException?|?Error?var2)?{
????????????throw?var2;
????????}?catch?(Throwable?var3)?{
????????????throw?new?UndeclaredThrowableException(var3);
????????}
????}
????public?final?String?toString()?throws??{
????????try?{
????????????return?(String)super.h.invoke(this,?m2,?(Object[])null);
????????}?catch?(RuntimeException?|?Error?var2)?{
????????????throw?var2;
????????}?catch?(Throwable?var3)?{
????????????throw?new?UndeclaredThrowableException(var3);
????????}
????}
????public?final?int?hashCode()?throws??{
????????try?{
????????????return?(Integer)super.h.invoke(this,?m0,?(Object[])null);
????????}?catch?(RuntimeException?|?Error?var2)?{
????????????throw?var2;
????????}?catch?(Throwable?var3)?{
????????????throw?new?UndeclaredThrowableException(var3);
????????}
????}
????static?{
????????try?{
????????????m1?=?Class.forName("java.lang.Object").getMethod("equals",?Class.forName("java.lang.Object"));
????????????m3?=?Class.forName("com.test.proxy.UserInterface").getMethod("sayHello");
????????????m2?=?Class.forName("java.lang.Object").getMethod("toString");
????????????m0?=?Class.forName("java.lang.Object").getMethod("hashCode");
????????}?catch?(NoSuchMethodException?var2)?{
????????????throw?new?NoSuchMethodError(var2.getMessage());
????????}?catch?(ClassNotFoundException?var3)?{
????????????throw?new?NoClassDefFoundError(var3.getMessage());
????????}
????}
}
結(jié)語(yǔ)
上面就是動(dòng)態(tài)代理源碼的調(diào)試過(guò)程,與之前的猜想的代理類的生成過(guò)程比較,動(dòng)態(tài)代理是直接生成class文件,省去了java文件和編譯這一塊。
剛開(kāi)始看可能比較繞,跟著注釋及跳轉(zhuǎn)指引,耐心多看兩遍就明白了。動(dòng)態(tài)代理涉及的知識(shí)點(diǎn)比較多,我自己看的時(shí)候,在WeakCache這一塊糾結(jié)了一陣,其實(shí)把它當(dāng)成一個(gè)兩層的map對(duì)待即可,只不過(guò)里面所有的KV都被弱引用包裝。






關(guān)注Java技術(shù)??锤喔韶?/strong>


