JDK動態代理示例
阿新 • • 發佈:2019-01-25
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()內部,在代理上呼叫方法時需要格外小心,因為對介面的呼叫將被重定向為對代理的呼叫。