Java動態(tài)代理的示例詳解
定義
動態(tài)代理指的是,代理類和目標(biāo)類的關(guān)系在程序運(yùn)行的時(shí)候確定的,客戶通過代理類來調(diào)用目標(biāo)對象的方法,是在程序運(yùn)行時(shí)根據(jù)需要動態(tài)的創(chuàng)建目標(biāo)類的代理對象。
分類
jdk動態(tài)代理
cglib動態(tài)代理
案例
需求
蘋果公司通過蘋果代理商來賣手機(jī)
方案一:jdk動態(tài)代理
定義抽象接口
/** * 售賣手機(jī)的接口(代理模式——抽象角色) * @author:liyajie * @createTime:2022/2/22 14:42 * @version:1.0 */ public interface IPhone { /** * 出售手機(jī) * @author: liyajie * @date: 2022/2/22 14:44 * @param * @return void * @exception: * @update: * @updatePerson: **/ void sellPhone(); }
定義目標(biāo)類實(shí)現(xiàn)接口,重寫接口方法
/** * 蘋果公司(代理模式——目標(biāo)角色) * @author:liyajie * @createTime:2022/2/22 14:46 * @version:1.0 */ public class TargetPhone implements IPhone { @Override public void sellPhone() { System.out.println("蘋果公司正在出售手機(jī)"); } }
定義代理類
/** * 代理商(代理模式——代理角色) * @author:liyajie * @createTime:2022/2/22 14:50 * @version:1.0 */ public class ProxyPhone { private Object target; public ProxyPhone(Object target){ this.target = target; } public Object getProxyInstance() { return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("JDK動態(tài)代理開始之前,添加業(yè)務(wù)邏輯XXX"); //使用反射機(jī)制來調(diào)用目標(biāo)對象的方法:解決了問題二 Object invoke = method.invoke(target, args); System.out.println("JDK動態(tài)代理結(jié)束之后,添加業(yè)務(wù)邏輯XXX"); return invoke; } }); } }
定義測試類
/** * 測試類 * @author:liyajie * @createTime:2022/2/23 15:15 * @version:1.0 */ public class Test { public static void main(String[] args) { // 創(chuàng)建目標(biāo)類 TargetPhone targetPhone = new TargetPhone(); // 創(chuàng)建代理類 IPhone iPhone = (IPhone) new ProxyPhone(targetPhone).getProxyInstance(); System.out.println(iPhone.getClass()); // 通過代理類調(diào)用目標(biāo)方法 iPhone.sellPhone(); } }
查看測試結(jié)果
方案二:cglib動態(tài)代理
定義目標(biāo)類
/** * 蘋果公司(代理模式——目標(biāo)角色) * @author:liyajie * @createTime:2022/2/22 14:46 * @version:1.0 */ public class TargetPhone { public void sellPhone() { System.out.println("蘋果公司正在出售手機(jī)"); } }
定義代理工廠,用來獲取代理類
/** * 代理工廠 * @author:liyajie * @createTime:2022/2/23 15:32 * @version:1.0 */ public class ProxyFactory implements MethodInterceptor { private Object target; public ProxyFactory(Object target){ this.target = target; } public Object getProxyInstance(){ // 創(chuàng)建一個(gè)工具類 Enhancer enhancer = new Enhancer(); // 設(shè)置父類 enhancer.setSuperclass(target.getClass()); // 設(shè)置回調(diào)函數(shù) enhancer.setCallback(this); // 創(chuàng)建子類對象,即代理對象 return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("cglib動態(tài)代理開始之前,添加業(yè)務(wù)邏輯xxxx"); Object invoke = method.invoke(target, objects); System.out.println("cglib動態(tài)代理之后,添加業(yè)務(wù)邏輯"); return invoke; } }
定義測試類
/** * 測試類 * @author:liyajie * @createTime:2022/2/23 15:44 * @version:1.0 */ public class Test { public static void main(String[] args) { // 創(chuàng)建目標(biāo)對象 TargetPhone targetPhone = new TargetPhone(); // 獲取代理對象 TargetPhone proxyInstance = (TargetPhone)new ProxyFactory(targetPhone).getProxyInstance(); // 通過代理對象調(diào)用具體的方法 proxyInstance.sellPhone(); } }
查看測試結(jié)果
分析
首先可以看到不管是jdk動態(tài)代理,還是cglib動態(tài)代理,實(shí)現(xiàn)的效果和靜態(tài)代理是一模一樣的,都實(shí)現(xiàn)了功能的擴(kuò)展。但是兩種動態(tài)代理還是有些不同的,其中jdk動態(tài)代理需要目標(biāo)對象實(shí)現(xiàn)接口,但是cglib動態(tài)代理不需要,因?yàn)樗窃趦?nèi)存中構(gòu)建一個(gè)子類對象,從而實(shí)現(xiàn)對目標(biāo)對象的功能擴(kuò)展。
總結(jié)
通過案例,我們了解了代理模式的幾種實(shí)現(xiàn)方式,下面我們總結(jié)下該模式:
優(yōu)勢:
- 代理模式在客戶端和目標(biāo)對象之間起到了一個(gè)中介和保護(hù)的作用
- 代理對象可以對目標(biāo)對象進(jìn)行功能的擴(kuò)展和業(yè)務(wù)的擴(kuò)展,增強(qiáng)目標(biāo)對象
- 代理模式可以將客戶端和目標(biāo)對象分離,在一定程度上降低了系統(tǒng)的耦合度
劣勢:
- 請求需要經(jīng)過代理對象,會導(dǎo)致處理速度變慢
- 因?yàn)闀写罅康拇韺ο螽a(chǎn)生,會增加系統(tǒng)的復(fù)雜度
到此這篇關(guān)于Java動態(tài)代理的示例詳解的文章就介紹到這了,更多相關(guān)Java 動態(tài)代理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java操作MongoDB數(shù)據(jù)庫的示例代碼
這篇文章主要介紹了Java操作MongoDB的示例代碼,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下2021-04-04關(guān)于Mybatis插入對象時(shí)空值的處理
這篇文章主要介紹了關(guān)于Mybatis插入對象時(shí)空值的處理方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-06-06SpringBoot實(shí)現(xiàn)評論回復(fù)功能(數(shù)據(jù)庫設(shè)計(jì))
這篇文章主要介紹了SpringBoot實(shí)現(xiàn)評論回復(fù)功能(數(shù)據(jù)庫設(shè)計(jì)),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04Mybatis之@ResultMap,@Results,@Result注解的使用
這篇文章主要介紹了Mybatis之@ResultMap,@Results,@Result注解的使用,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12基于java socket實(shí)現(xiàn) 聊天小程序
這篇文章主要介紹了基于java socket實(shí)現(xiàn) 聊天小程序,代碼分為服務(wù)器和客戶端,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-12-12手把手帶你分析SpringBoot自動裝配完成了Ribbon哪些核心操作
這篇文章主要介紹了詳解Spring Boot自動裝配Ribbon哪些核心操作的哪些操作,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-08-08