日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JDK动态代理实现原理--转载

發(fā)布時(shí)間:2025/4/5 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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;??
  • ??
  • /**?
  • ?*?實(shí)現(xiàn)自己的InvocationHandler?
  • ?*?@author?zyb?
  • ?*?@since?2012-8-9?
  • ?*?
  • ?*/??
  • public?class?MyInvocationHandler?implements?InvocationHandler?{??
  • ??????
  • ????//?目標(biāo)對象???
  • ????private?Object?target;??
  • ??????
  • ????/**?
  • ?????*?構(gòu)造方法?
  • ?????*?@param?target?目標(biāo)對象??
  • ?????*/??
  • ????public?MyInvocationHandler(Object?target)?{??
  • ????????super();??
  • ????????this.target?=?target;??
  • ????}??
  • ??
  • ??
  • ????/**?
  • ?????*?執(zhí)行目標(biāo)對象的方法?
  • ?????*/??
  • ????public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)?throws?Throwable?{??
  • ??????????
  • ????????//?在目標(biāo)對象的方法執(zhí)行之前簡單的打印一下??
  • ????????System.out.println("------------------before------------------");??
  • ??????????
  • ????????//?執(zhí)行目標(biāo)對象的方法??
  • ????????Object?result?=?method.invoke(target,?args);??
  • ??????????
  • ????????//?在目標(biāo)對象的方法執(zhí)行之后簡單的打印一下??
  • ????????System.out.println("-------------------after------------------");??
  • ??????????
  • ????????return?result;??
  • ????}??
  • ??
  • ????/**?
  • ?????*?獲取目標(biāo)對象的代理對象?
  • ?????*?@return?代理對象?
  • ?????*/??
  • ????public?Object?getProxy()?{??
  • ????????return?Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),???
  • ????????????????target.getClass().getInterfaces(),?this);??
  • ????}??
  • }??
  • ??
  • package?dynamic.proxy;??
  • ??
  • /**?
  • ?*?目標(biāo)對象實(shí)現(xiàn)的接口,用JDK來生成代理對象一定要實(shí)現(xiàn)一個(gè)接口?
  • ?*?@author?zyb?
  • ?*?@since?2012-8-9?
  • ?*?
  • ?*/??
  • public?interface?UserService?{??
  • ??
  • ????/**?
  • ?????*?目標(biāo)方法??
  • ?????*/??
  • ????public?abstract?void?add();??
  • ??
  • }??
  • ??
  • package?dynamic.proxy;???
  • ??
  • /**?
  • ?*?目標(biāo)對象?
  • ?*?@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;??
  • ??
  • /**?
  • ?*?動態(tài)代理測試類?
  • ?*?@author?zyb?
  • ?*?@since?2012-8-9?
  • ?*?
  • ?*/??
  • public?class?ProxyTest?{??
  • ??
  • ????@Test??
  • ????public?void?testProxy()?throws?Throwable?{??
  • ????????//?實(shí)例化目標(biāo)對象??
  • ????????UserService?userService?=?new?UserServiceImpl();??
  • ??????????
  • ????????//?實(shí)例化InvocationHandler??
  • ????????MyInvocationHandler?invocationHandler?=?new?MyInvocationHandler(userService);??
  • ??????????
  • ????????//?根據(jù)目標(biāo)對象生成代理對象??
  • ????????UserService?proxy?=?(UserService)?invocationHandler.getProxy();??
  • ??????????
  • ????????//?調(diào)用代理對象的方法??
  • ????????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代碼??
  • /**?
  • ?*?loader:類加載器?
  • ?*?interfaces:目標(biāo)對象實(shí)現(xiàn)的接口?
  • ?*?h:InvocationHandler的實(shí)現(xiàn)類?
  • ?*/??
  • 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?{??
  • ????????????//?調(diào)用代理對象的構(gòu)造方法(也就是$Proxy0(InvocationHandler?h))??
  • ????????Constructor?cons?=?cl.getConstructor(constructorParams);??
  • ????????????//?生成代理類的實(shí)例并把MyInvocationHandler的實(shí)例傳給它的構(gòu)造方法??
  • ????????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??
  • ????{??
  • ????//?如果目標(biāo)類實(shí)現(xiàn)的接口數(shù)大于65535個(gè)則拋出異常(我XX,誰會寫這么NB的代碼啊?)??
  • ????if?(interfaces.length?>?65535)?{??
  • ????????throw?new?IllegalArgumentException("interface?limit?exceeded");??
  • ????}??
  • ??
  • ????//?聲明代理對象所代表的Class對象(有點(diǎn)拗口)??
  • ????Class?proxyClass?=?null;??
  • ??
  • ????String[]?interfaceNames?=?new?String[interfaces.length];??
  • ??
  • ????Set?interfaceSet?=?new?HashSet();???//?for?detecting?duplicates??
  • ??
  • ????//?遍歷目標(biāo)類所實(shí)現(xiàn)的接口??
  • ????for?(int?i?=?0;?i?<?interfaces.length;?i++)?{??
  • ??????????
  • ????????//?拿到目標(biāo)類實(shí)現(xiàn)的接口的名稱??
  • ????????String?interfaceName?=?interfaces[i].getName();??
  • ????????Class?interfaceClass?=?null;??
  • ????????try?{??
  • ????????//?加載目標(biāo)類實(shí)現(xiàn)的接口到內(nèi)存中??
  • ????????interfaceClass?=?Class.forName(interfaceName,?false,?loader);??
  • ????????}?catch?(ClassNotFoundException?e)?{??
  • ????????}??
  • ????????if?(interfaceClass?!=?interfaces[i])?{??
  • ????????throw?new?IllegalArgumentException(??
  • ????????????interfaces[i]?+?"?is?not?visible?from?class?loader");??
  • ????????}??
  • ??
  • ????????//?中間省略了一些無關(guān)緊要的代碼?.......??
  • ??????????
  • ????????//?把目標(biāo)類實(shí)現(xiàn)的接口代表的Class對象放到Set中??
  • ????????interfaceSet.add(interfaceClass);??
  • ??
  • ????????interfaceNames[i]?=?interfaceName;??
  • ????}??
  • ??
  • ????//?把目標(biāo)類實(shí)現(xiàn)的接口名稱作為緩存(Map)中的key??
  • ????Object?key?=?Arrays.asList(interfaceNames);??
  • ??
  • ????Map?cache;??
  • ??????
  • ????synchronized?(loaderToCache)?{??
  • ????????//?從緩存中獲取cache??
  • ????????cache?=?(Map)?loaderToCache.get(loader);??
  • ????????if?(cache?==?null)?{??
  • ????????//?如果獲取不到,則新建地個(gè)HashMap實(shí)例??
  • ????????cache?=?new?HashMap();??
  • ????????//?把HashMap實(shí)例和當(dāng)前加載器放到緩存中??
  • ????????loaderToCache.put(loader,?cache);??
  • ????????}??
  • ??
  • ????}??
  • ??
  • ????synchronized?(cache)?{??
  • ??
  • ????????do?{??
  • ????????//?根據(jù)接口的名稱從緩存中獲取對象??
  • ????????Object?value?=?cache.get(key);??
  • ????????if?(value?instanceof?Reference)?{??
  • ????????????proxyClass?=?(Class)?((Reference)?value).get();??
  • ????????}??
  • ????????if?(proxyClass?!=?null)?{??
  • ????????????//?如果代理對象的Class實(shí)例已經(jīng)存在,則直接返回??
  • ????????????return?proxyClass;??
  • ????????}?else?if?(value?==?pendingGenerationMarker)?{??
  • ????????????try?{??
  • ????????????cache.wait();??
  • ????????????}?catch?(InterruptedException?e)?{??
  • ????????????}??
  • ????????????continue;??
  • ????????}?else?{??
  • ????????????cache.put(key,?pendingGenerationMarker);??
  • ????????????break;??
  • ????????}??
  • ????????}?while?(true);??
  • ????}??
  • ??
  • ????try?{??
  • ????????//?中間省略了一些代碼?.......??
  • ??????????
  • ????????//?這里就是動態(tài)生成代理對象的最關(guān)鍵的地方??
  • ????????byte[]?proxyClassFile?=?ProxyGenerator.generateProxyClass(??
  • ????????????proxyName,?interfaces);??
  • ????????try?{??
  • ????????????//?根據(jù)代理類的字節(jié)碼生成代理類的實(shí)例??
  • ????????????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;??
  • ????}??


  • 進(jìn)去ProxyGenerator類的靜態(tài)方法generateProxyClass,這里是真正生成代理類class字節(jié)碼的地方。?

    Java代碼??
  • public?static?byte[]?generateProxyClass(final?String?name,??
  • ???????????????????????????????????????????Class[]?interfaces)??
  • ???{??
  • ???????ProxyGenerator?gen?=?new?ProxyGenerator(name,?interfaces);??
  • ????//?這里動態(tài)生成代理類的字節(jié)碼,由于比較復(fù)雜就不進(jìn)去看了??
  • ???????final?byte[]?classFile?=?gen.generateClassFile();??
  • ??
  • ????//?如果saveGeneratedFiles的值為true,則會把所生成的代理類的字節(jié)碼保存到硬盤上??
  • ???????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);??
  • ???????????????????}??
  • ???????????????}??
  • ???????????});??
  • ???????}??
  • ??
  • ????//?返回代理類的字節(jié)碼??
  • ???????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;??
  • ??
  • /**?
  • ?*?代理類的生成工具?
  • ?*?@author?zyb?
  • ?*?@since?2012-8-9?
  • ?*/??
  • public?class?ProxyGeneratorUtils?{??
  • ??
  • ????/**?
  • ?????*?把代理類的字節(jié)碼寫到硬盤上?
  • ?????*?@param?path?保存路徑?
  • ?????*/??
  • ????public?static?void?writeProxyClassToHardDisk(String?path)?{??
  • ????????//?第一種方法,這種方式在剛才分析ProxyGenerator時(shí)已經(jīng)知道了??
  • ????????//?System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles",?true);??
  • ??????????
  • ????????//?第二種方法??
  • ??????????
  • ????????//?獲取代理類的字節(jié)碼??
  • ????????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;??
  • ??
  • /**?
  • ?*?動態(tài)代理測試類?
  • ?*?@author?zyb?
  • ?*?@since?2012-8-9?
  • ?*?
  • ?*/??
  • public?class?ProxyTest?{??
  • ??
  • ????@Test??
  • ????public?void?testProxy()?throws?Throwable?{??
  • ????????//?實(shí)例化目標(biāo)對象??
  • ????????UserService?userService?=?new?UserServiceImpl();??
  • ??????????
  • ????????//?實(shí)例化InvocationHandler??
  • ????????MyInvocationHandler?invocationHandler?=?new?MyInvocationHandler(userService);??
  • ??????????
  • ????????//?根據(jù)目標(biāo)對象生成代理對象??
  • ????????UserService?proxy?=?(UserService)?invocationHandler.getProxy();??
  • ??????????
  • ????????//?調(diào)用代理對象的方法??
  • ????????proxy.add();??
  • ??????????
  • ????}??
  • ??????
  • ????@Test??
  • ????public?void?testGenerateProxyClass()?{??
  • ????????ProxyGeneratorUtils.writeProxyClassToHardDisk("F:/$Proxy11.class");??
  • ????}??
  • }??


  • 通過以上代碼,就可以在F盤上生成一個(gè)$Proxy.class文件了,現(xiàn)在用反編譯工具來看一下這個(gè)class文件里面的內(nèi)容。?

    Java代碼??
  • //?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??
  • {??
  • ??
  • ????//?構(gòu)造方法,參數(shù)就是剛才傳過來的MyInvocationHandler類的實(shí)例??
  • ????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);??
  • ????????}??
  • ????}??
  • ??
  • ????/**?
  • ?????*?這個(gè)方法是關(guān)鍵部分?
  • ?????*/??
  • ????public?final?void?add()??
  • ????{??
  • ????????try??
  • ????????{??
  • ????????????//?實(shí)際上就是調(diào)用MyInvocationHandler的public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)方法,第二個(gè)問題就解決了??
  • ????????????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;??
  • ??
  • ????//?在靜態(tài)代碼塊中獲取了4個(gè)方法: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());??
  • ????????}??
  • ????}??
  • }??


  • 好了,到目前為止,前面 的兩個(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ò),歡迎將生活随笔推薦給好友。