詳解java動(dòng)態(tài)代理的2種實(shí)現(xiàn)方式
java的動(dòng)態(tài)代理在接java的api上有說(shuō)明,這里就不寫(xiě)了。我理解的代理:
對(duì)特定接口中特定方法的功能進(jìn)行擴(kuò)展,這就是代理。代理是通過(guò)代理實(shí)例關(guān)聯(lián)的調(diào)用處理程序?qū)ο笳{(diào)用方法。
下面通過(guò)一個(gè)例子看一下:
接口:
public interface Num {
void show();
int getNum();
int getProduct(int x);
}
實(shí)現(xiàn)類(lèi):
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中是怎么描述的
就是說(shuō)調(diào)用處理程序?qū)涌诘膶?shí)現(xiàn)類(lèi)對(duì)象調(diào)用Method對(duì)象表示的底層方法。
第一種實(shí)現(xiàn)代理的方式:
public class NumProxy {
private Object num;
//通過(guò)構(gòu)造方法構(gòu)造接口的實(shí)現(xiàn)類(lèi)對(duì)象
public NumProxy(Object num) {
this.num = num;
}
public Object getNumByProxy(){
Object numProxy = Proxy.newProxyInstance(num.getClass().getClassLoader(), new Class[]{Num.class}, new InvocationHandler() {
/**
* method: 對(duì)應(yīng)于在代理實(shí)例上調(diào)用的接口方法的 Method 實(shí)例。我理解的就是被代理的真實(shí)方法實(shí)例
* args: 我理解的是真實(shí)方法的參數(shù)數(shù)組
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object obj = null;
System.out.println("在方法之前開(kāi)始記錄");
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;
}
}
第二種實(shí)現(xiàn)代理的方式:通過(guò)實(shí)現(xiàn)InvocationHandler接口
public class NumProxyImpl implements InvocationHandler {
//這里我把接口類(lèi)型具體化了, 沒(méi)有寫(xiě)成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()開(kāi)始");
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()開(kāi)始");
obj = method.invoke(num, args);
System.out.println("proxy: show()結(jié)束");
}
return obj;
}
}
測(cè)試代碼:
public class TestNum {
public static void main(String[] args) {
//兩種方式一起測(cè)試
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();
}
}
控制臺(tái)結(jié)果:

第二種方式有點(diǎn)小疑惑,不知道大家有沒(méi)有,那就是并沒(méi)有顯示的調(diào)用NumProxyImpl中的invoke方法,可是卻執(zhí)行了,嗯嗯,這個(gè)自己下去看一下啊
不想麻煩的只需要記住就行了。
比如編碼的處理就可以用到代理,下次寫(xiě)個(gè)例子。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java?RabbitMQ消息隊(duì)列詳解常見(jiàn)問(wèn)題
消息隊(duì)列是最古老的中間件之一,從系統(tǒng)之間有通信需求開(kāi)始,就自然產(chǎn)生了消息隊(duì)列。本文告訴什么是消息隊(duì)列,為什么需要消息隊(duì)列,常見(jiàn)的消息隊(duì)列有哪些,RabbitMQ的部署和使用2022-07-07
JAVA如何使用Math類(lèi)操作數(shù)據(jù)
這篇文章主要介紹了JAVA如何使用Math類(lèi)操作數(shù)據(jù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
Java SpringBoot集成ChatGPT實(shí)現(xiàn)AI聊天
ChatGPT已經(jīng)組件放開(kāi)了,現(xiàn)在都可以基于它寫(xiě)插件了,也許可以用它結(jié)合文字語(yǔ)音開(kāi)發(fā)一個(gè)老人小孩需要的智能的說(shuō)話陪伴啥的,這篇文章就介紹SpringBoot結(jié)合ChatGPT實(shí)現(xiàn)AI聊天感興趣的同學(xué)可以借鑒一下2023-04-04
Java棧和基礎(chǔ)隊(duì)列的實(shí)現(xiàn)詳解
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)中的棧與隊(duì)列,在Java的時(shí)候,對(duì)于棧與隊(duì)列的應(yīng)用需要熟練的掌握,這樣才能夠確保Java學(xué)習(xí)時(shí)候能夠有扎實(shí)的基礎(chǔ)能力。本文小編就來(lái)詳細(xì)說(shuō)說(shuō)Java中的棧與隊(duì)列,需要的朋友可以參考一下2022-02-02
Spring MVC學(xué)習(xí)教程之RequestMappingHandlerAdapter詳解
這篇文章主要給大家介紹了關(guān)于Spring MVC學(xué)習(xí)教程之RequestMappingHandlerAdapter的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11
Spring Boot + Mybatis多數(shù)據(jù)源和動(dòng)態(tài)數(shù)據(jù)源配置方法
最近做項(xiàng)目遇到這樣的應(yīng)用場(chǎng)景,項(xiàng)目需要同時(shí)連接兩個(gè)不同的數(shù)據(jù)庫(kù)A, B,并且它們都為主從架構(gòu),一臺(tái)寫(xiě)庫(kù),多臺(tái)讀庫(kù)。下面小編給大家?guī)?lái)了Spring Boot + Mybatis多數(shù)據(jù)源和動(dòng)態(tài)數(shù)據(jù)源配置方法,需要的朋友參考下吧2018-01-01
Spring使用RestTemplate模擬form提交示例
本篇文章主要介紹了Spring使用RestTemplate模擬form提交示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-03-03
淺談Java實(shí)現(xiàn)回溯算法之八皇后問(wèn)題
八皇后問(wèn)題是一個(gè)古老而又著名的問(wèn)題,是學(xué)習(xí)回溯算法的一個(gè)經(jīng)典案例。今天我們就一起來(lái)探究一下吧2021-06-06
Spring中三種常見(jiàn)Bean的初始化參數(shù)機(jī)制你了解嗎
在Spring框架中,Bean的實(shí)例化與初始化是一個(gè)復(fù)雜的過(guò)程,本文我們主要來(lái)聊一聊它的常見(jiàn)的三種機(jī)制:InitializingBean接口、BeanDefinitionRegistryPostProcessor接口和EnvironmentAware接口,感興趣的小伙伴可以了解下2023-11-11

