1. 程式人生 > >代理模式學習筆記

代理模式學習筆記

1.正向代理和反向代理

ps:正向代理和反向代理都是使用在網路中。

1.1正向代理

正向代理一般是客戶端一直要訪問的目標地址,通過代理伺服器去訪問該目標地址,比如現在國內一般不能訪問外國網站那我們要訪問外國網站,怎麼辦呢?首先我們可以使用科學上網的方式,使用VPN訪問外網,而這個外網就是我們要訪問的目標伺服器,而vpn提供商就是代理伺服器,對於目標伺服器而言,他並不知到訪問自己的具體客戶端,甚至不知道訪問自己的只是一個代理伺服器。

1.2反向代理

反向代理一般是指客戶端的訪問請求通過代理伺服器去訪問,而這個代理伺服器將請求分發帶自己內網的伺服器中,而這種代理伺服器一般指負載均衡伺服器,對於客戶端而言,他並不知到自己訪問的具體伺服器是哪一個,甚至不知道自己目前訪問的只是一個代理伺服器。

兩者的差異:

兩者的代理伺服器一般都有一個快取,來提高訪問效率,而正向代理中客戶端有著明確的訪問目標,而反向代理中客戶端沒有,這就是兩者的主要的區別。

2.靜態代理VS動態代理

在某些情況下,一個客戶不想或者不能直接引用一個物件,此時可以通過一個稱之為“代理”的第三者來實現間接引用。代理物件可以在客戶端和目標物件之間起到中介的作用,並且可以通過代理物件去掉客戶不能看到的內容和服務或者新增客戶需要的額外服務。

通過引入一個新的物件來實現對真實物件的操作或者將新的物件作為真實物件的一個替身,這種實現機制即為代理模式,通過引入代理物件來間接訪問一個物件,這就是代理模式的模式動機。

1.靜態代理,靜態代理一般是指程式設計師手寫或者程式碼工具生成在編譯初期就已經已經變異好的類,而一個靜態代理類一般紙袋裡一個具體的類

2.動態代理是指程式在執行過程中並不知道自己要去代理的具體目標,只是在執行過程中動態的去代理,一般動態代理是對一個介面的不同實現類的代理,所以靜動的一個區別就是一個是基於類的代理,一個是基於介面的代理。

我們來看例子:

package study.provy;

/**
 * @Auther opprash
 * @Date 2018\8\3 0003 1:27
 */
public interface HelloSerivice {
    public void say();
}

上面的程式碼比較簡單,定義了一個介面和其實現類。這就是代理模式中的目標物件目標物件的介面。接下類定義代理物件。

package study.provy;

/**
 * @Auther opprash
 * @Date 2018\8\3 0003 1:30
 */
public class HelloSeriviceProxy implements  HelloSerivice{
    private HelloSerivice target;
    public HelloSeriviceProxy(HelloSerivice target){
        this.target=target;
    }
    @Override
    public void say(){
        System.out.println("load data");
        target.say();
        System.out.println("clear data");
    }
}

上面就是一個代理類,他也實現了目標物件的介面,並且擴充套件了say方法。下面是一個測試類:

package study.provy;

import org.junit.jupiter.api.Test;

/**
 * @Auther opprash
 * @Date 2018\8\3 0003 1:33
 */
public class helloSeriviceTest {
    @Test
    public void testProxy(){
        HelloSerivice target=new HelloSeriviceImpl();
        HelloSeriviceProxy proxy=new HelloSeriviceProxy(target);
        proxy.say();
    }
}

輸出:

load data
Hello World
clear data

這就是一個簡單的靜態的代理模式的實現。代理模式中的所有角色(代理物件、目標物件、目標物件的介面)等都是在編譯期就確定好的。

靜態代理的用途:

1.進行訪問許可權的控制:通過代理物件控制對真實物件的訪問

2.避免建立大物件:可以使用一個很小的代理類來代理要建立的大隊象,大物件在編譯初期就已經初始化好了,這樣可以減小程式對記憶體的使用

3.靜態代理新增額外的功能;在被代理類的前後增加額外的功能來補充其功能。

Java中的動態代理

前面介紹了靜態代理,雖然靜態代理模式很好用,但是靜態代理還是存在一些侷限性的,比如使用靜態代理模式需要程式設計師手寫很多程式碼,這個過程是比較浪費時間和精力的。一旦需要代理的類中方法比較多,或者需要同時代理多個物件的時候,這無疑會增加很大的複雜度。

有沒有一種方法,可以不需要程式設計師自己手寫代理類呢。這就是動態代理啦。

動態代理中的代理類並不要求在編譯期就確定,而是可以在執行期動態生成,從而實現對目標物件的代理功能。

Java中,實現動態代理有兩種方式:

JDK動態代理:java.lang.reflect 包中的Proxy類和InvocationHandler介面提供了生成動態代理類的能力。

Cglib動態代理:Cglib (Code Generation Library )是一個第三方程式碼生成類庫,執行時在記憶體中動態生成一個子類物件從而實現對目標物件功能的擴充套件。

關於這兩種動態代理的寫法本文就不深入展開了,讀者感興趣的話,後面我再寫文章單獨介紹。本文主要來簡單說一下這兩種動態代理的區別和用途。

JDK動態代理和Cglib動態代理的區別

JDK的動態代理有一個限制,就是使用動態代理的物件必須實現一個或多個介面。如果想代理沒有實現介面的類,就可以使用CGLIB實現。

Cglib是一個強大的高效能的程式碼生成包,它可以在執行期擴充套件Java類與實現Java介面。它廣泛的被許多AOP的框架使用,例如Spring AOP和dynaop,為他們提供方法的interception(攔截)。

Cglib包的底層是通過使用一個小而快的位元組碼處理框架ASM,來轉換位元組碼並生成新的類。不鼓勵直接使用ASM,因為它需要你對JVM內部結構包括class檔案的格式和指令集都很熟悉。

Cglib與動態代理最大的區別就是:

使用動態代理的物件必須實現一個或多個介面

使用cglib代理的物件則無需實現介面,達到代理類無侵入。

動態代理的用途

Java的動態代理,在日常開發中可能並不經常使用,但是並不代表他不重要。Java的動態代理的最主要的用途就是應用在各種框架中。因為使用動態代理可以很方便的執行期生成代理類,通過代理類可以做很多事情,比如AOP,比如過濾器、攔截器等。

在我們平時使用的框架中,像servlet的filter、包括spring提供的aop以及struts2的攔截器都使用了動態代理功能。我們日常看到的mybatis分頁外掛,以及日誌攔截、事務攔截、許可權攔截這些幾乎全部由動態代理的身影。