更新時(shí)間:2022-04-20 10:43:05 來(lái)源:動(dòng)力節(jié)點(diǎn) 瀏覽892次
代理模式是一種結(jié)構(gòu)類型的設(shè)計(jì)模式,它提供了另一種方式是通過(guò)代理訪問(wèn)目標(biāo)對(duì)象的對(duì)象。
這樣做的優(yōu)點(diǎn)是:實(shí)現(xiàn)目標(biāo)對(duì)象的基礎(chǔ)上,額外的功能操作可以提高,也就是說(shuō),目標(biāo)對(duì)象可以擴(kuò)展的功能。
這里使用一個(gè)想法在編程:不要修改代碼或別人寫的方法。如果你需要修改它,您可以擴(kuò)展代理的方法。
代理模型有三個(gè)角色:
真正的主題:真正的類,也就是說(shuō),代理類和委托類。用來(lái)真正完整的業(yè)務(wù)服務(wù)功能;
代理:代理類實(shí)現(xiàn)自己的請(qǐng)求的函數(shù)對(duì)應(yīng)于真正的主題,和代理類對(duì)象并沒(méi)有真正實(shí)現(xiàn)其業(yè)務(wù)功能;
主題:定義RealSubject和代理的角色應(yīng)該實(shí)現(xiàn)的接口。
有三種類型的代理模式,靜態(tài)代理,動(dòng)態(tài)代理(JDK代理、接口代理),Cglib代理(子類創(chuàng)建的目標(biāo)對(duì)象是動(dòng)態(tài)內(nèi)存)
靜態(tài)代理首先需要定義接口,代理對(duì)象和代理對(duì)象實(shí)現(xiàn)相同的接口,然后調(diào)用目標(biāo)對(duì)象的方法通過(guò)調(diào)用相同的方法。
可以看到,代理類只不過(guò)是添加一些操作調(diào)用委托類方法之前和之后。主要類的差異也會(huì)導(dǎo)致不同的代理類。
某公司生產(chǎn)電視機(jī),需要找一個(gè)代理在當(dāng)?shù)氐匿N售。當(dāng)客戶需要買電視,他可以直接通過(guò)代理購(gòu)買。
代碼示例:
電視:
public class TV {
private String name;//名稱
private String address;//生產(chǎn)地
public TV(String name, String address) {
this.name = name;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "TV{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
'}';
}
}
創(chuàng)建公司的接口:
public interface TVCompany {
/**
* 生產(chǎn)電視機(jī)
* @return 電視機(jī)
*/
public TV produceTV();
}
公司的工廠生產(chǎn)電視機(jī):
public class TVFactory implements TVCompany {
@Override
public TV produceTV() {
System.out.println("TV factory produce TV...");
return new TV("小米電視機(jī)","合肥");
}
}
代理地方訂單的貨物(靜態(tài)代理類型):
public class TVProxy implements TVCompany{
private TVCompany tvCompany;
public TVProxy(){
}
@Override
public TV produceTV() {
System.out.println("TV proxy get order .... ");
System.out.println("TV proxy start produce .... ");
if(Objects.isNull(tvCompany)){
System.out.println("machine proxy find factory .... ");
tvCompany = new TVFactory();
}
return tvCompany.produceTV();
}
}
消費(fèi)者獲得商品通過(guò)代理(代理)的使用:
public class TVConsumer {
public static void main(String[] args) {
TVProxy tvProxy = new TVProxy();
TV tv = tvProxy.produceTV();
System.out.println(tv);
}
}
輸出結(jié)果:
TV proxy get order ....
TV proxy start produce ....
machine proxy find factory ....
TV factory produce TV...
TV{name='小米電視機(jī)', address='合肥'}
Process finished with exit code 0
優(yōu)點(diǎn):靜態(tài)代理模式實(shí)現(xiàn)的功能擴(kuò)張目標(biāo)對(duì)象不改變目標(biāo)對(duì)象。
缺點(diǎn):靜態(tài)代理實(shí)現(xiàn)所有目標(biāo)對(duì)象的方法。一旦方法被添加到目標(biāo)接口,代理對(duì)象和目標(biāo)對(duì)象必須做出相應(yīng)調(diào)整,從而增加維護(hù)成本。
如何解決靜態(tài)代理的缺點(diǎn)嗎?答案是,您可以使用動(dòng)態(tài)代理
動(dòng)態(tài)代理有以下特點(diǎn):
JDK動(dòng)態(tài)代理對(duì)象不需要實(shí)現(xiàn)接口,只有目標(biāo)對(duì)象需要實(shí)現(xiàn)的接口。
實(shí)現(xiàn)動(dòng)態(tài)代理基于接口,您需要使用JDK動(dòng)態(tài)構(gòu)建的API在JVM內(nèi)存代理對(duì)象。
需要使用數(shù)組。代理,其newProxyInstance方法,但這種方法需要接收三個(gè)參數(shù)。
注意,這個(gè)方法在代理類是一個(gè)靜態(tài)方法,和接收三個(gè)參數(shù):
類加載器加載程序:指定當(dāng)前目標(biāo)對(duì)象使用類加載器,并獲得的方法加載程序是固定的。
類< ?>[]接口:接口實(shí)現(xiàn)的目標(biāo)對(duì)象的類型,和通用方法用于確定類型。
InvocationHandler h:事件處理,執(zhí)行目標(biāo)對(duì)象的方法時(shí),會(huì)觸發(fā)事件處理程序的方法,目前執(zhí)行的目標(biāo)對(duì)象的方法將會(huì)作為一個(gè)參數(shù)傳遞。
一天,公司業(yè)務(wù)增加,越來(lái)越多的產(chǎn)品銷售,并需要更多的售后。但該公司發(fā)現(xiàn),原來(lái)的代理必須重新訓(xùn)練完成的所有業(yè)務(wù),所以它發(fā)現(xiàn)另一個(gè)動(dòng)態(tài)無(wú)縫連接劑B劑B承諾所有的公司的業(yè)務(wù),無(wú)論如何添加新業(yè)務(wù),它可以完成沒(méi)有額外的培訓(xùn)。
代碼示例:
public interface TVCompany {
/**
* 生產(chǎn)電視機(jī)
* @return 電視機(jī)
*/
public TV produceTV();
/**
* 維修電視機(jī)
* @param tv 電視機(jī)
* @return 電視機(jī)
*/
public TV repair(TV tv);
}
工廠也開(kāi)始維護(hù)業(yè)務(wù):
public class TVFactory implements TVCompany {
@Override
public TV produceTV() {
System.out.println("TV factory produce TV...");
return new TV("小米電視機(jī)","合肥");
}
@Override
public TV repair(TV tv) {
System.out.println("tv is repair finished...");
return new TV("小米電視機(jī)","合肥");
}
}
B代理全面代理公司的業(yè)務(wù)。使用代理。newProxyInstance方法生成一個(gè)代理對(duì)象在調(diào)用方法,實(shí)現(xiàn)InvocationHandler反映在代理類的方法調(diào)用通過(guò)調(diào)用方法,并提供一個(gè)增強(qiáng)的方法。
public class TVProxyFactory {
private Object target;
public TVProxyFactory(Object o){
this.target = o;
}
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("TV proxy find factory for tv.... ");
Object invoke = method.invoke(target, args);
return invoke;
}
});
}
}
購(gòu)買和修理這兩個(gè)服務(wù)B代理可以直接完成。如果公司提高其業(yè)務(wù)后,代理B可以做同樣的事情。
public class TVConsumer {
public static void main(String[] args) {
TVCompany target = new TVFactory();
TVCompany tvCompany = (TVCompany) new TVProxyFactory(target).getProxy();
TV tv = tvCompany.produceTV();
tvCompany.repair(tv);
}
}
輸出結(jié)果:
TV proxy find factory for tv....
TV factory produce TV...
TV proxy find factory for tv....
tv is repair finished...
Process finished with exit code 0
代理對(duì)象不需要實(shí)現(xiàn)該接口,但目標(biāo)對(duì)象必須實(shí)現(xiàn)的接口,否則不能使用動(dòng)態(tài)代理。
動(dòng)態(tài)代理模式,所有函數(shù)調(diào)用最終會(huì)由調(diào)用函數(shù),所以我們可以做一些操作,如日志系統(tǒng)、交易,攔截,權(quán)限控制,等等。
JDK動(dòng)態(tài)代理的最致命的問(wèn)題之一是,它只能代理實(shí)現(xiàn)類實(shí)現(xiàn)一個(gè)接口,代理和代理類只能實(shí)現(xiàn)接口的方法。如果實(shí)現(xiàn)類都有自己的私有方法,但接口不如果是這樣的話,這個(gè)方法不能用于代理調(diào)用。
解決這個(gè)問(wèn)題?我們可以使用CGLIB動(dòng)態(tài)代理機(jī)制。
靜態(tài)代理和JDK代理需要一個(gè)對(duì)象來(lái)實(shí)現(xiàn)一個(gè)接口。有時(shí)只是一個(gè)單一對(duì)象的代理對(duì)象。在這種情況下,可以使用Cglib代理。
Cglib代理代理,可以被稱為子類構(gòu)造一個(gè)子類對(duì)象在內(nèi)存中實(shí)現(xiàn)擴(kuò)張目標(biāo)對(duì)象的函數(shù)。
劑C不僅想為公司行為,但也想從多個(gè)產(chǎn)品的工廠。
Cglib增強(qiáng)器生成一個(gè)代理類,通過(guò)實(shí)現(xiàn)MethodInterceptor接口,并在截距法實(shí)現(xiàn)的,在這個(gè)過(guò)程中可以添加增強(qiáng)方法和可以使用反射方法或MethodProxy繼承類調(diào)用原方法。
看到B進(jìn)行各種業(yè)務(wù)(接口)的公司,那么這個(gè)時(shí)候代理C發(fā)現(xiàn)了新的商機(jī)。B只能代表一個(gè)特定的公司的產(chǎn)品,我不僅要代表公司的產(chǎn)品,此外,它與不同的工廠,有廣泛的渠道獲得商品,更自由地賺錢。所以使用Cglib。
代碼示例:
public class TVProxyCglib implements MethodInterceptor {
//給目標(biāo)對(duì)象創(chuàng)建一個(gè)代理對(duì)象
public Object getProxyInstance(Class c){
//1.工具類
Enhancer enhancer = new Enhancer();
//2.設(shè)置父類
enhancer.setSuperclass(c);
//3.設(shè)置回調(diào)函數(shù)
enhancer.setCallback(this);
//4.創(chuàng)建子類(代理對(duì)象)
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("TVProxyFactory enhancement.....");
Object object = methodProxy.invokeSuper(o, objects);
return object;
}
}
新代理的工廠
public class TVFactoryB {
public TV produceTVB() {
System.out.println("tv factory B producing tv.... ");
return new TV("華為電視機(jī)", "南京");
}
public TV repairB(TV tv) {
System.out.println("tv B is repair finished.... ");
return tv;
}
}
C代理可以直接與該公司合作,或處理工廠。和可以代理任何工廠的產(chǎn)品。
public class TVConsumer {
public static void main(String[] args) {
TVCompany tvCompany = (TVCompany) new TVProxyCglib().getProxyInstance(TVFactory.class);
TV tv = tvCompany.produceTV();
tvCompany.repair(tv);
System.out.println("==============================");
TVFactoryB tvFactoryB = (TVFactoryB) new TVProxyCglib().getProxyInstance(TVFactoryB.class);
TV tv = tvFactoryB.produceTVB();
tvFactoryB.repairB(tv);
}
}
輸出結(jié)果:
TVProxyFactory enhancement.....
TV factory produce TV...
TVProxyFactory enhancement.....
tv is repair finished...
==============================
TVProxyFactory enhancement.....
tv factory B producing tv....
TVProxyFactory enhancement.....
tv B is repair finished....
Process finished with exit code 0
有兩種實(shí)現(xiàn)AOP在Spring,JDK和Cglib,如下所示:
如果目標(biāo)對(duì)象需要實(shí)現(xiàn)一個(gè)接口,使用JDK代理。
如果目標(biāo)對(duì)象不需要實(shí)現(xiàn)的接口,使用Cglib代理。
靜態(tài)代理代理類與目標(biāo)類需要實(shí)現(xiàn)接口方法,以便代理可以增強(qiáng)其功能。
JDK動(dòng)態(tài)代理:需要一個(gè)代理類實(shí)現(xiàn)一個(gè)接口,使用代理。newProxyInstance生成代理類方法和實(shí)現(xiàn)InvocationHandler調(diào)用方式來(lái)達(dá)到增強(qiáng)功能。
Cglib動(dòng)態(tài)代理:代理類實(shí)現(xiàn)接口不使用Cblib增強(qiáng)器生成子代理對(duì)象類和實(shí)現(xiàn)MethodInterceptor攔截方法,這種方法可以達(dá)到增強(qiáng)功能。
0基礎(chǔ) 0學(xué)費(fèi) 15天面授
有基礎(chǔ) 直達(dá)就業(yè)
業(yè)余時(shí)間 高薪轉(zhuǎn)行
工作1~3年,加薪神器
工作3~5年,晉升架構(gòu)
提交申請(qǐng)后,顧問(wèn)老師會(huì)電話與您溝通安排學(xué)習(xí)
初級(jí) 202925
初級(jí) 203221
初級(jí) 202629
初級(jí) 203743