Java基礎(chǔ)之讓你徹底搞懂代理模式
一、代理模式
什么是代理模式?
先來(lái)生活常用例子:你想買(mǎi)票,你沒(méi)必要去車(chē)站買(mǎi);而是可以去一個(gè)代售點(diǎn),代售點(diǎn)代理車(chē)站賣(mài)票,這就是一個(gè)簡(jiǎn)單的代理模式!
- 主要解決:在直接訪問(wèn)對(duì)象時(shí)帶來(lái)的問(wèn)題,比如說(shuō):要訪問(wèn)的對(duì)象在遠(yuǎn)程的機(jī)器上。在面向?qū)ο笙到y(tǒng)中,有些對(duì)象由于某些原因(比如對(duì)象創(chuàng)建開(kāi)銷(xiāo)很大,或者某些操作需要安全控制,或者需要進(jìn)程外的訪問(wèn)),直接訪問(wèn)會(huì)給使用者或者系統(tǒng)結(jié)構(gòu)帶來(lái)很多麻煩,我們可以在訪問(wèn)此對(duì)象時(shí)加上一個(gè)對(duì)此對(duì)象的訪問(wèn)層。
- 總結(jié):我們?cè)L問(wèn)實(shí)例對(duì)象時(shí)是通過(guò)代理對(duì)象訪問(wèn)的,這樣比較靈活也可以添加一些附加操作
二、靜態(tài)代理
顧名思義,靜態(tài)的,由程序員構(gòu)寫(xiě),在編譯是就已經(jīng)將程序接口,代理類(lèi)和被代理類(lèi)寫(xiě)定了!在程序運(yùn)行前就已經(jīng)生成!
來(lái)個(gè)簡(jiǎn)單實(shí)例:

