上一篇大家又說我放水了。這樣說我很傷心的啵。今天跟大家分享一下代理模式以及JAVA中的代理模式。
代理模式有什么用呢?我總結(jié)的一點(diǎn)就是,讓別人代理安全一點(diǎn)。
現(xiàn)實(shí)生活中其實(shí)也有很多代理。
比如保險代理,你不需要去關(guān)注太多的細(xì)節(jié),只需要做決策是否需要買保險,至于買那種保險適合你,需要哪些資料,都通過代理去幫你管理,雖然要出一點(diǎn)錢,不會浪費(fèi)自己的時間。
又比如保安,由保安去代理幫你識別出入口的安全問題,自己只需要管理公司內(nèi)部的事宜。
又比如網(wǎng)絡(luò)服務(wù)供應(yīng)商代理,由代理去幫你決定使用什么路由決策,使用哪些網(wǎng)線哪些網(wǎng)段,自己只需要保證跟網(wǎng)絡(luò)供應(yīng)商的鏈接是通的。
代理總是要有額外的開銷的,這點(diǎn)是毋庸置疑的,無論在生活中還是軟件層面中。生活中需要付出額外的時間去尋找代理,額外的金錢去雇傭代理。軟件中需要寫額外的代碼去設(shè)計這種代理,或者需要消耗額外的時間去進(jìn)行代理的調(diào)用。
但就一個字,值!
代理模式按用途來分,有以下這么幾種:
(1)?遠(yuǎn)程代理(Remote Proxy)
(2)?虛擬代理(Virtual Proxy)
(3)?保護(hù)代理(Protect Proxy)
(4)?緩沖代理(Cache Proxy)
(5)?智能引用代理(Smart Reference Proxy)
遠(yuǎn)程代理(Remote Proxy)
遠(yuǎn)程代理就類似網(wǎng)絡(luò)服務(wù)供應(yīng)商,用來與外面進(jìn)行通信,內(nèi)部所有的通信都通過這一個或者幾個代理進(jìn)行,比較方便,也比較安全。有啥事我就誰也不找我就找你了,我就賴在這里不走了哼。
虛擬代理(Virtual Proxy)
怎么說呢,人要臉樹要皮,在每加載完成的時候也不希望別人看到蒼茫的天涯吧?這是你的愛嗎?虛擬機(jī)代理就是在大文件加載的時候,先給別人看看,誒你別說,我這里是有料的喔,毋問題你等等就能看到主菜了。
保護(hù)代理(Protect Proxy)
保安,控制系統(tǒng)輸入輸出的安全性。
緩沖緩存代理(Buffer and Cache Proxy)
哎呀呀,這里很多人就不知道緩沖和緩存的區(qū)別了,有很多設(shè)計中都習(xí)慣使用緩沖緩存一起設(shè)計的模式,但是緩沖跟緩存是有區(qū)別的。
緩沖是什么呢?是避震器,是用來緩解大壓力用的,作為一個過渡的區(qū)域。緩存又是啥玩意?緩存就是一個方便存儲的box,我們用隨身的管家來比喻可能好一點(diǎn),方便,快捷。
我????:我要吃雞。
管家:沒問題馬上送到。
管家:您的雞來了。
我????:這一千萬幫我存起來。
管家:沒問題您的一千萬存起來了。
實(shí)際過程中,一般都使用一個內(nèi)存服務(wù)器來進(jìn)行存儲,有就直接取,沒有就往其他數(shù)據(jù)源去請求。這個內(nèi)存服務(wù)器即起到了緩沖的作用,也起到了緩存的作用。
智能引用代理(Smart Reference Proxy)
嘛現(xiàn)在大家能想到的都是這類了。就是在動作的之前之后再做一些動作。比如吃飯這個事情,我不管,我就是要有人幫我記錄一下吃飯時間,幫我洗手,幫我試一下菜是不是有毒。(行行行你是皇帝)飯后我不管,也要有人幫我記錄吃飯時間,幫我擦嘴幫我洗手幫我刷牙。
按實(shí)現(xiàn)方式來說,有這么幾種(前方高能我要開始貼大片代碼了):
(1)?聚合
(2) 繼承
(3)?JDK動態(tài)代理
(4)?CGLIB動態(tài)代理
假設(shè)我們定義了Loan這么一個接口,實(shí)現(xiàn)了LoanCenter這么一個貸款中心。
public interfaceLoan {
voidloan(Integer loan);
}
public classLoanCenterimplementsLoan{
public voidloan(Integer loan) {
Printer.println("loan "+loan+" is handled");
}
}
為了各種原因,要怎么對這個貸款中心設(shè)置代理呢?
聚合
把原始類當(dāng)成一個成員變量,去前后添油加醋。
public classAggregationLoanProxyextendsLoanCenter{
privateLoanloanCenter;
AggregationLoanProxy(Loan loan){
this.loanCenter= loan;
}
public voidloan(Integer loan) {
Printer.println("Aggregation loan start");
loanCenter.loan(loan);
Printer.println("Aggregation loan end");
}
}
繼承
寫一個子類去繼承LoanCenter,添油加醋,然后調(diào)用super方法。
public classInheritLoanProxyextendsLoanCenter{
@Override
public voidloan(Integer loan) {
Printer.println("inherit loan start");
super.loan(loan);
Printer.println("inherit loan start");
}
}
JDK動態(tài)代理
JDK利用反射生成一個子類,添油加醋完去調(diào)用接口中的方法。
public classJDKProxy {
public staticObject getProxy(finalObject target){
returnProxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),newInvocationHandler() {
publicObject invoke(Object proxy, Method method, Object[] args)throwsThrowable {
Printer.println("jdk loan start");
Object result = method.invoke(target,args);
Printer.println("jdk loan end");
returnresult;
}
});
}
}
CGLIB動態(tài)代理
CGLib利用反射生成一個子類,添油加醋完去調(diào)用子類中的目標(biāo)方法。
public classCGLibProxyimplementsMethodInterceptor {
privateObjecttarget;
publicObject intercept(Object o, Method method, Object[] args, MethodProxy methodProxy)throwsThrowable {
Printer.println("cglib loan start");
Object result = methodProxy.invokeSuper(o , args);
Printer.println("cglib loan end");
returnresult;
}
publicObject getInstance(Object target) {
this.target= target;
Enhancer enhancer =newEnhancer();
enhancer.setSuperclass(this.target.getClass());
// 回調(diào)方法
enhancer.setCallback(this);
// 創(chuàng)建代理對象
returnenhancer.create();
}
}
JDK動態(tài)代理和CGLib動態(tài)代理都是動態(tài)生成子類的方式去進(jìn)行代理。
什么?你問我JDK和CGLib有什么差別?JDK動態(tài)代理只能基于接口,而CGLib是基于方法,所以CGLib的普適性比較高。但是CGLib的開銷比JDK動態(tài)代理高,性能較差。
還有問題?Spring里面的AOP用的哪個?兩個都有使用到,Spring見機(jī)行事按需調(diào)用。
有小伙伴想知道JDK動態(tài)代理和CGLib更深層次的原理嗎?私聊我啊萬一我下次說說看呢。
哥我錯了,您分享一下可好