設計模式-代理模式(Proxy)
阿新 • • 發佈:2018-11-24
代理模式(Proxy)
- 定義 : 為其他物件提供一種代理, 以控制對這個物件的訪問
- 代理物件在客戶端和目標物件之間起到中介的作用
- 型別 : 結構型
適用場景
- 保護目標物件
- 增強目標物件
優點
- 代理模式能將代理物件與真實被呼叫的目標物件分離
- 一定程度上降低了系統的耦合度, 擴充套件性好
- 保護目標物件
- 增強目標物件
缺點
- 造成系統設計中類的數目增加
- 在客戶端和目標物件之間增加了一個代理物件, 會造成一定的效能下降
- 增加了系統的複雜度
擴充套件
- 靜態代理
- 動態代理 : 只能代理實現了介面的類
- CGLib代理 : 通過繼承實現的, 所以要注意final關鍵字
Spring代理選擇
-
當Bean中有實現介面時, Spring就會用JDK的動態代理
-
當Bean中沒有實現介面時, Spring使用CGLib
-
也可以強制使用CGLib, 增加如下配置即可:
<aop : aspectj-autoproxy proxy-target-class="true"/>
模式角色
-
Proxy :
- 儲存一個引用使得代理可以訪問實體。若 RealSubject和Subject的介面相同,Proxy會
引用Subject。 - 提供一個與Subject的介面相同的介面,這樣代理就可以用來替代實體。
- 控制對實體的存取,並可能負責建立和刪除它。
- 控制對實體的存取,並可能負責建立和刪除它。
- 儲存一個引用使得代理可以訪問實體。若 RealSubject和Subject的介面相同,Proxy會
-
Subject : 定義RealSubject 和Proxy 的共用介面,這樣就在任何使用 RealSubject的地方都可以使
用Proxy。 -
RealSubject : 定義Proxy所代表的實體
程式碼實現
靜態代理
UML類圖:
對應各模組程式碼:
/**
* @author 七夜雪
* @create 2018-11-24 9:31
*/
public interface Subject {
public void showName();
}
/**
* 被代理類
*
* @author 七夜雪
* @create 2018-11-24 9:30
*/
public class RealSubject implements Subject {
@Override
public void showName() {
System.out.println("被代理類方法---");
}
}
/**
* 代理類
*
* @author 七夜雪
* @create 2018-11-24 9:32
*/
public class Proxy implements Subject {
private RealSubject realSubject = new RealSubject();
@Override
public void showName() {
System.out.println("被代理類方法執行之前執行...");
realSubject.showName();
System.out.println("被代理類方法執行之後執行...");
}
}
測試類 :
/**
* 測試類
*
* @author 七夜雪
* @create 2018-11-24 9:34
*/
public class Client {
public static void main(String[] args) {
Subject subject = new Proxy();
subject.showName();
}
}
測試結果 :
被代理類方法執行之前執行...
被代理類方法---
被代理類方法執行之後執行...
動態代理
這裡就以JDK的動態代理為例, 要實現JDK的動態代理, 就需要實現InvocationHandler介面, 下面是具體程式碼實現:
動態代理類 :
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 動態代理
*
* @author 七夜雪
* @create 2018-11-24 9:55
*/
public class DynamicProxy implements InvocationHandler {
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
public Object bind(){
Class cls = target.getClass();
return Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
beforeMethod();
Object invoke = method.invoke(target, args);
afterMethod();
return invoke;
}
private void beforeMethod(){
System.out.println("動態代理 before code");
}
private void afterMethod(){
System.out.println("動態代理 after code");
}
}
Subject介面 :
/**
* @author 七夜雪
* @create 2018-11-24 9:31
*/
public interface Subject {
public void showName();
}
Subject介面的兩個實現類, 即被代理的類 :
/**
* 被代理類
*
* @author 七夜雪
* @create 2018-11-24 9:30
*/
public class RealSubject1 implements Subject {
@Override
public void showName() {
System.out.println("被代理類方法1---");
}
}
/**
* 被代理類
*
* @author 七夜雪
* @create 2018-11-24 9:30
*/
public class RealSubject1 implements Subject {
@Override
public void showName() {
System.out.println("被代理類方法2---");
}
}
測試程式碼 :
/**
* 測試類
*
* @author 七夜雪
* @create 2018-11-24 9:34
*/
public class Client {
public static void main(String[] args) {
Subject proxy1 = (Subject) new DynamicProxy(new RealSubject1()).bind();
Subject proxy2 = (Subject) new DynamicProxy(new RealSubject2()).bind();
proxy1.showName();
proxy2.showName();
}
}
測試結果 :
動態代理 before code
被代理類方法1---
動態代理 after code
動態代理 before code
被代理類方法2---
動態代理 after code
本文參考:
慕課網<java設計模式精講 Debug 方式+記憶體分析>課程
四人幫<設計模式>