生活随笔
收集整理的這篇文章主要介紹了
JDK动态代理实现原理--转载
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
之前雖然會用JDK的動態(tài)代理,但是有些問題卻一直沒有搞明白。比如說:InvocationHandler的invoke方法是由誰來調(diào)用的,代理對象是怎么生成的,直到前幾個(gè)星期才把這些問題全部搞明白了。?
??? 廢話不多說了,先來看一下JDK的動態(tài)是怎么用的。?
Java代碼??
package?dynamic.proxy;?????import?java.lang.reflect.InvocationHandler;??import?java.lang.reflect.Method;??import?java.lang.reflect.Proxy;????public?class?MyInvocationHandler?implements?InvocationHandler?{????????????????private?Object?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;??????}????????????public?Object?getProxy()?{??????????return?Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),???????????????????target.getClass().getInterfaces(),?this);??????}??}????package?dynamic.proxy;????public?interface?UserService?{????????????public?abstract?void?add();????}????package?dynamic.proxy;?????public?class?UserServiceImpl?implements?UserService?{????????????public?void?add()?{??????????System.out.println("--------------------add---------------");??????}??}????package?dynamic.proxy;?????import?org.junit.Test;????public?class?ProxyTest?{????????@Test??????public?void?testProxy()?throws?Throwable?{??????????????????UserService?userService?=?new?UserServiceImpl();????????????????????????????MyInvocationHandler?invocationHandler?=?new?MyInvocationHandler(userService);????????????????????????????UserService?proxy?=?(UserService)?invocationHandler.getProxy();????????????????????????????proxy.add();????????????????}??}??
執(zhí)行結(jié)果如下:?
------------------before------------------?
--------------------add---------------?
-------------------after------------------?
?? 用起來是很簡單吧,其實(shí)這里基本上就是AOP的一個(gè)簡單實(shí)現(xiàn)了,在目標(biāo)對象的方法執(zhí)行之前和執(zhí)行之后進(jìn)行了增強(qiáng)。Spring的AOP實(shí)現(xiàn)其實(shí)也是用了Proxy和InvocationHandler這兩個(gè)東西的。?
??? 用起來是比較簡單,但是如果能知道它背后做了些什么手腳,那就更好不過了。首先來看一下JDK是怎樣生成代理對象的。既然生成代理對象是用的Proxy類的靜態(tài)方newProxyInstance,那么我們就去它的源碼里看一下它到底都做了些什么??
Java代碼??
public?static?Object?newProxyInstance(ClassLoader?loader,????????????????????????Class<?>[]?interfaces,????????????????????????InvocationHandler?h)??????throws?IllegalArgumentException??????{??????if?(h?==?null)?{??????????throw?new?NullPointerException();??????}????????????Class?cl?=?getProxyClass(loader,?interfaces);????????????try?{??????????????????????Constructor?cons?=?cl.getConstructor(constructorParams);??????????????????????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());??????}??????}??
?? 我們再進(jìn)去getProxyClass方法看一下?
Java代碼??
public?static?Class<?>?getProxyClass(ClassLoader?loader,????????????????????????????????????????????Class<?>...?interfaces)??????throws?IllegalArgumentException??????{??????????if?(interfaces.length?>?65535)?{??????????throw?new?IllegalArgumentException("interface?limit?exceeded");??????}????????????Class?proxyClass?=?null;????????String[]?interfaceNames?=?new?String[interfaces.length];????????Set?interfaceSet?=?new?HashSet();?????????????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");??????????}??????????????????????????????????????interfaceSet.add(interfaceClass);????????????interfaceNames[i]?=?interfaceName;??????}????????????Object?key?=?Arrays.asList(interfaceNames);????????Map?cache;????????????synchronized?(loaderToCache)?{??????????????????cache?=?(Map)?loaderToCache.get(loader);??????????if?(cache?==?null)?{??????????????????cache?=?new?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)?{??????????????????????????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());??????????}??????????}??????????????????proxyClasses.put(proxyClass,?null);????????}?????????????????return?proxyClass;??????}??
進(jìn)去ProxyGenerator類的靜態(tài)方法generateProxyClass,這里是真正生成代理類class字節(jié)碼的地方。?
Java代碼??
public?static?byte[]?generateProxyClass(final?String?name,?????????????????????????????????????????????Class[]?interfaces)?????{?????????ProxyGenerator?gen?=?new?ProxyGenerator(name,?interfaces);?????????????final?byte[]?classFile?=?gen.generateClassFile();???????????????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;?????}??
現(xiàn)在,JDK是怎樣動態(tài)生成代理類的字節(jié)的原理已經(jīng)一目了然了。?
好了,再來解決另外一個(gè)問題,那就是由誰來調(diào)用InvocationHandler的invoke方法的。要解決這個(gè)問題就要看一下JDK到底為我們生成了一個(gè)什么東西。用以下代碼可以獲取到JDK為我們生成的字節(jié)碼并寫到硬盤中。?
Java代碼??
package?dynamic.proxy;?????import?java.io.FileOutputStream;??import?java.io.IOException;????import?sun.misc.ProxyGenerator;????public?class?ProxyGeneratorUtils?{????????????public?static?void?writeProxyClassToHardDisk(String?path)?{??????????????????????????????????????????????????????????????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;????public?class?ProxyTest?{????????@Test??????public?void?testProxy()?throws?Throwable?{??????????????????UserService?userService?=?new?UserServiceImpl();????????????????????????????MyInvocationHandler?invocationHandler?=?new?MyInvocationHandler(userService);????????????????????????????UserService?proxy?=?(UserService)?invocationHandler.getProxy();????????????????????????????proxy.add();????????????????}????????????@Test??????public?void?testGenerateProxyClass()?{??????????ProxyGeneratorUtils.writeProxyClassToHardDisk("F:/$Proxy11.class");??????}??}??
通過以上代碼,就可以在F盤上生成一個(gè)$Proxy.class文件了,現(xiàn)在用反編譯工具來看一下這個(gè)class文件里面的內(nèi)容。?
Java代碼??
??import?dynamic.proxy.UserService;??import?java.lang.reflect.*;????public?final?class?$Proxy11?extends?Proxy??????implements?UserService??{????????????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??????????{??????????????????????????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;????????????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());??????????}??????}??}??
好了,到目前為止,前面 的兩個(gè)問題都已經(jīng)知道回事了,現(xiàn)在再用JDK動態(tài)代理的時(shí)候就不只會用而已了,真正的達(dá)到了“知其然,知其所以然”的目的。。。???
就寫到這了,累死了。。??
原文地址:http://rejoy.iteye.com/blog/1627405
轉(zhuǎn)載于:https://www.cnblogs.com/davidwang456/p/4045412.html
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀
總結(jié)
以上是生活随笔為你收集整理的JDK动态代理实现原理--转载的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。