Java 靜態代理、動態代理的使用

原文:Java 動態代理。簡單修改。

靜態代理

創建一個接口,然後創建被代理的類實現該接口並且實現該接口中的抽象方法。之後再創建一個代理類,同時使其也實現這個接口。在代理類中持有一個被代理對象的引用,而後在代理類方法中調用該對象的方法。

接口:

public interface HelloInterface {
    void sayHello();
}

被代理類:

public class Hello implements HelloInterface{
    @Override
    public void sayHello() {
        System.out.println("Hello zhanghao!");
    }
}

代理類:

public class HelloProxy implements HelloInterface{
    private HelloInterface helloInterface = null;
    public HelloInterface(HelloInterface o) {
        helloInterface = o;
    }
    @Override
    public void sayHello() {
        System.out.println("Before invoke sayHello" );
        helloInterface.sayHello();
        System.out.println("After invoke sayHello");
    }
}

代理類調用:

被代理類被傳遞給了代理類 HelloProxy,代理類在執行具體方法時通過所持用的被代理類完成調用。

public static void main(String[] args) {
    HelloProxy helloProxy = new HelloProxy(new Hello());
    helloProxy.sayHello();
}
Before invoke sayHello
Hello zhanghao!
After invoke sayHello

使用靜態代理很容易就完成了對一個類的代理操作。但是靜態代理的缺點也暴露了出來:由於代理只能爲一個類服務,如果需要代理的類很多,那麼就需要編寫大量的代理類,比較繁瑣。

動態代理

利用反射機制在運行時創建代理類。

接口、被代理類不變,我們構建一個 handler 類來實現 InvocationHandler 接口。

public class ProxyHandler implements InvocationHandler{
    private Object object;
    public ProxyHandler(Object object){
        this.object = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before invoke "  + method.getName());
        method.invoke(object, args);
        System.out.println("After invoke " + method.getName());
        return null;
    }
}

使用動態代理:

public static void main(String[] args) {
    HelloInterface hello = new Hello();

    InvocationHandler handler = new ProxyHandler(hello);

    HelloInterface proxyHello = (HelloInterface) Proxy.newProxyInstance(
        hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), handler);

    proxyHello.sayHello();
}
Before invoke sayHello
Hello zhanghao!
After invoke sayHello

通過 Proxy 類的靜態方法 newProxyInstance 返回一個接口的代理實例。針對不同的代理類,傳入相應的代理程序控制器 InvocationHandler。

如果新來一個被代理類 Bye,如:

public interface ByeInterface {
    void sayBye();
}
public class Bye implements ByeInterface {
    @Override
    public void sayBye() {
        System.out.println("Bye zhanghao!");
    }
}

那麼執行過程:

public static void main(String[] args) {
    HelloInterface hello = new Hello();
    ByeInterface bye = new Bye();

    InvocationHandler handler = new ProxyHandler(hello);
    InvocationHandler handler1 = new ProxyHandler(bye);

    HelloInterface proxyHello = (HelloInterface) Proxy.newProxyInstance(
        hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), handler);

    ByeInterface proxyBye = (ByeInterface) Proxy.newProxyInstance(
        bye.getClass().getClassLoader(), bye.getClass().getInterfaces(), handler1);
    
    proxyHello.sayHello();
    proxyBye.sayBye();
}
Before invoke sayHello
Hello zhanghao!
After invoke sayHello
Before invoke sayBye
Bye zhanghao!
After invoke sayBye

對於 Hello 和 Bye,能夠使用同一個代理處理器 ProxyHandler 實現代理,是因爲不會直接告訴 ProxyHandler 所代理的類實現了哪些接口,也就是說 ProxyHandler 不依賴於指定接口,這意味着它對被代理類實現了哪些接口一無所知,也不能直接調用某個接口實現類中的方法實現,所以要有一個 Proxy 類,來告知 ProxyHandler 被代理類實現了哪些接口,並間接調用 ProxyHandler 中的代理方法,因爲 Proxy 本身也不知道被代理類實現了哪些接口,所以需要在構造函數中傳入 object.getClass().getInterfaces() 的結果。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章