為一個物件提供一個替身
,以控制對這個物件的存取。即通過代理物件存取目標物件.
使用者端直接使用的都是代理物件
,並不知道真實物件是誰,此時代理物件可以在使用者端和真實物件之間起到中介作用
.
(1) 中介作用:代理物件可以在使用者端和目標物件之間起到中介的作用,這樣起到了中介的作用和保護了目標物件的作用。
(2) 職責清晰作用: 可以使真實角色的操作更加純粹,不用去關注一些公共的業務。公共也就交給代理角色,實現了業務的分工。
靜態代理在使用時,需要定義介面或者父類別[抽象角色],被代理物件[真實角色]與代理物件[代理角色]一起實現相同的介面或者是繼承相同父類別。
(1) 通過介面聚合的方式,維護一個目標物件
(2) 通過構造器,對目標物件進行初始化
//代理物件,靜態代理
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("提交。。。。。");//方法
}
}
優點
在不修改目標物件的功能前提下, 能通過代理物件對目標功能擴充套件
缺點
■ 靜態代理:(經歷了
編譯
和執行)
在程式執行前就已經存在代理類的位元組碼檔案
(因為通過了編譯階段),代理物件和真實物件的關係在執行前就確定了
(因為通過了編譯階段)。■ 動態代理:(
只經歷了執行
,咱通過某種手段(例如反射等)得到的位元組碼【遵循位元組碼格式和結構】)動態代理類是在程式執行期間由jvm通過反射等機制動態生成的,所以
不存在代理類的位元組碼檔案
(因為沒有經歷編譯階段),代理物件和真實物件的關係是在程式執行期間才確定的
。
動態代理包括:jdk代理和cglib代理
目標物件是否需要實現介面,jdk需要,cglib不需要。jdk代理的代理物件是利用反射機制動態生成,而cglib的代理物件是利用攔截機制動態生成。
代理類所在包:java.lang.reflect.Proxy
JDK實現代理只需要使用newProxyInstance方法,但是該方法需要接收三個引數,
完整的寫法是: static Object newProxyInstance(ClassLoader loader, Class[] interfaces,InvocationHandler h )
//1. ClassLoader loader: 指定當前目標物件使用的類載入器, 獲取載入器的方法固定
//2. Class<?>[] interfaces: 目標物件實現的介面型別,使用泛型方法確認型別
//3. InvocationHandler h: 事情處理,執行目標物件的方法時,會觸發事情處理器方法, 會把當前執行的目標物件方法作為引數傳
//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: 目標物件實現的介面型別,使用泛型方法確認型別
//3. InvocationHandler h : 事情處理,執行目標物件的方法時,會觸發事情處理器方法, 會把當前執行的目標物件方法作為引數傳入
*/
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;
}
});
}
}
動態代理包括:jdk代理和cglib代理
目標物件是否需要實現介面,jdk需要,cglib不需要。jdk代理的代理物件是利用反射機制動態生成,而cglib的代理物件是利用攔截機制動態生成。
Cglib代理也叫作子類代理,它是在記憶體中構建一個子類物件從而實現對目標物件功能擴充套件。
(1) 目標物件需要實現介面,用JDK代理
(2) 目標物件不需要實現介面,用Cglib代理
public class ProxyFactory implements MethodInterceptor {
//維護一個目標物件
private Object target;
//構造器,傳入一個被代理的物件
public ProxyFactory(Object target) {
this.target = target;
}
//返回一個代理物件: 是 target 物件的代理物件
public Object getProxyInstance() {
//1. 建立一個工具類
Enhancer enhancer = new Enhancer();
//2. 設定父類別
enhancer.setSuperclass(target.getClass());
//3. 設定回撥函數
enhancer.setCallback(this);
//4. 建立子類物件,即代理物件
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;
}
}
(1) 防火牆代理: 內網通過代理穿透防火牆,實現對公網的存取。
(2) 快取代理: 比如當請求圖片檔案等資源時,先到快取代理取,如果取到資源則ok,如果取不到資源,再到公網或者資料庫取,然後快取。
(3) 遠端代理: 遠端物件的本地代表,通過它可以把遠端物件當本地物件來呼叫。遠端代理通過網路和 真正的遠端物件溝通訊息。
(4) 同步代理:主要使用在多執行緒程式設計中,完成多執行緒間同步工作。
參考內容來源:《尚矽谷Java設計模式(圖解+框架原始碼剖析)》 https://www.bilibili.com/video/BV1G4411c7N4
如果本文對你有幫助的話記得給一樂點個贊哦,感謝!
本文來自部落格園,作者:一樂樂,轉載請註明原文連結:https://www.cnblogs.com/shan333/p/16356600.html