摘要:實際開發(fā)中的,通用異常處理,通用日志處理,事物處理都可以用到動態(tài)代理。四總結(jié)優(yōu)點動態(tài)代理類簡化了代碼編程工作,提高了軟件的可擴展性。
JDK的動態(tài)代理
一、靜態(tài)代理
了解動態(tài)代理前,有必要先講解下靜態(tài)代理。
舉個例子:銀行開通了短信業(yè)務,在你取錢,存錢,轉(zhuǎn)賬后都會 給你發(fā)送短信,我們來模擬下業(yè)務場景。
靜態(tài)代理的實現(xiàn)
下面來模擬下業(yè)務代碼
1.定義IBankCardService接口
/** * 銀行卡操作接口 * @author yizl * */ public interface IBankCardService { /** * 存錢 * @param cardId */ public void putInMoney(String cardId); /** * 取錢 * @param cardId */ public void outMoney(String cardId); /** * 查詢余額 * @param cardId */ public String getMoney(String cardId); }
2.接口實現(xiàn)(BankCardServiceImpl)
/** * 銀行卡操作實現(xiàn)類 * @author yizl * */ public class BankCardServiceImpl implements IBankCardService { @Override public void putInMoney(String cardId) { System.out.println("開始往銀行卡賬號為:"+cardId+" 存錢"); } @Override public void outMoney(String cardId) { System.out.println("向銀行卡賬號為:"+cardId+" 取錢"); } @Override public String getMoney(String cardId) { System.out.println("查詢銀行卡賬號為:"+cardId+" 的余額"); return null; } }
3.編寫代理類
假設項目經(jīng)理有個需求:在每次業(yè)務操作后都需要向用戶發(fā)送短信.
在不修改已有的實現(xiàn)類的前提下怎么實現(xiàn)這個需求.
1.我們寫一個代理類,讓它與銀行卡操作實現(xiàn)類的接口相同.
2.在代理類的構(gòu)造器中,傳入銀行卡操作實現(xiàn)類,在代理類的方法內(nèi)部仍然調(diào)用銀行卡操作實現(xiàn)類的方法.
代理類
/** * 代理銀行卡操作實現(xiàn)類 * @author yizl * */ public class ProxyBankCardServiceImpl implements IBankCardService { private IBankCardService bankCardService; public ProxyBankCardServiceImpl(IBankCardService bankCardService) { this.bankCardService=bankCardService; } @Override public void putInMoney(String cardId) { bankCardService.putInMoney(cardId); System.out.println("向客戶發(fā)送短信"); } @Override public void outMoney(String cardId) { bankCardService.outMoney(cardId); System.out.println("向客戶發(fā)送短信"); } @Override public String getMoney(String cardId) { bankCardService.getMoney(cardId); System.out.println("向客戶發(fā)送短信"); return null; } }
4.調(diào)用代理類
public class ProxyTest { public static void main(String[] args) { IBankCardService bankCardService =new BankCardServiceImpl(); IBankCardService proxyBankCard=new ProxyBankCardServiceImpl(bankCardService); proxyBankCard.putInMoney("9527"); } } 打印結(jié)果: 開始往銀行卡賬號為:9527的賬戶存錢 向客戶發(fā)送短信
可以看出,代理類的作用:代理對象=增強代碼+目標對象
代理類只對銀行卡操作實現(xiàn)類進行增強,每個方法都添加發(fā)送短信業(yè)務,真正業(yè)務還是在銀行卡操作實現(xiàn)類中在進行。
靜態(tài)代理的缺點
我們發(fā)現(xiàn)靜態(tài)代碼其實很麻煩,有點脫褲子放屁的意思.
靜態(tài)代理的缺點:
1.要為每一個目標類都要編寫相應的代理類,會有很多代理類。 2.接口改了,目標類和代理類都要跟著改。
二、動態(tài)代理
我們只想寫增強的代碼,不需要寫代理類,增強代碼還可以復用到不同的目標類。這時動態(tài)代理橫空出世了。
動態(tài)代理實現(xiàn)
1、獲取代理類方式一
1.JDK提供了 java.lang.reflect.Proxy類有一個getProxyClass(ClassLoader, interfaces)靜態(tài)方法,傳入類加載器,和接口,就可以得到代理類的Class對象.
2.得到了代理類的class對象,通過代理類的class對象得到構(gòu)造器,java.lang.reflect.InvocationHandler類中,每一個動態(tài)代理類都要實現(xiàn)InvocationHandler接口,動態(tài)代理對象調(diào)用一個方法時,就會轉(zhuǎn)到實現(xiàn)InvocationHandler接口類的invoke方法.
3.得到代理類,實行調(diào)用.
public class ProxyTest { public static void main(String[] args) throws Exception { //目標對象 IBankCardService bankCard=new BankCardServiceImpl(); //獲取代理對象 IBankCardService proxyBank = (IBankCardService) getProxy(bankCard); //調(diào)用方法 proxyBank.getMoney("9527"); } /** * 獲取代理類 * @param target 目標類 * @return * @throws SecurityException * @throws NoSuchMethodException */ private static Object getProxy(Object target) throws Exception { //得到代理類大class Class proxyClass = Proxy.getProxyClass(target.getClass().getClassLoader(), target.getClass().getInterfaces()); //創(chuàng)建代理類的構(gòu)造函數(shù),構(gòu)造函數(shù)的方法必須傳入InvocationHandler接口的實現(xiàn)類 Constructor constructor=proxyClass.getConstructor(InvocationHandler.class); //獲取代理類 Object proxy =constructor.newInstance(new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //調(diào)用目標文件的方法 Object resulet = method.invoke(target,args); //增強方法 System.out.println("向客戶發(fā)送短信"); return resulet; } }); return proxy; } } 打印結(jié)果: 查詢銀行卡賬號為:9527的賬戶 的余額 向客戶發(fā)送短信
2、獲取代理類方式二
實際變成中不會使用getProxyClass(),因為JDK的Proxy類提供了更好用的方法newProxyInstance(ClassLoader loader, Class>[] interfaces,InvocationHandler h),直接傳入InvocationHandler 實現(xiàn)類就可以的到代理類.
1.代理類的調(diào)用處理程序?qū)崿F(xiàn)
/** * 發(fā)送短信調(diào)用類 * @author yizl * */ public class SendMessageInvocation implements InvocationHandler { /** * 目標類 */ private Object obj; /** * 通過構(gòu)造方法傳參 * @param obj */ public SendMessageInvocation(Object obj) { this.obj=obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //調(diào)用目標文件的方法 Object resulet = method.invoke(obj,args); //增強方法 System.out.println("向客戶發(fā)送短信"); return resulet; } }
2.獲取代理類,調(diào)用取錢方法
public class ProxyTest { public static void main(String[] args) throws Exception { // 獲取銀行卡操作實現(xiàn)類 IBankCardService bankCard = new BankCardServiceImpl(); // 獲取銀行卡操作類的代理類 IBankCardService proxyBank = (IBankCardService)Proxy.newProxyInstance(bankCard.getClass().getClassLoader(), bankCard.getClass().getInterfaces(),new SendMessageInvocation(bankCard)); proxyBank.outMoney("9527"); } } 打印結(jié)果: 向銀行卡賬號為:9527的賬戶取錢 向客戶發(fā)送短信
用JDK提供的代理類,很完美的解決了,不寫代理類,直接寫增強方法,直接就獲取到目標的代理類。
三、動態(tài)代理的應用
設計模式中有一個設計原則是開閉原則:軟件中對于擴展是開放的,對于修改是封閉的。再不改變源碼的情況下,拓展它的行為。 工作中接收了很多以前的代碼,里面的邏輯讓人摸不透,就可以使用代理類進行增強。 Spring的AOP就是Java的動態(tài)代理來實現(xiàn)的切面編程。 RPC框架,框架本身不知道要調(diào)用哪些接口,哪些方法。這是框架可以一個創(chuàng)建代理類給客戶端使用。 實際開發(fā)中的,通用異常處理,通用日志處理,事物處理都可以用到動態(tài)代理。
四、總結(jié)
優(yōu)點:
動態(tài)代理類簡化了代碼編程工作,提高了軟件的可擴展性。
缺點:
JDK動態(tài)代理只能代理有接口的實現(xiàn)類,沒有接口的類就不能用JDK的動態(tài)代理。(Cglib動態(tài)代理可以對沒有接口的類實現(xiàn)代理)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/77763.html
摘要:要明白,動態(tài)代理類的存在意義是為了攔截方法并修改邏輯而動態(tài)代理的局限性之一就是只能攔截接口所聲明的方法。因為動態(tài)代理類是繼承自業(yè)務類,所以該類和方法不能聲明成無法繼承或重寫。者最終都是生成了一個新的動態(tài)代理類對象。 動態(tài)代理 1、先談靜態(tài)代理 對于靜態(tài)代理,我們已經(jīng)很熟悉了。我們擁有一個抽象類,真實類繼承自抽象類并重寫其業(yè)務方法,代理類持有真實類的對象實例,在重寫業(yè)務方法中通過調(diào)用真實...
摘要:動態(tài)代理的核心是接口和類。以上結(jié)果說明它生成的代理類為,說明是代理。測試前提實現(xiàn)接口測試類使用接口方式注入代理方式必須以接口方式注入測試配置為,運行結(jié)果如下實際校驗邏輯。。。。 本文也同步發(fā)布至簡書,地址:https://www.jianshu.com/p/f70... AOP設計模式通常運用在日志,校驗等業(yè)務場景,本文將簡單介紹基于Spring的AOP代理模式的運用。 1. 代理模...
摘要:與靜態(tài)代理對比,動態(tài)代理是在動態(tài)生成代理類,由代理類完成對具體方法的封裝,實現(xiàn)的功能。本文將分析中兩種動態(tài)代理的實現(xiàn)方式,和,比較它們的異同。那如何動態(tài)編譯呢你可以使用,這是一個封裝了的庫,幫助你方便地實現(xiàn)動態(tài)編譯源代碼。 發(fā)現(xiàn)Java面試很喜歡問Spring AOP怎么實現(xiàn)的之類的問題,所以寫一篇文章來整理一下。關(guān)于AOP和代理模式的概念這里并不做贅述,而是直奔主題,即AOP的實現(xiàn)方...
摘要:值得一提的是由于采用動態(tài)創(chuàng)建子類的方式生成代理對象,所以不能對目標類中的方法進行代理。動態(tài)代理中生成的代理類是子類,調(diào)試的時候可以看到,打開源碼可看到實現(xiàn)了和也就實現(xiàn)方法。 前面講到了動態(tài)代理的底層原理,接下來我們來看一下aop的動態(tài)代理.Spring AOP使用了兩種代理機制:一種是基于JDK的動態(tài)代理,一種是基于CGLib的動態(tài)代理. ①JDK動態(tài)代理:使用JDK創(chuàng)建代理有一個限制...
摘要:動態(tài)代理是包提供的方式,它必須借助一個接口才能產(chǎn)生代理對象,所以要預先定義接口。第步,建立代理對象和真實對象的關(guān)系。第個是把生成的動態(tài)代理對象下掛在哪些接口下,這個寫法就是放在實現(xiàn)的接口下。 JDK動態(tài)代理是java.lang.reflect.*包提供的方式,它必須借助一個接口才能產(chǎn)生代理對象,所以要預先定義接口。 1. 接口 public interface Hello { ...
閱讀 2657·2023-04-26 00:07
閱讀 2441·2021-11-15 11:37
閱讀 652·2021-10-19 11:44
閱讀 2181·2021-09-22 15:56
閱讀 1736·2021-09-10 10:50
閱讀 1511·2021-08-18 10:21
閱讀 2579·2019-08-30 15:53
閱讀 1640·2019-08-30 11:11