1. 程式人生 > 其它 >設計模式之代理模式(靜態代理和JDK動態代理)

設計模式之代理模式(靜態代理和JDK動態代理)

技術標籤:設計模式java設計模式

一、什麼是代理

代理模式定義

為其他物件提供一種代理以控制對這個物件的訪問。代理物件起到中介作用,可去掉功能服務或增加額外的服務。

常見的代理模式

遠端代理:為不同地理的物件提供區域網待辦物件,通過遠端代理可以監控各個店鋪使之能直觀的瞭解店內資訊。

虛擬代理:根據需要將資源消耗很多的物件進行延遲,真正需要的時候進行建立。

智慧引用代理又分為靜態代理和動態代理兩種。下面重點介紹一些靜態代理和動態代理。

二、靜態代理

1.靜態代理:代理和被代理物件在代理之前是確定的,他們都實現相同的介面或者繼承相同的抽象類。具體的UML關係圖如下所示:

2.靜態代理的實現。現在模擬汽車在行駛過程中的示例。在汽車行駛前後增加“汽車開始行駛”和“汽車結束行駛”的日誌,並在最後統計輸出汽車行駛的時間。

Moveable介面

public interface Moveable {
    void move();
}

在這裡Car類是實現了Moveable介面的被代理類

public class Car implements Moveable {
    @Override
    public void move() {


        // 實現開車
        try {
            Thread.sleep(new Random().nextInt(1000));
            System.out.println("汽車行駛中...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


    }
}
CarTimeProxy類是代理物件
public class CarTimeProxy implements Moveable {

    private Moveable m;
    public CarTimeProxy(Moveable m){
        super();
        this.m = m;
    }
    @Override
    public void move() {
        long startTime = System.currentTimeMillis();
        System.out.println("汽車開始行駛....");
        m.move();
        long endTime = System.currentTimeMillis();
        System.out.println("汽車結束行駛...汽車行駛時間:"+(endTime-startTime)+"ms!");
    }
}

測試類:

public class Client {

    /**
     * 測試類
     * @param args
     */
    public static void main(String[] args) {
        Car car = new Car();
        CarTimeProxy ctp = new CarTimeProxy(car);
        ctp.move();

    }
}

三、動態代理

動態代理:動態產生代理,實現對不同類,不同方法的代理。

動態代理的實現方式有兩種,一種是JDK動態代理,另外一種是CGLIB動態代理。

JDK動態代理和CGLIB動態代理區別

JDK動態代理

1.只能代理實現了介面的類

2.沒有實現介面的類不能實現JDK的動態代理

CGLIB動態代理

1.針對類來實現代理的

2.對指定目標類產生一個子類,通過方法攔截技術攔截所有父類方法的呼叫。

在這裡重點介紹以下JDK的動態代理。

JDK動態代理類位於java.lang.reflect包下,一般主要涉及到以下兩個類:

(1)Interface InvocationHandler:該介面中僅定義了一個方法

public object invoke(Object obj,Method method,Object[] args)在實際使用時,第一個引數obj一般是指代理類,method是被代理的方法,args為該方法的引數陣列。這個抽象方法在代理類中動態實現。

(2)Proxy:該類即為動態代理類

static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h):返回代理類的一個例項,返回後的代理類可以當作被代理類使用(可使用被代理類的在介面中宣告過的方法)

所謂Dynamic Proxy是這樣一種class:它是在執行時生成的class,該class需要實現一組interface,使用動態代理,必須實現InvocationHandler介面。

動態代理步驟
1.建立一個實現介面InvocationHandler的類,它必須實現invoke方法
2.建立被代理的類以及介面
3.通過Proxy的靜態方法,建立一個代理類
newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)
4.通過代理呼叫方法

具體程式碼實現:

1、需要動態代理的介面:複用上面的Moveable介面

2.需要代理的物件:複用上面的Car類

3.建立一個實現了InvocatHandler的類

public class TimeHandler implements InvocationHandler {

    private Object target;
    public TimeHandler(Object object){
        this.target = object;

    }

    /**
     *
     * @param proxy 被代理物件
     * @param method 被代理物件方法
     * @param args 方法的引數
     * @return 返回值
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long startTime = System.currentTimeMillis();
        System.out.println("汽車開始行駛....");
        method.invoke(target);
        long endTime = System.currentTimeMillis();
        System.out.println("汽車結束行駛...\n汽車行駛時間:"+(endTime-startTime)+"ms");
        return  null;
    }
}

4.客戶端測試類,通過Proxy的newProxyInstance方法,生成代理物件。

public class Client {

    public static void main(String[] args) {
        Car car = new Car();
        InvocationHandler handler = new TimeHandler(car);
        Class<? extends Car> cls = car.getClass();
        Moveable moveable = (Moveable) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),handler);
        moveable.move();

    }
}

在這裡多說一下,Java的JDK動態代理,也是Spring的AOP的實現原理。