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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

教你清楚了解JAVA动态代理

發(fā)布時間:2025/5/22 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 教你清楚了解JAVA动态代理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

2019獨角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>

  • 代理在生活中很常見,比如說婚介網(wǎng)站,其實就是找對象的代理;還有社保代理、人事代理;還有找黃牛搶票,其實也是一種代理;而這些代理,在JAVA中也是有對應(yīng)實現(xiàn)的。

1、為什么要動態(tài)代理

動態(tài)代理的作用其實就是在不修改原代碼的前提下,對已有的方法進(jìn)行增強。

關(guān)鍵點:

  • 不修改原來已有的代碼(滿足設(shè)計模式的要求)
  • 對已有方法進(jìn)行增強

2、舉個栗子

我們用一個很簡單的例子來說明: Hello 類,有一個 introduction 方法。

現(xiàn)在我們的需求就是不修改 Hello 類的 introduction 方法,在 introduction 之前先 sayHello ,在 introduction 之后再 sayGoodBye

3、實現(xiàn)方式

JAVA中,實現(xiàn)動態(tài)代理有兩種方式,一種是JDK提供的,一種是第三方庫 CgLib 提供的。特點如下:

? CgLib

3.1、JDK動態(tài)代理

JDK動態(tài)代理需要實現(xiàn)接口,然后通過對接口方法的增強來實現(xiàn)動態(tài)代理

所以要使用JDK動態(tài)代理的話,我們首先要創(chuàng)建一個接口,并且被代理的方法要在這個接口里面

3.1.1、創(chuàng)建一個接口

我們創(chuàng)建一個接口如下:

Personal.java

? public interface Personal { /** * 被代理的方法 */ void introduction(); }

3.1.2、實現(xiàn)接口

創(chuàng)建接口實現(xiàn)類,并且完成 introduction 方法

PersonalImpl.java

? public class PersonalImpl implements Personal { @Override public void introduction() { System.out.println("我是程序員!"); } }

3.1.3、創(chuàng)建代理類

JDK代理的關(guān)鍵就是這個代理類了,需要實現(xiàn) InvocationHandler

在代理類中,所有方法的調(diào)用都好分發(fā)到 invoke 方法中。我們在 invoke 方法完成對方法的增強即可

JDKProxyFactory.java