設(shè)計(jì)公共接口Person:
public interface Person {
public void handinWork();
}
Student:
public class Student implements Person {
private String name;
public Student(String name) {
this.name=name;
}
public void setName(String name) {
this.name = name;
}
public void handinWork() {
System.out.println(name+"提交作業(yè)");
}
}
代理類(lèi)StudentProxy:
public class StudentProxy implements Person {
//代理誰(shuí)
Student student;
//防止重名,確保只是代理Student這個(gè)對(duì)象
public StudentProxy(Student student) {
if(student.getClass()==Student.class){
this.student = (Student) student;
}
}
public void handinWork() {
//交作業(yè)時(shí)代理(班長(zhǎng))想代替學(xué)生搞點(diǎn)事···
System.out.println("老師這個(gè)比的作業(yè)是抄的呢");
student.handinWork();
}
}
測(cè)試:
public class StaticProxy {
public static void main(String[] args) {
//創(chuàng)建出兩個(gè)對(duì)象,代理和被代理
Student student = new Student("張三");
StudentProxy monitor = new StudentProxy(student);
//代理類(lèi)去交作業(yè)?。。。。?
monitor.handinWork();
}
}
可以發(fā)現(xiàn),程序本質(zhì)還是學(xué)生交作業(yè),不過(guò)是通過(guò)一個(gè)中間層monitor(班長(zhǎng))去實(shí)現(xiàn)的,然后這個(gè)代理層還可以添加些其他的操作功能,在提交作業(yè)之前或者之后!
三、動(dòng)態(tài)代理
靜態(tài)代理是在程序運(yùn)行前就生成了,很明顯動(dòng)態(tài)代理就是在程序運(yùn)行期間添加代理層以達(dá)到效果。代理類(lèi)動(dòng)態(tài)生成!
- 需要了解兩個(gè)類(lèi):Proxy 代理, InvocationHandler
- Proxy:代理類(lèi),使用的時(shí)候動(dòng)態(tài)生成
- InvocationHandler:主要執(zhí)行需要代理的方法,使用invoke執(zhí)行
舉個(gè)例子:方便理解,就上面那個(gè)實(shí)例我們將它改造成一個(gè)動(dòng)態(tài)的!
第一步,創(chuàng)建一個(gè)類(lèi)實(shí)現(xiàn)InvocationHandler接口,用它構(gòu)建出代理類(lèi)和代理方法:
public class ProxyInvocation implements InvocationHandler {
//被代理的接口,真實(shí)的對(duì)象
private Person person;
//生成得到的代理類(lèi)
public void setPerson(Person person) {
this.person = person;
}
//通過(guò)Proxy類(lèi)的newProxyInstance方法創(chuàng)建代理對(duì)象,我們來(lái)看下方法中的參數(shù)
// * 第一個(gè)參數(shù):people.getClass().getClassLoader(),使用handler對(duì)象的classloader對(duì)象來(lái)加載我們的代理對(duì)象
// * 第二個(gè)參數(shù):people.getClass().getInterfaces(),這里為代理類(lèi)提供的接口是真實(shí)對(duì)象實(shí)現(xiàn)的接口,這樣代理對(duì)象就能像真實(shí)對(duì)象一樣調(diào)用接口中的所有方法
// * 第三個(gè)參數(shù):handler,我們將代理對(duì)象關(guān)聯(lián)到上面的InvocationHandler對(duì)象上
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),person.getClass().getInterfaces(),this);
}
//處理代理實(shí)例,返回結(jié)果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(person, args);
return result;
}
}
參照靜態(tài)代理,需要一個(gè)代理對(duì)象,只不過(guò)靜態(tài)代理中代理對(duì)象是我們手動(dòng)創(chuàng)建的,所以動(dòng)態(tài)代理中我們利用jdk自帶代理類(lèi)Proxy的newProxyInstance方法動(dòng)態(tài)的生成了一個(gè)代理類(lèi)而已,這個(gè)代理類(lèi)可以根據(jù)我們傳的參數(shù)動(dòng)態(tài)改變,
測(cè)試:
//真實(shí)角色student
Student student = new Student("張三");
//拿到InvocationHandler的繼承類(lèi)
ProxyInvocation pih = new ProxyInvocation();
//拿到代理的接口
pih.setPerson(student);
//動(dòng)態(tài)生成了proxy代理類(lèi)
Person proxy = (Person) pih.getProxy();
//代理類(lèi)執(zhí)行方法
proxy.handinWork();
改進(jìn)成工具類(lèi):將獲得接口部分全部采用參數(shù)代替;
private Object target;
//生成得到的代理類(lèi)
public void setPerson(Object target) {
this.target= target;
}
//通過(guò)Proxy類(lèi)的newProxyInstance方法創(chuàng)建代理對(duì)象,我們來(lái)看下方法中的參數(shù)
// * 第一個(gè)參數(shù):people.getClass().getClassLoader(),使用handler對(duì)象的classloader對(duì)象來(lái)加載我們的代理對(duì)象
// * 第二個(gè)參數(shù):people.getClass().getInterfaces(),這里為代理類(lèi)提供的接口是真實(shí)對(duì)象實(shí)現(xiàn)的接口,這樣代理對(duì)象就能像真實(shí)對(duì)象一樣調(diào)用接口中的所有方法
// * 第三個(gè)參數(shù):handler,我們將代理對(duì)象關(guān)聯(lián)到上面的InvocationHandler對(duì)象上
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
//處理代理實(shí)例,返回結(jié)果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(person, args);
return result;
}
就是把接口類(lèi)型和參數(shù)改一下就可以!后續(xù)會(huì)添加代理模式在Spring上的使用,
四、總結(jié)
你不敲一遍代碼你永遠(yuǎn)都不會(huì)理解,你抱著學(xué)一遍而不是徹底弄明白你也不可能學(xué)會(huì)!多查資料多理解代碼,多花點(diǎn)時(shí)間一定會(huì)懂得!加油老鐵。以解決問(wèn)題的心態(tài)學(xué)編程而不是為了高薪工作。
到此這篇關(guān)于Java基礎(chǔ)之讓你徹底搞懂代理模式的文章就介紹到這了,更多相關(guān)java代理模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java使用apache commons連接ftp修改ftp文件名失敗原因
這篇文章主要介紹了java使用apache commons連接ftp修改ftp文件名失敗原因解析,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-08-08
java比較兩個(gè)list是否相同equals的代碼詳解
在本篇文章里小編給大家分享的是關(guān)于java比較兩個(gè)list是否相同equals的代碼詳解,有需要的朋友們可以參考學(xué)習(xí)下。2020-02-02
SpringBoot配置SSL同時(shí)支持http和https訪問(wèn)實(shí)現(xiàn)
本文主要介紹了SpringBoot配置SSL同時(shí)支持http和https訪問(wèn)實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
java實(shí)現(xiàn)動(dòng)態(tài)上傳多個(gè)文件并解決文件重名問(wèn)題
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)動(dòng)態(tài)上傳多個(gè)文件,并解決文件重名問(wèn)題的方法,感興趣的小伙伴們可以參考一下2016-03-03
總結(jié)Java常用加解密方法AES?SHA1?md5
這篇文章主要為大家介紹了Java常用加密方法AES?SHA1?md5總結(jié)及示例demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
Java根據(jù)URL下載文件到本地的2種方式(大型文件與小型文件)
這篇文章主要給大家介紹了關(guān)于Java根據(jù)URL下載文件到本地的2種方式,分別是大型文件與小型文件,避免內(nèi)存溢出OOM,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-01-01
JavaScript中HTML元素操作的實(shí)現(xiàn)
本文主要介紹了JavaScript中HTML元素操作的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
Java設(shè)計(jì)模式之Iterator模式介紹
所謂Iterator模式,即是Iterator為不同的容器提供一個(gè)統(tǒng)一的訪問(wèn)方式。本文以java中的容器為例,模擬Iterator的原理。需要的朋友可以參考下2013-07-07

