一、代理模式基本介紹
1、什么是代理模式
為一個對象提供一個替身,以控制對這個對象的訪問。即通過代理對象訪問目標對象.
客戶端直接使用的都是代理對象,并不知道真實對象是誰,此時代理對象可以在客戶端和真實對象之間起到中介作用.
2、代理模式的作用
(1) 中介作用:代理對象可以在客戶端和目標對象之間起到中介的作用,這樣起到了中介的作用和保護了目標對象的作用。
(2) 職責清晰作用: 可以使真實角色的操作更加純粹,不用去關注一些公共的業(yè)務。公共也就交給代理角色,實現(xiàn)了業(yè)務的分工。
3、代理模式的組成(角色分析):
- 抽象角色: 一般使用接口或抽象類
- 真實角色: 被代理的角色[目標對象]
- 代理角色: 代理真實角色,代理真實角色后,我們一般會做一些附屬操作[代理對象]
4、代理模式分類:
- 靜態(tài)代理
- 動態(tài)代理(jdk代理、cglib代理)
二、靜態(tài)代理
1、靜態(tài)代理實現(xiàn)過程:
靜態(tài)代理在使用時,需要定義接口或者父類[抽象角色],被代理對象[真實角色]與代理對象[代理角色]一起實現(xiàn)相同的接口或者是繼承相同父類。
2、靜態(tài)代理代碼:
(1) 通過接口聚合的方式,維護一個目標對象
(2) 通過構造器,對目標對象進行初始化
//代理對象,靜態(tài)代理
public class TeacherDaoProxy implements ITeacherDao{
private ITeacherDao target; // 目標對象,通過接口來聚合
//構造器
public TeacherDaoProxy(ITeacherDao target) {
this.target = target;
}
@Override
public void teach() {
// TODO Auto-generated method stub
System.out.println("開始代理 完成某些操作。。。。。 ");//方法
target.teach();
System.out.println("提交。。。。。");//方法
}
}
3、靜態(tài)代理優(yōu)缺點:
優(yōu)點
在不修改目標對象的功能前提下, 能通過代理對象對目標功能擴展
缺點
- 因為代理對象需要與目標對象實現(xiàn)一樣的接口,所以會有很多代理類
- 一旦接口增加方法,目標對象與代理對象都要維護
4、靜態(tài)代理和動態(tài)代理的區(qū)別:
(1) 簡單說,就是代理對象是否是動態(tài)生成的,靜態(tài)代理不是,動態(tài)代理是。
(2) 詳細說,考慮代理類的字節(jié)碼的編譯運行情況,考慮在程序運行前是否就已經存在代理類的字節(jié)碼文件,靜態(tài)代理是已經存在,動態(tài)代理不是,是等到程序運行時由jvm通過反射等機制動態(tài)生成的。
■ 靜態(tài)代理:(經歷了
編譯和運行)
在程序運行前就已經存在代理類的字節(jié)碼文件(因為通過了編譯階段),代理對象和真實對象的關系在運行前就確定了(因為通過了編譯階段)。■ 動態(tài)代理:(
只經歷了運行,咱通過某種手段(例如反射等)得到的字節(jié)碼【遵循字節(jié)碼格式和結構】)動態(tài)代理類是在程序運行期間由jvm通過反射等機制動態(tài)生成的,所以
不存在代理類的字節(jié)碼文件(因為沒有經歷編譯階段),代理對象和真實對象的關系是在程序運行期間才確定的。
三、動態(tài)代理之jdk代理
動態(tài)代理包括:jdk代理和cglib代理
1、動態(tài)代理jdk 和 cglib 區(qū)別:
目標對象是否需要實現(xiàn)接口,jdk需要,cglib不需要。jdk代理的代理對象是利用反射機制動態(tài)生成,而cglib的代理對象是利用攔截機制動態(tài)生成。
2、jdk代理基本介紹
- 代理對象, 不需要實現(xiàn)接口,但是目標對象要實現(xiàn)接口,否則不能用動態(tài)代理
- 代理對象的生成,是利用JDK的API(利用反射機制),動態(tài)的在內存中構建代理對象
- JDK代理也叫做接口代理
3、JDK中生成代理對象的API
代理類所在包:java.lang.reflect.Proxy
JDK實現(xiàn)代理只需要使用newProxyInstance方法,但是該方法需要接收三個參數(shù),
完整的寫法是: static Object newProxyInstance(ClassLoader loader, Class[] interfaces,InvocationHandler h )
//1. ClassLoader loader: 指定當前目標對象使用的類加載器, 獲取加載器的方法固定
//2. Class<?>[] interfaces: 目標對象實現(xiàn)的接口類型,使用泛型方法確認類型
//3. InvocationHandler h: 事情處理,執(zhí)行目標對象的方法時,會觸發(fā)事情處理器方法, 會把當前執(zhí)行的目標對象方法作為參數(shù)傳
4、jdk代理的代碼
//jdk代理,代理工廠,生成代理對象
public class ProxyFactory {
//維護一個目標對象 , Object
private Object target;
//構造器 , 對target 進行初始化
public ProxyFactory(Object target) {
this.target = target;
}
//給目標對象 生成一個代理對象
public Object getProxyInstance() {
//說明
/*
* public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
//1. ClassLoader loader : 指定當前目標對象使用的類加載器, 獲取加載器的方法固定
//2. Class<?>[] interfaces: 目標對象實現(xiàn)的接口類型,使用泛型方法確認類型
//3. InvocationHandler h : 事情處理,執(zhí)行目標對象的方法時,會觸發(fā)事情處理器方法, 會把當前執(zhí)行的目標對象方法作為參數(shù)傳入
*/
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
System.out.println("JDK代理開始~~");
//反射機制調用目標對象的方法
Object returnVal = method.invoke(target, args);
System.out.println("JDK代理提交");
return returnVal;
}
});
}
}
四、動態(tài)代理之cglib代理
動態(tài)代理包括:jdk代理和cglib代理
1、動態(tài)代理jdk 和 cglib 區(qū)別:
目標對象是否需要實現(xiàn)接口,jdk需要,cglib不需要。jdk代理的代理對象是利用反射機制動態(tài)生成,而cglib的代理對象是利用攔截機制動態(tài)生成。
2、cglib代理基本介紹
Cglib代理也叫作子類代理,它是在內存中構建一個子類對象從而實現(xiàn)對目標對象功能擴展。
3、在AOP編程中如何選擇代理模式:
(1) 目標對象需要實現(xiàn)接口,用JDK代理
(2) 目標對象不需要實現(xiàn)接口,用Cglib代理
4、cglib 代理的代碼:
public class ProxyFactory implements MethodInterceptor {
//維護一個目標對象
private Object target;
//構造器,傳入一個被代理的對象
public ProxyFactory(Object target) {
this.target = target;
}
//返回一個代理對象: 是 target 對象的代理對象
public Object getProxyInstance() {
//1. 創(chuàng)建一個工具類
Enhancer enhancer = new Enhancer();
//2. 設置父類
enhancer.setSuperclass(target.getClass());
//3. 設置回調函數(shù)
enhancer.setCallback(this);
//4. 創(chuàng)建子類對象,即代理對象
return enhancer.create();
}
//重寫 intercept 方法,會調用目標對象的方法
@Override
public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {
// TODO Auto-generated method stub
System.out.println("Cglib代理模式 ~~ 開始");
Object returnVal = method.invoke(target, args);
System.out.println("Cglib代理模式 ~~ 提交");
return returnVal;
}
}
五、擴展---代理模式(Proxy)的變體
1、幾種常見的代理模式介紹— 幾種變體
(1) 防火墻代理: 內網通過代理穿透防火墻,實現(xiàn)對公網的訪問。
(2) 緩存代理: 比如當請求圖片文件等資源時,先到緩存代理取,如果取到資源則ok,如果取不到資源,再到公網或者數(shù)據(jù)庫取,然后緩存。
(3) 遠程代理: 遠程對象的本地代表,通過它可以把遠程對象當本地對象來調用。遠程代理通過網絡和 真正的遠程對象溝通信息。
(4) 同步代理:主要使用在多線程編程中,完成多線程間同步工作。
參考內容來源:《尚硅谷Java設計模式(圖解+框架源碼剖析)》 https://www.bilibili.com/video/BV1G4411c7N4
如果本文對你有幫助的話記得給一樂點個贊哦,感謝!