代理,就是需要代理類和被代理類有相同的對外接口或者說成服務,所以代理類一般都必須實現了所有被代理類已實現的接口,因爲接口就是制定了一系列對外服務的標準。
正因爲動態代理有這樣靈活的特性,所以我們在設計動態代理類(DynamicProxy)時不用顯式地讓它實現與真實主題類(RealSubject)相同的接口(interface),而是把這種實現推遲到運行時。
爲了能讓DynamicProxy類能夠在運行時纔去實現RealSubject類已實現的一系列接口並執行接口中相關的方法操作,需要讓DynamicProxy類實現JDK自帶的java.lang.reflect.InvocationHandler接口,該接口中的invoke()方法能夠讓DynamicProxy實例在運行時調用被代理類的“對外服務”,即調用被代理類需要對外實現的所有接口中的方法,也就是完成對真實方法的調用,Java幫助文檔中稱這些真實方法爲處理程序。
我們肯定必須先把被代理類RealSubject已實現的所有interface都加載到JVM中,不然JVM怎麼能夠找到這些方法呢?明白了這個道理,那麼我們就可以創建一個被代理類的實例,獲得該實例的類加載器ClassLoader。
所謂的類加載器ClassLoader,就是具有某個類的類定義,即類的內部相關結構(包括繼承樹、方法區等等)
動態代理模式可以使得我們在不改變原來已有的代碼結構的情況下,對原來的“真實方法”進行擴展、增強其功能,並且可以達到控制被代理對象的行爲的目的。DynamicProxy類必須實現的invoke()方法在調用被代理類的真實方法的前後都可進行一定的特殊操作。這是動態代理最明顯的優點
爲了解決某些問題,比如,不允許直接訪問某些類;對訪問要做特殊處理等。或者,要對原方法進行統一的擴展,出現了動態代理需求
類圖
JDK動態代理中包含一個類和一個接口:
InvocationHandler接口:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
參數說明:
Object proxy:指被代理的對象。
Method method:要調用的方法
Object[] args:方法調用時所需要的參數
可以將InvocationHandler接口的子類想象成一個代理的最終操作類
接口中聲明的所有方法都被轉移到一個集中的方法中處理(invoke)
動態代理類只能代理接口,代理類都需要實現InvocationHandler類,實現invoke方法。該invoke方法就是調用被代理接口的所有方法時需要調用的,該invoke方法返回的值是被代理接口的一個實現類
主題接口
public interface ISubject {
void doSomething();
}
真實對象
public class RealSubject implements ISubject {
@Override
public void doSomething() {
System.out.println("+++RealSubject+++");
}
}
handler
public class SubHandler implements InvocationHandler {
private Object obj;// 持有真實對象
public SubHandler(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = method.invoke(obj, args);// 真實對象來執行具體的方法
System.out.println("dy proxy ");//加入自己操作
return result;
}
}
使用
public class Test {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
ISubject sub = (ISubject) Proxy.newProxyInstance(realSubject.getClass()
.getClassLoader(), realSubject.getClass().getInterfaces(),
new SubHandler(realSubject));
sub.doSomething();
}
}
//output
+++RealSubject+++
dy proxy