設計模式之代理模式


一、代理模式基本介紹

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

  1. 代理類所在包:java.lang.reflect.Proxy

  2. 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



如果本文對你有幫助的話記得給一樂點個贊哦,感謝!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容