? import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class JDKProxyFactory<T> implements InvocationHandler { /** * 目標(biāo)對象 */ private T target; /** * 構(gòu)造函數(shù)傳入目標(biāo)對象 * * @param target 目標(biāo)對象 */ public JDKProxyFactory(T target) { this.target = target; } /** * 獲取代理對象 * * @return 獲取代理 */ public T getProxy() { return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 對方法增強 System.out.println("大家好!"); // 調(diào)用原方法 Object result = method.invoke(target, args); // 方法增強 System.out.println("再見!"); return result; } }

就這樣,JDK動態(tài)代理的代碼就完成了,接下來寫一份測試代碼

3.1.4、編寫測試代碼

為了方便測試,我們編寫一個 test 方法

同時為了查看class文件,還添加了一個 generatorClass 方法,這個方法可以將動態(tài)代理生成的 .class 輸出到文件

ProxyTest.java

? import org.junit.Test; import sun.misc.ProxyGenerator; import java.io.FileOutputStream; import java.io.IOException; public class ProxyTest { @Test public void testJdkProxy() { // 生成目標(biāo)對象 Personal personal = new PersonalImpl(); // 獲取代理對象 JDKProxyFactory<Personal> proxyFactory = new JDKProxyFactory<>(personal); Personal proxy = proxyFactory.getProxy(); // 將proxy的class字節(jié)碼輸出到文件 generatorClass(proxy); // 調(diào)用代理對象 proxy.introduction(); } /** * 將對象的class字節(jié)碼輸出到文件 * * @param proxy 代理類 */ private void generatorClass(Object proxy) { FileOutputStream out = null; try { byte[] generateProxyClass = ProxyGenerator.generateProxyClass(proxy.getClass().getSimpleName(), new Class[]{proxy.getClass()}); out = new FileOutputStream(proxy.getClass().getSimpleName() + ".class"); out.write(generateProxyClass); } catch (Exception e) { e.printStackTrace(); } finally { if (out != null) { try { out.close(); } catch (IOException e) { // TODO Auto-generated catch block } } } } }

3.1.5、查看運行結(jié)果

可以看到,運行 test 方法之后,控制臺打印出如下:

? 大家好! 我是程序員! 再見!

我們在 introduction 方法前和后都成功增加了功能,讓這個程序員的自我介紹瞬間變得更加有禮貌了。

3.1.6、探探動態(tài)代理的秘密

動態(tài)代理的代碼并不多,那么JDK底層是怎么幫我們實現(xiàn)的呢?

在測試的時候我們將動態(tài)生成的代理類的 class 字節(jié)碼輸出到了文件,我們可以反編譯看看。

結(jié)果有點長,就不全部貼出來了,不過我們可以看到,里面有一個 introduction 方法如下:

? /** * the invocation handler for this proxy instance. * @serial */ protected InvocationHandler h; protected Proxy(InvocationHandler h) { Objects.requireNonNull(h); this.h = h; } public final void introduction() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } }

原來,生成的代理對象里面,引用了我們的 InvocationHandler ,然后在將 introduction 方法里面調(diào)用了 InvocationHandler 的 introduction ,而 InvocationHandler 是由我們編寫的代理類,在這里我們增加了 sayHello 和 sayGoodBye 操作,然后還調(diào)用了原對象的 introduction 方法,就這樣完成了動態(tài)代理。

3.2、CgLib動態(tài)代理

CgLib 動態(tài)

3.2.1、創(chuàng)建被代理對象

由于 CgLib 不需要實現(xiàn)接口,所以我們不需要創(chuàng)建接口文件了(當(dāng)然,你要有接口也沒有問題)

直接創(chuàng)建目標(biāo)類,實現(xiàn) introduction 方法

PersonalImpl.java

? public class PersonalImpl { public void introduction() { System.out.println("我是程序員!"); } }

3.2.2、創(chuàng)建代理類

同樣,我們也需要創(chuàng)建代理類,并且在這里實現(xiàn)增強的邏輯,這次我們不是實現(xiàn) InvocationHandler 接口了,而是實現(xiàn) CgLib 提供的接口 MethodInterceptor ,都是類似的, MethodInterceptor 中,全部方法調(diào)用都會交給 intercept 處理,我們在 intercept 添加處理邏輯即可。

CgLibProxyFactory.java

? import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class CgLibProxyFactory<T> implements MethodInterceptor { /** * 獲取代理對象 * * @param tClass 被代理的目標(biāo)對象 * @return 代理對象 */ public T getProxyByCgLib(Class<T> tClass) { // 創(chuàng)建增強器 Enhancer enhancer = new Enhancer(); // 設(shè)置需要增強的類的類對象 enhancer.setSuperclass(tClass); // 設(shè)置回調(diào)函數(shù) enhancer.setCallback(this); // 獲取增強之后的代理對象 return (T) enhancer.create(); } /** * 代理類方法調(diào)用回調(diào) * * @param obj 這是代理對象,也就是[目標(biāo)對象]的子類 * @param method [目標(biāo)對象]的方法 * @param args 參數(shù) * @param proxy 代理對象的方法 * @return 返回結(jié)果,返回給調(diào)用者 * @throws Throwable */ @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("大家好!"); Object result = proxy.invokeSuper(obj, args); System.out.println("再見!"); return result; } }

3.2.3、編寫測試代碼

在剛才的測試方法中,我們添加一個 cglib 的測試方法:

? @Test public void testCgLibProxy() { // 生成被代理的目標(biāo)對象 PersonalImpl personal = new PersonalImpl(); // 獲取代理類 CgLibProxyFactory<PersonalImpl> proxyFactory = new CgLibProxyFactory<>(); PersonalImpl proxy = proxyFactory.getProxyByCgLib((Class<PersonalImpl>) personal.getClass()); // 將proxy的class字節(jié)碼輸出到文件 generatorClass(proxy); // 調(diào)用代理對象 proxy.introduction(); }

3.2.4、查看運行結(jié)果

運行測試用例,可以看到跟JDK的實現(xiàn)一樣的效果

? 大家好! 我是程序員! 再見!

3.2.5、探探動態(tài)代理的秘密

跟JDK的測試一樣,我們也來看看生成的 class 文件

? public final void introduction() throws { try { super.h.invoke(this, m7, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } }

可以發(fā)現(xiàn),與JDK的動態(tài)代理并沒有區(qū)別。

4、如何選擇

既然有兩種實現(xiàn)方式,那么到底應(yīng)該怎么選擇呢?

就兩個原則:

  • 目標(biāo)類有接口實現(xiàn)的, JDK 和 CgLib 都可以選擇,你開心就好
  • 目標(biāo)類沒有實現(xiàn)任何接口,那只能用 CgLib 了

分享一些知識點給大家希望能幫助到大家,或者從中啟發(fā)。

加入Q君羊:821169538 都是java愛好澤,大家可以一起討論交流學(xué)習(xí)

原文

http://fengqiangboy.com/15377761043880.html

轉(zhuǎn)載于:https://my.oschina.net/u/3972077/blog/2208364

總結(jié)

以上是生活随笔為你收集整理的教你清楚了解JAVA动态代理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产裸体永久免费视频网站 | www.日韩在线| 精品国产成人av | 男女h网站| 免费黄网在线看 | 欧美日韩色| 黄色片亚洲 | 国产欧美在线视频 | 夜夜激情网 | 亚洲日本成人 | 污污视频在线观看网站 | 日韩电影在线观看一区二区 | 国内一级视频 | 久久不雅视频 | 爱情岛亚洲首页论坛小巨 | 韩国伦理大片 | 日韩在线毛片 | www.在线观看麻豆 | 天天色天天射天天操 | 亚洲综合视频在线 | 免费毛片观看 | 亚洲国产成人av | 影音先锋 日韩 | 激情黄色av | 秋霞欧美在线观看 | 国产探花在线精品一区二区 | 午夜视频网 | 国产精品久久久久久一区二区三区 | 精品少妇一区二区三区免费观 | www.在线观看av | 日韩国产精品久久 | 日韩欧美国产一区二区三区在线观看 | 午夜看看 | 日日夜夜操操操 | 欧美成人精品二区三区99精品 | 蜜臀av粉嫩av懂色av | 欧美疯狂做受 | 国产精品久久麻豆 | 黄色一级片免费播放 | 东北老女人av | 欧美综合国产 | 欧美人交a欧美精品 | 欧美视频免费 | 日本强好片久久久久久aaa | 麻豆免费观看视频 | 在线性视频 | 日本在线视频一区 | av资源部 | 日韩a级一片 | 久久久一二三四 | 91丨国产丨白丝 | 久草中文在线 | 免费国产 | 操一操av| 视频区小说区 | 99热视| 日韩精品少妇 | 女同中文字幕 | 国产精品国产精品国产专区不卡 | 丁香花五月天 | 性av免费| 91丨porny丨国产 | 国产精品作爱 | 美女被日网站 | 永久视频在线 | 中文在线最新版天堂 | 精品免费观看 | 91偷拍精品一区二区三区 | 人人揉人人 | 成人免费网视频 | 张柏芝亚洲一区二区三区 | av综合色| www.久久久 | 人人妻人人澡人人爽精品 | 久色免费视频 | 越南a级片 | 免费黄色网址在线观看 | 桥本有菜aⅴ一区二区三区 在线午夜电影 | 亚洲 日本 欧美 中文幕 | a视频免费在线观看 | 亚洲妇熟xx妇色黄蜜桃 | 男女无遮挡猛进猛出 | 91大尺度 | 肉色欧美久久久久久久免费看 | 99久精品 | 日韩在线观看网站 | 日韩精品视频免费在线观看 | 国产69精品久久久久999小说 | 亚洲av无码一区东京热久久 | 黑人精品无码一区二区三区 | 学生调教贱奴丨vk | 在线观看亚洲欧美 | 久久精久久 | 日韩一区二区三区免费在线观看 | 影音先锋在线看片资源 | 亚洲日本香蕉 | 欧美日韩精品久久久 | 国产精品久久久久久久久久免费 | 亚洲の无码国产の无码步美 |