Java基礎(chǔ)之代理原理與用法詳解
本文實(shí)例講述了Java基礎(chǔ)之代理原理與用法。分享給大家供大家參考,具體如下:
1.什么是代理
動(dòng)態(tài)代理技術(shù)是整個(gè)java技術(shù)中最重要的一個(gè)技術(shù),它是學(xué)習(xí)java框架的基礎(chǔ),不會(huì)動(dòng)態(tài)代理技術(shù),那么在學(xué)習(xí)Spring這些框架時(shí)是學(xué)不明白的。
動(dòng)態(tài)代理技術(shù)就是用來產(chǎn)生一個(gè)對(duì)象的代理對(duì)象的。在開發(fā)中為什么需要為一個(gè)對(duì)象產(chǎn)生代理對(duì)象呢?
舉一個(gè)現(xiàn)實(shí)生活中的例子:歌星或者明星都有一個(gè)自己的經(jīng)紀(jì)人,這個(gè)經(jīng)紀(jì)人就是他們的代理人,當(dāng)我們需要找明星表演時(shí),不能直接找到該明星,只能是找明星的代理人。比如劉德華在現(xiàn)實(shí)生活中非常有名,會(huì)唱歌,會(huì)跳舞,會(huì)拍戲,劉德華在沒有出名之前,我們可以直接找他唱歌,跳舞,拍戲,劉德華出名之后,他干的第一件事就是找一個(gè)經(jīng)紀(jì)人,這個(gè)經(jīng)紀(jì)人就是劉德華的代理人(代理),當(dāng)我們需要找劉德華表演時(shí),不能直接找到劉德華了(劉德華說,你找我代理人商談具體事宜吧!),只能是找劉德華的代理人,因此劉德華這個(gè)代理人存在的價(jià)值就是攔截我們對(duì)劉德華的直接訪問!
這個(gè)現(xiàn)實(shí)中的例子和我們?cè)陂_發(fā)中是一樣的,我們?cè)陂_發(fā)中之所以要產(chǎn)生一個(gè)對(duì)象的代理對(duì)象,主要用于攔截對(duì)真實(shí)業(yè)務(wù)對(duì)象的訪問。那么代理對(duì)象應(yīng)該具有什么方法呢?代理對(duì)象應(yīng)該具有和目標(biāo)對(duì)象相同的方法
所以在這里明確代理對(duì)象的兩個(gè)概念:
1、代理對(duì)象存在的價(jià)值主要用于攔截對(duì)真實(shí)業(yè)務(wù)對(duì)象的訪問。
2、代理對(duì)象應(yīng)該具有和目標(biāo)對(duì)象(真實(shí)業(yè)務(wù)對(duì)象)相同的方法。劉德華(真實(shí)業(yè)務(wù)對(duì)象)會(huì)唱歌,會(huì)跳舞,會(huì)拍戲,我們現(xiàn)在不能直接找他唱歌,跳舞,拍戲了,只能找他的代理人(代理對(duì)象)唱歌,跳舞,拍戲,一個(gè)人要想成為劉德華的代理人,那么他必須具有和劉德華一樣的行為(會(huì)唱歌,會(huì)跳舞,會(huì)拍戲),劉德華有什么方法,他(代理人)就要有什么方法,我們找劉德華的代理人唱歌,跳舞,拍戲,但是代理人不是真的懂得唱歌,跳舞,拍戲的,真正懂得唱歌,跳舞,拍戲的是劉德華,在現(xiàn)實(shí)中的例子就是我們要找劉德華唱歌,跳舞,拍戲,那么只能先找他的經(jīng)紀(jì)人,交錢給他的經(jīng)紀(jì)人,然后經(jīng)紀(jì)人再讓劉德華去唱歌,跳舞,拍戲。
2.代理的分類
靜態(tài)代理:代理類和委托類在代碼運(yùn)行之前關(guān)系就已經(jīng)確定了,也就是說在代理類的代碼一開始就已經(jīng)存在了。
動(dòng)態(tài)代理:動(dòng)態(tài)代理類的字節(jié)碼在程序運(yùn)行的時(shí)候生成。
3.Java中的代理
"java.lang.reflect.Proxy"類介紹
現(xiàn)在要生成某一個(gè)對(duì)象的代理對(duì)象,這個(gè)代理對(duì)象通常也要編寫一個(gè)類來生成,所以首先要編寫用于生成代理對(duì)象的類。在java中如何用程序去生成一個(gè)對(duì)象的代理對(duì)象呢,java在JDK1.5之后提供了一個(gè)"java.lang.reflect.Proxy"類,通過"Proxy"類提供的一個(gè)newProxyInstance方法用來創(chuàng)建一個(gè)對(duì)象的代理對(duì)象,如下所示:
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
newProxyInstance方法用來返回一個(gè)代理對(duì)象,這個(gè)方法總共有3個(gè)參數(shù),ClassLoader loader用來指明生成代理對(duì)象使用哪個(gè)類裝載器,Class<?>[] interfaces用來指明生成哪個(gè)對(duì)象的代理對(duì)象,通過接口指定,InvocationHandler h用來指明產(chǎn)生的這個(gè)代理對(duì)象要做什么事情。所以我們只需要調(diào)用newProxyInstance方法就可以得到某一個(gè)對(duì)象的代理對(duì)象了。
編寫生成代理對(duì)象的類
在java中規(guī)定,要想產(chǎn)生一個(gè)對(duì)象的代理對(duì)象,那么這個(gè)對(duì)象必須要有一個(gè)接口,所以我們第一步就是設(shè)計(jì)這個(gè)對(duì)象的接口,在接口中定義這個(gè)對(duì)象所具有的行為(方法)
StduentInterface.java--定義對(duì)象的行為接口
public interface StduentInterface {
public int insertStudent(Student student);
}
StudentDao.java--定義目標(biāo)業(yè)務(wù)對(duì)象類
public class StudentDAO implements StduentInterface {
@Override
public int insertStudent(Student student) {
// 以下這段代碼是業(yè)務(wù)邏輯
return null == student ? 0 : 1;
}
}
創(chuàng)建靜態(tài)代理
public class StudentStaticProxyDAO {
private StudentDAO studentDAO;
public StudentStaticProxyDAO(StudentDAO studentDAO) {
this.studentDAO = studentDAO;
}
public int insertStudent(Student student) {
Logger.info("開始插入一個(gè)學(xué)生記錄: " + student.toString());
int number = studentDAO.insertStudent(student);
Logger.info("插入 " + number + " 條學(xué)生記錄");
return number;
}
}
動(dòng)態(tài)代理
public class LoggerDynamicProxy implements InvocationHandler{
private Object target;
public LoggerDynamicProxy(Object obj) {
this.target = obj;
}
/**
* 動(dòng)態(tài)代理類中的 invoke 方法
*
* 三個(gè)參數(shù)的意義:
*
* proxy :代理對(duì)象
* method : 委托類中要調(diào)用的方法
* args :method 方法的參數(shù)
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Logger.info("before 業(yè)務(wù)方法調(diào)用之前");
Object obj = method.invoke(target, args);
Logger.info("before 業(yè)務(wù)方法調(diào)用之前");
return obj;
}
}
測(cè)試類
public class ProxyTest {
public static void main(String[] args) {
/**
* 基礎(chǔ)組件準(zhǔn)備
*/
StudentDAO studentDao = new StudentDAO();
Student student = new Student(100000);
StudentStaticProxyDAO studentProxyDAO = new StudentStaticProxyDAO(studentDao);
/**
* 測(cè)試委托類的功能
*/
System.out.println(studentDao.insertStudent(student));
/**
* 測(cè)試靜態(tài)代理類的功能
*/
System.out.println(studentProxyDAO.insertStudent(student));
/**
* 測(cè)試動(dòng)態(tài)代理類的功能
*/
StduentInterface newProxyInstance = (StduentInterface)Proxy.newProxyInstance(studentDao.getClass().getClassLoader(),
studentDao.getClass().getInterfaces(),
new LoggerDynamicProxy(studentDao));
int insertStudent = newProxyInstance.insertStudent(student);
System.out.println(insertStudent);
}
運(yùn)行結(jié)果
1
INFO: 開始插入一個(gè)學(xué)生記錄: Student [id=100000, name=null]
INFO: 插入 1 條學(xué)生記錄
1
INFO: before 業(yè)務(wù)方法調(diào)用之前
INFO: before 業(yè)務(wù)方法調(diào)用之前
1
INFO: before 業(yè)務(wù)方法調(diào)用之前
INFO: before 業(yè)務(wù)方法調(diào)用之前
1
更多java相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Java面向?qū)ο蟪绦蛟O(shè)計(jì)入門與進(jìn)階教程》、《Java數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Java操作DOM節(jié)點(diǎn)技巧總結(jié)》、《Java文件與目錄操作技巧匯總》和《Java緩存操作技巧匯總》
希望本文所述對(duì)大家java程序設(shè)計(jì)有所幫助。
- java代理模式與動(dòng)態(tài)代理模式詳解
- java實(shí)現(xiàn)http的Post、Get、代理訪問請(qǐng)求
- Java中反射動(dòng)態(tài)代理接口的詳解及實(shí)例
- 基于接口實(shí)現(xiàn)java動(dòng)態(tài)代理示例
- 詳解java中動(dòng)態(tài)代理實(shí)現(xiàn)機(jī)制
- java動(dòng)態(tài)代理(jdk與cglib)詳細(xì)解析
- java實(shí)現(xiàn)動(dòng)態(tài)代理方法淺析
- Java動(dòng)態(tài)代理的應(yīng)用詳解
- 詳解java動(dòng)態(tài)代理的2種實(shí)現(xiàn)方式
- Java中的代理模式詳解及實(shí)例代碼
- 淺談Java注解和動(dòng)態(tài)代理
相關(guān)文章
SpringBoot項(xiàng)目導(dǎo)入aliyun oss starter依賴后啟動(dòng)報(bào)錯(cuò)問題
這篇文章主要介紹了SpringBoot項(xiàng)目導(dǎo)入aliyun oss starter依賴后啟動(dòng)報(bào)錯(cuò)問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
Spring MVC項(xiàng)目開發(fā)踩過的一些bug
這篇文章主要給大家介紹了關(guān)于Spring MVC項(xiàng)目開發(fā)踩過的一些bug,文中通過圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
解讀httpclient的validateAfterInactivity連接池狀態(tài)檢測(cè)
這篇文章主要為大家介紹了httpclient的validateAfterInactivity連接池狀態(tài)檢測(cè)解讀*,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11
Struts2實(shí)現(xiàn)CRUD(增 刪 改 查)功能實(shí)例代碼
CRUD是Create(創(chuàng)建)、Read(讀?。pdate(更新)和Delete(刪除)的縮寫,它是普通應(yīng)用程序的縮影。接下來通過本文給大家介紹Struts2實(shí)現(xiàn)CRUD(增 刪 改 查)功能實(shí)例代碼,感興趣的朋友一起看看吧2016-06-06
java實(shí)現(xiàn)登錄之后抓取數(shù)據(jù)
這篇文章給大家分享了用JAVA實(shí)現(xiàn)在登陸以后抓取網(wǎng)站的數(shù)據(jù)的相關(guān)知識(shí),有興趣的朋友可以測(cè)試參考下。2018-07-07
Spring-cloud-eureka使用feign調(diào)用服務(wù)接口
這篇文章主要為大家詳細(xì)介紹了Spring-cloud-eureka使用feign調(diào)用服務(wù)接口,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-04-04
SpringMVC 實(shí)現(xiàn)用戶登錄實(shí)例代碼
這篇文章主要介紹了SpringMVC 實(shí)現(xiàn)用戶登錄實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2017-02-02
Java學(xué)習(xí)關(guān)于循環(huán)和數(shù)組練習(xí)題整理
在本篇文章里小編給各位整理了關(guān)于Java學(xué)習(xí)關(guān)于循環(huán)和數(shù)組練習(xí)題相關(guān)內(nèi)容,有興趣的朋友們跟著參考學(xué)習(xí)下。2019-07-07

