代理模式应该都不陌生。
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中的方法罢了。