1. 程式人生 > >JDK動態代理示例

JDK動態代理示例

Java動態代理可以動態地建立代理並動態地處理對所代理方法的呼叫。

下面用《Java程式設計思想》中的一個例子說明:
首先是介面類,目標類要實現的介面:

public interface Interface {
    void doSomething();
    void somethingElse(String args);
}

再就是目標類,也可以成為真實類,繼承上面的介面並實現其中的方法:

public class RealObject implements Interface {

    @Override
    public void doSomething() {
        System.out.println("I am doing something..."
); } @Override public void somethingElse(String args) { System.out.println("doing something else"); } }

再就是建立一個代理物件,代理物件持有一個Object型別的引用(這說明可以代理任意型別的目標類?),代理物件的建構函式有一個Object型別的引數,用來初始化持有的引用。並且有一個主要的invoke方法。
代理類程式碼如下:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public
class DynamicProxyHandler implements InvocationHandler{ private Object proxied; public DynamicProxyHandler(Object proxied){ this.proxied = proxied; } public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{ System.out.println("**** proxy:" + proxy.getClass() + ", method:"
+ method + ", args:" + args); if(method.getName().equals("doSomething")){ System.out.println("detected the doSomething method!"); } if(args!=null){ for(Object obj:args){ System.out.print(obj+" "); } } return method.invoke(proxied,args); } }

最後是測試類,為目標類動態生成一個代理,並傳遞個消費者(要使用這個類的物件)。程式碼如下:

import java.lang.reflect.Proxy;

public class SimpleDynamicProxy {
    public static void consumer(Interface iface){
        iface.doSomething();
        iface.somethingElse("bonobo");
    }

    public static void main(String[] args){
        RealObject real = new RealObject();
        consumer(real);

        Interface proxy = (Interface) Proxy.newProxyInstance(Interface.class.getClassLoader(),
                new Class[]{Interface.class},
                new DynamicProxyHandler(real));

        consumer(proxy);
    }
}

輸出為:

I am doing something...
doing something else
**** proxy:class $Proxy0, method:public abstract void proxy.Interface.doSomething(), args:null
detected the doSomething method!
I am doing something...
**** proxy:class $Proxy0, method:public abstract void proxy.Interface.somethingElse(java.lang.String), args:[Ljava.lang.Object;@13785d3
bonobo doing something else

通過呼叫靜態方法Proxy.newProxyInstance()可以建立動態代理,這個方法需要一個類載入器,通常可以從已經被載入的物件中獲取其載入器,然後傳遞給它;還需要一個你希望該代理實現的介面列表;以及InvocationHandler介面的一個實現。
invoke方法中傳遞進來了代理物件,以防你需要區分請求的來源,但是在許多情況下,你並不關心這一點。然而在invoke()內部,在代理上呼叫方法時需要格外小心,因為對介面的呼叫將被重定向為對代理的呼叫。