詳解java動態(tài)代理的2種實現(xiàn)方式
java的動態(tài)代理在接java的api上有說明,這里就不寫了。我理解的代理:
對特定接口中特定方法的功能進行擴展,這就是代理。代理是通過代理實例關(guān)聯(lián)的調(diào)用處理程序?qū)ο笳{(diào)用方法。
下面通過一個例子看一下:
接口:
public interface Num { void show(); int getNum(); int getProduct(int x); }
實現(xiàn)類:
public class MyNum implements Num { @Override public int getNum() { return 3; } @Override public int getProduct(int x) { return x; } @Override public void show() { System.out.println("底層方法打印數(shù)字99"); } }
先看一下Method中的invoke方法在api中是怎么描述的
就是說調(diào)用處理程序?qū)涌诘膶崿F(xiàn)類對象調(diào)用Method對象表示的底層方法。
第一種實現(xiàn)代理的方式:
public class NumProxy { private Object num; //通過構(gòu)造方法構(gòu)造接口的實現(xiàn)類對象 public NumProxy(Object num) { this.num = num; } public Object getNumByProxy(){ Object numProxy = Proxy.newProxyInstance(num.getClass().getClassLoader(), new Class[]{Num.class}, new InvocationHandler() { /** * method: 對應(yīng)于在代理實例上調(diào)用的接口方法的 Method 實例。我理解的就是被代理的真實方法實例 * args: 我理解的是真實方法的參數(shù)數(shù)組 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object obj = null; System.out.println("在方法之前開始記錄"); String methodName = method.getName(); if("getProduct".equals(methodName)){ obj = method.invoke(num, args); obj = (Integer) obj * 2; System.out.println("proxy: getProduct()結(jié)束"); } else if("show".equals(methodName)){ obj = method.invoke(num, args); System.out.println("proxy: show()結(jié)束"); } return obj; } }); return numProxy; } }
第二種實現(xiàn)代理的方式:通過實現(xiàn)InvocationHandler接口
public class NumProxyImpl implements InvocationHandler { //這里我把接口類型具體化了, 沒有寫成Object private Num num; public NumProxyImpl(Num num){ this.num = num; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object obj = null; String methodName = method.getName(); if("getProduct".equals(methodName)){ System.out.println("proxy: getProduct()開始"); obj = method.invoke(num, args); obj = (Integer) obj * 2; System.out.println("proxy: getProduct()結(jié)束"); }else if("show".equals(methodName)){ System.out.println("proxy: show()開始"); obj = method.invoke(num, args); System.out.println("proxy: show()結(jié)束"); } return obj; } }
測試代碼:
public class TestNum { public static void main(String[] args) { //兩種方式一起測試 NumProxy np = new NumProxy(new MyNum()); Num numProxy = (Num) np.getNumByProxy(); int x = numProxy.getProduct(2); System.out.println(x); numProxy.show(); System.out.println("----------------"); NumProxyImpl npi = new NumProxyImpl(new MyNum()); Num numPro = (Num) Proxy.newProxyInstance(Num.class.getClassLoader(), new Class[]{Num.class}, npi); int n = numPro.getProduct(3); System.out.println(n); numPro.show(); } }
控制臺結(jié)果:
第二種方式有點小疑惑,不知道大家有沒有,那就是并沒有顯示的調(diào)用NumProxyImpl中的invoke方法,可是卻執(zhí)行了,嗯嗯,這個自己下去看一下啊
不想麻煩的只需要記住就行了。
比如編碼的處理就可以用到代理,下次寫個例子。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java SpringBoot集成ChatGPT實現(xiàn)AI聊天
ChatGPT已經(jīng)組件放開了,現(xiàn)在都可以基于它寫插件了,也許可以用它結(jié)合文字語音開發(fā)一個老人小孩需要的智能的說話陪伴啥的,這篇文章就介紹SpringBoot結(jié)合ChatGPT實現(xiàn)AI聊天感興趣的同學可以借鑒一下2023-04-04Spring MVC學習教程之RequestMappingHandlerAdapter詳解
這篇文章主要給大家介紹了關(guān)于Spring MVC學習教程之RequestMappingHandlerAdapter的相關(guān)資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面隨著小編來一起學習學習吧2018-11-11Spring Boot + Mybatis多數(shù)據(jù)源和動態(tài)數(shù)據(jù)源配置方法
最近做項目遇到這樣的應(yīng)用場景,項目需要同時連接兩個不同的數(shù)據(jù)庫A, B,并且它們都為主從架構(gòu),一臺寫庫,多臺讀庫。下面小編給大家?guī)砹薙pring Boot + Mybatis多數(shù)據(jù)源和動態(tài)數(shù)據(jù)源配置方法,需要的朋友參考下吧2018-01-01Spring使用RestTemplate模擬form提交示例
本篇文章主要介紹了Spring使用RestTemplate模擬form提交示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-03-03Spring中三種常見Bean的初始化參數(shù)機制你了解嗎
在Spring框架中,Bean的實例化與初始化是一個復(fù)雜的過程,本文我們主要來聊一聊它的常見的三種機制:InitializingBean接口、BeanDefinitionRegistryPostProcessor接口和EnvironmentAware接口,感興趣的小伙伴可以了解下2023-11-11