之前雖然會用JDK的動態代理,但是有些問題卻一直沒有搞明白。比如說:InvocationHandler的invoke方法是由誰來調用的,代理對象是怎么生成的,直到前幾個星期才把這些問題全部搞明白了。
??? 廢話不多說了,先來看一下JDK的動態是怎么用的。
- package ?dynamic.proxy;???
- ??
- import ?java.lang.reflect.InvocationHandler;??
- import ?java.lang.reflect.Method;??
- import ?java.lang.reflect.Proxy;??
- ??
- /** ?
- ?*?實現自己的InvocationHandler ?
- ?*?@author?zyb ?
- ?*?@since?2012-8-9 ?
- ?* ?
- ?*/ ??
- public ? class ?MyInvocationHandler? implements ?InvocationHandler?{??
- ??????
- ???? //?目標對象? ??
- ???? private ?Object?target;??
- ??????
- ???? /** ?
- ?????*?構造方法 ?
- ?????*?@param?target?目標對象? ?
- ?????*/ ??
- ???? public ?MyInvocationHandler(Object?target)?{??
- ???????? super ();??
- ???????? this .target?=?target;??
- ????}??
- ??
- ??
- ???? /** ?
- ?????*?執行目標對象的方法 ?
- ?????*/ ??
- ???? public ?Object?invoke(Object?proxy,?Method?method,?Object[]?args)? throws ?Throwable?{??
- ??????????
- ???????? //?在目標對象的方法執行之前簡單的打印一下 ??
- ????????System.out.println( "------------------before------------------" );??
- ??????????
- ???????? //?執行目標對象的方法 ??
- ????????Object?result?=?method.invoke(target,?args);??
- ??????????
- ???????? //?在目標對象的方法執行之后簡單的打印一下 ??
- ????????System.out.println( "-------------------after------------------" );??
- ??????????
- ???????? return ?result;??
- ????}??
- ??
- ???? /** ?
- ?????*?獲取目標對象的代理對象 ?
- ?????*?@return?代理對象 ?
- ?????*/ ??
- ???? public ?Object?getProxy()?{??
- ???????? return ?Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),???
- ????????????????target.getClass().getInterfaces(),? this );??
- ????}??
- }??
- ??
- package ?dynamic.proxy;??
- ??
- /** ?
- ?*?目標對象實現的接口,用JDK來生成代理對象一定要實現一個接口 ?
- ?*?@author?zyb ?
- ?*?@since?2012-8-9 ?
- ?* ?
- ?*/ ??
- public ? interface ?UserService?{??
- ??
- ???? /** ?
- ?????*?目標方法? ?
- ?????*/ ??
- ???? public ? abstract ? void ?add();??
- ??
- }??
- ??
- package ?dynamic.proxy;???
- ??
- /** ?
- ?*?目標對象 ?
- ?*?@author?zyb ?
- ?*?@since?2012-8-9 ?
- ?* ?
- ?*/ ??
- public ? class ?UserServiceImpl? implements ?UserService?{??
- ??
- ???? /*?(non-Javadoc) ?
- ?????*?@see?dynamic.proxy.UserService#add() ?
- ?????*/ ??
- ???? public ? void ?add()?{??
- ????????System.out.println( "--------------------add---------------" );??
- ????}??
- }??
- ??
- package ?dynamic.proxy;???
- ??
- import ?org.junit.Test;??
- ??
- /** ?
- ?*?動態代理測試類 ?
- ?*?@author?zyb ?
- ?*?@since?2012-8-9 ?
- ?* ?
- ?*/ ??
- public ? class ?ProxyTest?{??
- ??
- ???? @Test ??
- ???? public ? void ?testProxy()? throws ?Throwable?{??
- ???????? //?實例化目標對象 ??
- ????????UserService?userService?=? new ?UserServiceImpl();??
- ??????????
- ???????? //?實例化InvocationHandler ??
- ????????MyInvocationHandler?invocationHandler?=? new ?MyInvocationHandler(userService);??
- ??????????
- ???????? //?根據目標對象生成代理對象 ??
- ????????UserService?proxy?=?(UserService)?invocationHandler.getProxy();??
- ??????????
- ???????? //?調用代理對象的方法 ??
- ????????proxy.add();??
- ??????????
- ????}??
- }??
執行結果如下:
------------------before------------------
--------------------add---------------
-------------------after------------------
?? 用起來是很簡單吧,其實這里基本上就是AOP的一個簡單實現了,在目標對象的方法執行之前和執行之后進行了增強。Spring的AOP實現其實也是用了Proxy和InvocationHandler這兩個東西的。
??? 用起來是比較簡單,但是如果能知道它背后做了些什么手腳,那就更好不過了。首先來看一下JDK是怎樣生成代理對象的。既然生成代理對象是用的Proxy類的靜態方newProxyInstance,那么我們就去它的源碼里看一下它到底都做了些什么?
- /** ?
- ?*?loader:類加載器 ?
- ?*?interfaces:目標對象實現的接口 ?
- ?*?h:InvocationHandler的實現類 ?
- ?*/ ??
- public ? static ?Object?newProxyInstance(ClassLoader?loader,??
- ??????????????????????Class<?>[]?interfaces,??
- ??????????????????????InvocationHandler?h)??
- ???? throws ?IllegalArgumentException??
- ????{??
- ???? if ?(h?==? null )?{??
- ???????? throw ? new ?NullPointerException();??
- ????}??
- ??
- ???? /* ?
- ?????*?Look?up?or?generate?the?designated?proxy?class. ?
- ?????*/ ??
- ????Class?cl?=?getProxyClass(loader,?interfaces);??
- ??
- ???? /* ?
- ?????*?Invoke?its?constructor?with?the?designated?invocation?handler. ?
- ?????*/ ??
- ???? try ?{??
- ???????????? //?調用代理對象的構造方法(也就是$Proxy0(InvocationHandler?h)) ??
- ????????Constructor?cons?=?cl.getConstructor(constructorParams);??
- ???????????? //?生成代理類的實例并把MyInvocationHandler的實例傳給它的構造方法 ??
- ???????? return ?(Object)?cons.newInstance( new ?Object[]?{?h?});??
- ????}? catch ?(NoSuchMethodException?e)?{??
- ???????? throw ? new ?InternalError(e.toString());??
- ????}? catch ?(IllegalAccessException?e)?{??
- ???????? throw ? new ?InternalError(e.toString());??
- ????}? catch ?(InstantiationException?e)?{??
- ???????? throw ? new ?InternalError(e.toString());??
- ????}? catch ?(InvocationTargetException?e)?{??
- ???????? throw ? new ?InternalError(e.toString());??
- ????}??
- ????}??
?? 我們再進去getProxyClass方法看一下
- public ? static ?Class<?>?getProxyClass(ClassLoader?loader,???
- ?????????????????????????????????????????Class<?>...?interfaces)??
- ???? throws ?IllegalArgumentException??
- ????{??
- ???? //?如果目標類實現的接口數大于65535個則拋出異常(我XX,誰會寫這么NB的代碼啊?) ??
- ???? if ?(interfaces.length?>? 65535 )?{??
- ???????? throw ? new ?IllegalArgumentException( "interface?limit?exceeded" );??
- ????}??
- ??
- ???? //?聲明代理對象所代表的Class對象(有點拗口) ??
- ????Class?proxyClass?=? null ;??
- ??
- ????String[]?interfaceNames?=? new ?String[interfaces.length];??
- ??
- ????Set?interfaceSet?=? new ?HashSet();??? //?for?detecting?duplicates ??
- ??
- ???? //?遍歷目標類所實現的接口 ??
- ???? for ?( int ?i?=? 0 ;?i?<?interfaces.length;?i++)?{??
- ??????????
- ???????? //?拿到目標類實現的接口的名稱 ??
- ????????String?interfaceName?=?interfaces[i].getName();??
- ????????Class?interfaceClass?=? null ;??
- ???????? try ?{??
- ???????? //?加載目標類實現的接口到內存中 ??
- ????????interfaceClass?=?Class.forName(interfaceName,? false ,?loader);??
- ????????}? catch ?(ClassNotFoundException?e)?{??
- ????????}??
- ???????? if ?(interfaceClass?!=?interfaces[i])?{??
- ???????? throw ? new ?IllegalArgumentException(??
- ????????????interfaces[i]?+? "?is?not?visible?from?class?loader" );??
- ????????}??
- ??
- ???????? //?中間省略了一些無關緊要的代碼?....... ??
- ??????????
- ???????? //?把目標類實現的接口代表的Class對象放到Set中 ??
- ????????interfaceSet.add(interfaceClass);??
- ??
- ????????interfaceNames[i]?=?interfaceName;??
- ????}??
- ??
- ???? //?把目標類實現的接口名稱作為緩存(Map)中的key ??
- ????Object?key?=?Arrays.asList(interfaceNames);??
- ??
- ????Map?cache;??
- ??????
- ???? synchronized ?(loaderToCache)?{??
- ???????? //?從緩存中獲取cache ??
- ????????cache?=?(Map)?loaderToCache.get(loader);??
- ???????? if ?(cache?==? null )?{??
- ???????? //?如果獲取不到,則新建地個HashMap實例 ??
- ????????cache?=? new ?HashMap();??
- ???????? //?把HashMap實例和當前加載器放到緩存中 ??
- ????????loaderToCache.put(loader,?cache);??
- ????????}??
- ??
- ????}??
- ??
- ???? synchronized ?(cache)?{??
- ??
- ???????? do ?{??
- ???????? //?根據接口的名稱從緩存中獲取對象 ??
- ????????Object?value?=?cache.get(key);??
- ???????? if ?(value? instanceof ?Reference)?{??
- ????????????proxyClass?=?(Class)?((Reference)?value).get();??
- ????????}??
- ???????? if ?(proxyClass?!=? null )?{??
- ???????????? //?如果代理對象的Class實例已經存在,則直接返回 ??
- ???????????? return ?proxyClass;??
- ????????}? else ? if ?(value?==?pendingGenerationMarker)?{??
- ???????????? try ?{??
- ????????????cache.wait();??
- ????????????}? catch ?(InterruptedException?e)?{??
- ????????????}??
- ???????????? continue ;??
- ????????}? else ?{??
- ????????????cache.put(key,?pendingGenerationMarker);??
- ???????????? break ;??
- ????????}??
- ????????}? while ?( true );??
- ????}??
- ??
- ???? try ?{??
- ???????? //?中間省略了一些代碼?....... ??
- ??????????
- ???????? //?這里就是動態生成代理對象的最關鍵的地方 ??
- ???????? byte []?proxyClassFile?=?ProxyGenerator.generateProxyClass(??
- ????????????proxyName,?interfaces);??
- ???????? try ?{??
- ???????????? //?根據代理類的字節碼生成代理類的實例 ??
- ????????????proxyClass?=?defineClass0(loader,?proxyName,??
- ????????????proxyClassFile,? 0 ,?proxyClassFile.length);??
- ????????}? catch ?(ClassFormatError?e)?{??
- ???????????? throw ? new ?IllegalArgumentException(e.toString());??
- ????????}??
- ????????}??
- ???????? //?add?to?set?of?all?generated?proxy?classes,?for?isProxyClass ??
- ????????proxyClasses.put(proxyClass,? null );??
- ??
- ????}???
- ???? //?中間省略了一些代碼?....... ??
- ??????
- ???? return ?proxyClass;??
- ????}??
進去ProxyGenerator類的靜態方法generateProxyClass,這里是真正生成代理類class字節碼的地方。
- public ? static ? byte []?generateProxyClass( final ?String?name,??
- ???????????????????????????????????????????Class[]?interfaces)??
- ???{??
- ???????ProxyGenerator?gen?=? new ?ProxyGenerator(name,?interfaces);??
- ???? //?這里動態生成代理類的字節碼,由于比較復雜就不進去看了 ??
- ??????? final ? byte []?classFile?=?gen.generateClassFile();??
- ??
- ???? //?如果saveGeneratedFiles的值為true,則會把所生成的代理類的字節碼保存到硬盤上 ??
- ??????? if ?(saveGeneratedFiles)?{??
- ???????????java.security.AccessController.doPrivileged(??
- ??????????? new ?java.security.PrivilegedAction<Void>()?{??
- ??????????????? 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);??
- ???????????????????}??
- ???????????????}??
- ???????????});??
- ???????}??
- ??
- ???? //?返回代理類的字節碼 ??
- ??????? return ?classFile;??
- ???}??
現在,JDK是怎樣動態生成代理類的字節的原理已經一目了然了。
好了,再來解決另外一個問題,那就是由誰來調用InvocationHandler的invoke方法的。要解決這個問題就要看一下JDK到底為我們生成了一個什么東西。用以下代碼可以獲取到JDK為我們生成的字節碼并寫到硬盤中。
- package ?dynamic.proxy;???
- ??
- import ?java.io.FileOutputStream;??
- import ?java.io.IOException;??
- ??
- import ?sun.misc.ProxyGenerator;??
- ??
- /** ?
- ?*?代理類的生成工具 ?
- ?*?@author?zyb ?
- ?*?@since?2012-8-9 ?
- ?*/ ??
- public ? class ?ProxyGeneratorUtils?{??
- ??
- ???? /** ?
- ?????*?把代理類的字節碼寫到硬盤上 ?
- ?????*?@param?path?保存路徑 ?
- ?????*/ ??
- ???? public ? static ? void ?writeProxyClassToHardDisk(String?path)?{??
- ???????? //?第一種方法,這種方式在剛才分析ProxyGenerator時已經知道了 ??
- ???????? //?System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles",?true); ??
- ??????????
- ???????? //?第二種方法 ??
- ??????????
- ???????? //?獲取代理類的字節碼 ??
- ???????? byte []?classFile?=?ProxyGenerator.generateProxyClass( "$Proxy11" ,?UserServiceImpl. class .getInterfaces());??
- ??????????
- ????????FileOutputStream?out?=? null ;??
- ??????????
- ???????? try ?{??
- ????????????out?=? new ?FileOutputStream(path);??
- ????????????out.write(classFile);??
- ????????????out.flush();??
- ????????}? catch ?(Exception?e)?{??
- ????????????e.printStackTrace();??
- ????????}? finally ?{??
- ???????????? try ?{??
- ????????????????out.close();??
- ????????????}? catch ?(IOException?e)?{??
- ????????????????e.printStackTrace();??
- ????????????}??
- ????????}??
- ????}??
- }??
- ??
- package ?dynamic.proxy;???
- ??
- import ?org.junit.Test;??
- ??
- /** ?
- ?*?動態代理測試類 ?
- ?*?@author?zyb ?
- ?*?@since?2012-8-9 ?
- ?* ?
- ?*/ ??
- public ? class ?ProxyTest?{??
- ??
- ???? @Test ??
- ???? public ? void ?testProxy()? throws ?Throwable?{??
- ???????? //?實例化目標對象 ??
- ????????UserService?userService?=? new ?UserServiceImpl();??
- ??????????
- ???????? //?實例化InvocationHandler ??
- ????????MyInvocationHandler?invocationHandler?=? new ?MyInvocationHandler(userService);??
- ??????????
- ???????? //?根據目標對象生成代理對象 ??
- ????????UserService?proxy?=?(UserService)?invocationHandler.getProxy();??
- ??????????
- ???????? //?調用代理對象的方法 ??
- ????????proxy.add();??
- ??????????
- ????}??
- ??????
- ???? @Test ??
- ???? public ? void ?testGenerateProxyClass()?{??
- ????????ProxyGeneratorUtils.writeProxyClassToHardDisk( "F:/$Proxy11.class" );??
- ????}??
- }??
通過以上代碼,就可以在F盤上生成一個$Proxy.class文件了,現在用反編譯工具來看一下這個class文件里面的內容。
- //?Decompiled?by?DJ?v3.11.11.95?Copyright?2009?Atanas?Neshkov??Date:?2012/8/9?20:11:32 ??
- //?Home?Page:?http://members.fortunecity.com/neshkov/dj.html??http://www.neshkov.com/dj.html?-?Check?often?for?new?version! ??
- //?Decompiler?options:?packimports(3)? ??
- ??
- import ?dynamic.proxy.UserService;??
- import ?java.lang.reflect.*;??
- ??
- public ? final ? class ?$Proxy11? extends ?Proxy??
- ???? implements ?UserService??
- {??
- ??
- ???? //?構造方法,參數就是剛才傳過來的MyInvocationHandler類的實例 ??
- ???? public ?$Proxy11(InvocationHandler?invocationhandler)??
- ????{??
- ???????? super (invocationhandler);??
- ????}??
- ??
- ???? public ? final ? boolean ?equals(Object?obj)??
- ????{??
- ???????? try ??
- ????????{??
- ???????????? return ?((Boolean) super .h.invoke( this ,?m1,? new ?Object[]?{??
- ????????????????obj??
- ????????????})).booleanValue();??
- ????????}??
- ???????? catch (Error?_ex)?{?}??
- ???????? catch (Throwable?throwable)??
- ????????{??
- ???????????? throw ? new ?UndeclaredThrowableException(throwable);??
- ????????}??
- ????}??
- ??
- ???? /** ?
- ?????*?這個方法是關鍵部分 ?
- ?????*/ ??
- ???? public ? final ? void ?add()??
- ????{??
- ???????? try ??
- ????????{??
- ???????????? //?實際上就是調用MyInvocationHandler的public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)方法,第二個問題就解決了 ??
- ???????????? super .h.invoke( this ,?m3,? null );??
- ???????????? return ;??
- ????????}??
- ???????? catch (Error?_ex)?{?}??
- ???????? catch (Throwable?throwable)??
- ????????{??
- ???????????? throw ? new ?UndeclaredThrowableException(throwable);??
- ????????}??
- ????}??
- ??
- ???? public ? final ? int ?hashCode()??
- ????{??
- ???????? try ??
- ????????{??
- ???????????? return ?((Integer) super .h.invoke( this ,?m0,? null )).intValue();??
- ????????}??
- ???????? catch (Error?_ex)?{?}??
- ???????? catch (Throwable?throwable)??
- ????????{??
- ???????????? throw ? new ?UndeclaredThrowableException(throwable);??
- ????????}??
- ????}??
- ??
- ???? public ? final ?String?toString()??
- ????{??
- ???????? try ??
- ????????{??
- ???????????? return ?(String) super .h.invoke( this ,?m2,? null );??
- ????????}??
- ???????? catch (Error?_ex)?{?}??
- ???????? catch (Throwable?throwable)??
- ????????{??
- ???????????? throw ? new ?UndeclaredThrowableException(throwable);??
- ????????}??
- ????}??
- ??
- ???? private ? static ?Method?m1;??
- ???? private ? static ?Method?m3;??
- ???? private ? static ?Method?m0;??
- ???? private ? static ?Method?m2;??
- ??
- ???? //?在靜態代碼塊中獲取了4個方法:Object中的equals方法、UserService中的add方法、Object中的hashCode方法、Object中toString方法 ??
- ???? static ???
- ????{??
- ???????? try ??
- ????????{??
- ????????????m1?=?Class.forName( "java.lang.Object" ).getMethod( "equals" ,? new ?Class[]?{??
- ????????????????Class.forName( "java.lang.Object" )??
- ????????????});??
- ????????????m3?=?Class.forName( "dynamic.proxy.UserService" ).getMethod( "add" ,? new ?Class[ 0 ]);??
- ????????????m0?=?Class.forName( "java.lang.Object" ).getMethod( "hashCode" ,? new ?Class[ 0 ]);??
- ????????????m2?=?Class.forName( "java.lang.Object" ).getMethod( "toString" ,? new ?Class[ 0 ]);??
- ????????}??
- ???????? catch (NoSuchMethodException?nosuchmethodexception)??
- ????????{??
- ???????????? throw ? new ?NoSuchMethodError(nosuchmethodexception.getMessage());??
- ????????}??
- ???????? catch (ClassNotFoundException?classnotfoundexception)??
- ????????{??
- ???????????? throw ? new ?NoClassDefFoundError(classnotfoundexception.getMessage());??
- ????????}??
- ????}??
- }??
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
