代理模式和 Java 動態代理

本文涉及到代理模式和 Java 反射的相關知識,如果對這兩部分不熟的話,可以閱讀作者的 代理模式Java 反射教程

代理模式

在代理模式中涉及到一個接口以及這個接口的兩個實現類。這兩個實現類,其中一個類爲代理類,另一個爲被代理的類。

一個接口

MyInterface.java

public interface MyInterface {
    void doSomething1();
    void doSomething2();
    void doSomething3();
}     

被代理的類

MyTest.java

public class MyTest implements MyInterface {
    @Override
    public void doSomething1() {
        System.out.println("doSomething1() called");
    }

    @Override
    public void doSomething2() {
        System.out.println("doSomething2() called");
    }

    @Override
    public void doSomething3() {
        System.out.println("doSomething3() called");
    }
}

代理類

ProxyTest.java

public class ProxyTest implements MyInterface {
    // 被代理對象
    private MyInterface realMyInterface;

    public ProxyTest(MyInterface realMyInterface) {
        this.realMyInterface = realMyInterface;
    }

    @Override
    public void doSomething1() {
        System.out.println("before doSomething1()");
        realMyInterface.doSomething1();
        System.out.println("after doSomething1()");
        System.out.println();


    }

    @Override
    public void doSomething2() {
        System.out.println("before doSomething2()");
        realMyInterface.doSomething2();
        System.out.println("after doSomething2()");
        System.out.println();

    }

    @Override
    public void doSomething3() {
        System.out.println("before doSomething3()");
        realMyInterface.doSomething3();
        System.out.println("after doSomething3()");
        System.out.println();

    }
}

Demo.java

public class Demo {
    public static void main(String[] args) {
        MyInterface myInterface = new MyTest();
        MyInterface proxy = new ProxyTest(myInterface);
        proxy.doSomething1();
        proxy.doSomething2();
        proxy.doSomething3();
    }
}   

輸出結果:

before doSomething1()
doSomething1() called
after doSomething1()

before doSomething2()
doSomething2() called
after doSomething2()

before doSomething3()
doSomething3() called
after doSomething3()

動態代理

在代理模式中的接口中如果有很多個方法,代理類就需要實現接口中的所有的方法,有些繁瑣。有時候我們僅會在被代理方法的前面或後面加上相同或相似的處理,但我們在代理類中仍然需要實現接口中的每一個方法。

代理模式能實現的功能,動態代理也能實現,動態代理實現起來可能還要更簡潔。
在代理模式中涉及到一個接口和該接口的兩個實現類。在動態代理中涉及到一個接口和該接口的一個實現類和一個實現了 InvocationHandler 的實現類。

一個接口。

MyInterface.java

public interface MyInterface {
    void doSomething1();
    void doSomething2();
    void doSomething3();
}     

被代理的類

MyTest.java

public class MyTest implements MyInterface {
    @Override
    public void doSomething1() {
        System.out.println("doSomething1() called");
    }

    @Override
    public void doSomething2() {
        System.out.println("doSomething2() called");
    }

    @Override
    public void doSomething3() {
        System.out.println("doSomething3() called");
    }
}  

InvocationHandler.java

public interface InvocationHandler {
    // proxy 是代理對象
    public Object invoke(Object proxy, Method method, Object[] args); 
}

MyInvocationHandler.java

public class MyInvocationHandler implements InvocationHandler {
    // 被代理的對象
    private MyInterface myInterface;
    public MyInvocationHandler(MyInterface myInterface) {
        this.myInterface = myInterface;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {
        // proxy 是代理對象,不過在 invoke 方法中好像一般不會用到它
        System.out.println("before " + method.getName() + "()");
        // 通過反射調用被代理對象的 method 
        Object returnValue = method.invoke(myInterface, args);
        System.out.println("after " + method.getName() + "()");
        System.out.println();
        return returnValue;
    }
}

Demo.java

public class Demo {
    public static void main(String[] args) {
        // 被代理的對象
        MyInterface myInterface = new MyTest();
        InvocationHandler invocationHandler = new MyInvocationHandler(myInterface);
        // 代理對象
        MyInterface myProxy = (MyInterface) Proxy.newProxyInstance(Demo.class.getClassLoader(), new Class[] {MyInterface.class}, invocationHandler);
        myProxy.doSomething1();
        myProxy.doSomething2();
        myProxy.doSomething3();

    }
}

輸出結果:

before doSomething1()
doSomething1() called
after doSomething1()

before doSomething2()
doSomething2() called
after doSomething2()

before doSomething3()
doSomething3() called
after doSomething3()

代理模式和 Java 動態代理的比較

從輸出結果來看,代理模式的輸出結果和動態代理的輸出結果是完全一樣的。

代理模式和動態代理的相同點:

  • 兩者可以實現同樣的功能換句話說用代理模式能實現的用動態代理也能實現。
  • 兩者都需要一個一個接口和該接口的一個實現類,在本例中是 MyInterface 接口和 MyTest(被代理的類)。

代理模式和動態代理的不同點:

  • 代理模式需要自己創建一個代理類,這個代理類和被代理類需要實現同一個接口。而動態代理不需要自己創建代理類,代理類是由 JVM 動態(在運行時)創建的,所以叫動態代理。
  • 動態代理中用戶需要自己創建一個實現了 InvocationHandler 接口的類。一般來說,這個 invocation handler 有一個成員變量,這個成員變量是被代理的對象,有一個只有一個參數的共有構造方法,用於在創建 invocation handler 的時候把被代理的對象傳入構造方法。
  • 代理模式中用戶需要在代理類中去實現接口中的每一個方法,在動態代理中所有的邏輯處理都放在 invocation handler 中的 invoke() 方法中,由 invoke() 方法統一處理。
  • 動態代理中代理類關聯了一個 InvocationHandler 對象,調用代理對象的某個方法時代理對象會把這個調用請求轉發給 InvocationHandler 對象由 InvocationHandler 的 invoke() 方法來統一處理。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章