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