代理模式應該都不陌生。
Java通過反射機制,提供了代理模式的實現。其使用到的核心類如下:InvocationHandler接口 Proxy類
先看示例:
接口:
public interface MyInterface {
void method();
}
接口實現類:
public class MyInterfaceImpl implements MyInterface {
public void method() {
System.out.println("method");
}
}
代理類:public class MyProxy implements InvocationHandler {
Object obj;
public ProxyClass(Object o) {
obj = o;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
try {
System.out.println("before the method is called ");
result = method.invoke(obj, args);
} catch (Exception e) {
} finally {
System.out.println("after the method is called");
}
return result;
}
}
調用類:
public class Main {
public static void main(String[] argv) throws Exception {
MyInterface myintf = (MyInterface) Proxy.newProxyInstance( 1
MyInterface.class.getClassLoader(),
new Class[] { MyInterface.class }, new MyProxy( 2
new MyInterfaceImpl()));
System.out.println(myintf instanceof Proxy);
myintf.method();
}
}
需要關注的是代理類的實現。自JDK1.3之後,每一個代理的實例會有一個InvocationHandler對應。當代理實例的方法被調用的時候,改方法將會被編譯並且發送到對應的InvocationHandler的invoke方法上。
這裏需要注意兩處代碼:
1. new ProxyClass(new MyInterfaceImpl()) 對應MyProxy中的 result = method.invoke(obj, args); 該處很簡單,就是對實際方法的調用執行。
2.Proxy.newProxyInstance
先看參數:1.ClassLoader loader 代理類的加載體 2. Class<?>[] interfaces 代理類的繼承接口。3 InvocationHandler h 上面的MyProxy
代理類的集成接口,這裏有多個的原因,是因爲一個類可能會實現多個接口。
接下來:
Class cl = getProxyClass(loader, interfaces);
通過loader和interfaces創建代理類。具體方法如下:
try {
interfaceClass = Class.forName(interfaceName, false, loader);
} catch (ClassNotFoundException e) {
}
Proxy.class
接下來進行緩存處理:
synchronized (loaderToCache) {
cache = (Map) loaderToCache.get(loader);
if (cache == null) {
cache = new HashMap();
loaderToCache.put(loader, cache);
}
最後,返回已經創建的接口。當創建好這個接口之後,JDK所作的是 Constructor cons = cl.getConstructor(constructorParams); 而這個constructorParams是什麼,這個constructorParams就是InvocationHandler.class 就是說所有Proxy的實現方法的接口。
在這裏,便得到了Constructor 然後再通過newInstance去得到這個代理的實類。
在這裏應該比較明白了,所謂的代理,在1處創建的是Proxy的對象,而這個Object繼承的接口則是MyInterface,當然了,運行方法還是爲定義的method,只不過是,創建代理的時候,就已經將method包裝,實際上執行的只不過爲invoke中的方法罷了。