代理模式(靜態代理、動態代理)

代理模式的由來:當調用某個對象時,不關心是否準確獲得該對象,而是隻要一個能提供對應功能的對象便可,這時咱們能夠爲該對象提供一個代理對象,由代理對象控制對源對象的引用。java

第一.靜態代理數組

常見靜態代理模式:一個接口,兩個實現類,分別爲被代理類和代理類,代理類中進行以下操做便可
1.建立接口類型成員變量
2.構造方法中建立被代理類對象()
3.實現的接口方法中調用被代理類的實現的接口方法
示例代碼以下:ide

// 被代理類
class SubjectImpl implements Subject {
    @Override
    public void action() {
        System.out.println("執行action方法體");
    }
}

// 代理類
class ProxyClass implements Subject {
    private Subject subject = new SubjectImpl();

    private void beforeHandle() {
        System.out.println("業務方法執行前執行前置加強處理");
    }

    private void afterHandle() {
        System.out.println("業務方法執行後執行後置加強處理");
    }

    @Override
    public void action() {
        this.beforeHandle();
        subject.action();
        this.afterHandle();
    }

}

public class ProxyTest {
    public static void main(String[] args) {
        ProxyClass obj = new ProxyClass();
        obj.action();
    }
}

要使用被代理類對象的方法時,只需簡單的實例化代理類對象,調用此代理類對象的方法便可,實際上是方法內部調用了被代理類的方法。工具

第二.動態代理this

JDK動態代理主要用到了Proxy類和InvocationHandler接口,二者都在java.lang.reflect包下。spa

首先介紹一下Proxy類,這個類是全部動態代理類的父類,主要用到這個類的newProxyInstance()靜態方法:代理

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

這個方法直接生成一個動態代理類對象,方法須要傳三個參數,第一個參數是被代理類對應的類加載器對象,第二個參數是被代理類實現的一系列接口對應的Class對象組成的數組一個數組,第三個參數是一個InvocationHandler對象(一個InvocationHandler實現類對象)。code

InvocationHander接口就只有一個方法:對象

public Object invoke(Object proxy, Method method, Object[] args)

咱們得自定義一個InvocationHander接口實現類,重寫invoke()方法。blog

JDK動態代理代碼示例:

//接口
interface Subject {
    public void doSomething(String str);
}

// 接口實現類
class RealSubject implements Subject {
    @Override
    public void doSomething(String str) {
        System.out.println("Subject接口實現類RealSubject實現doSomething方法()");
    }
}

// InvocationHandler接口實現類
class MyIncovationHandler implements InvocationHandler {
    private Object proxied;

    // 構造器參數是被代理類對象
    public MyIncovationHandler(Object proxied) {
        this.proxied = proxied;
    }

    public MyIncovationHandler() {
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        method.invoke(proxied, args);
        after();
        return null;
    }

    // 加強處理方法,能夠抽出到一個單獨的工具類裏面
    private void before() {
        System.out.println("Before處理");
    }

    private void after() {
        System.out.println("After處理");
    }
}

public class JdkDynamicProxyTest {
    public static void main(String args[]) {
        Subject s = new RealSubject();
        Object obj = Proxy.newProxyInstance(RealSubject.class.getClassLoader(), RealSubject.class.getInterfaces(),
                new MyIncovationHandler(s));
        Subject subject = (Subject) obj;
        subject.doSomething("kou");
    }
}

     上例中,有一個RealSubject類,實現了接口Subject。InvocationHander接口的實現類MyInvocationHander,重寫了invoke方法,在方法體中調用第二個參數method的invoke方法,method的invoke方法須要兩個參數,第一個參數是被代理類的實例,第二個參數是參數列表,是invoke方法的第三個參數。這裏被代理類的實例不建議直接new出來一個實例而後傳進去,而是建議在建立InvocationHander實例時把被代理類實例傳進來,這樣比較解耦。

      編譯上Proxy.newProxyInstance()的返回值類型是Object,但其實運行時類型是動態代理類的類型($Proxy開頭的類),又由於實現了代理類所實現的所有接口,因此能夠強轉爲任意一個所實現的接口類型。這個時候調用該接口的方法,底層就會執行接口實現類對應的實現。

      Proxy的newProxyInstance()方法的第二個參數是接口對應的Class對象組成的數組,而不是被代理類的Class對象。因此說,JDK動態代理創建在接口之上的。那麼,若是被代理類沒有實現任何接口,就不能用JDK動態代理了,須要用到cglib動態代理。cglib動態代理實際上是對被代理類建立一個子類,讓這個子類去代理父類,因此要求被代理類不能是final的。

相關文章
相關標籤/搜索