所谓动态代理,就是提供一个接口给Proxy类,Proxy类会在运行时自己实现该接口,然后返回该接口的实例,之后对该接口方法的调用都会传给一个处理类处理。它实际上动态实现了该接口,但在方法的实现中,会将该方法传递给了处理器(handler)的处理函数(invoke)。
和动态代理相关的类
Proxy
提供了静态方法创建动态代理类(dynamic proxy class)和实例(instance),也是所有被该类方法创建的动态代理类的父类。
调用getInvocationHandler方法可得到调用处理器( invocation handler),getProxyClass可得到动态代理类的Class对象,newProxyInstance可以创建代理实例(proxy instance)。
InvocationHandler
调用处理器要实现的接口,代理实例被调用的方法会传入该接口的invoke方法中。
相关名词
动态代理类(dynamic proxy class):运行时动态创建的类,实现了传入的接口,可通过Proxy.getProxyClass获得。
代理实例:动态代理类的对象,可由Proxy.newProxyInstance获得。
调用处理器(invocation handler):实现了InvocationHandler的类,动态代理调用的方法都会被出给该类处理。
代码
下面给出具体代码,该代码可以代理任意一个类, 然后计算每个方法被调用所花的时间。
public class App
{
public static void main(String[] arg) {
//创建代理对象,传入Map接口
Map<String,String> mapProxyInstance=(Map)Proxy.newProxyInstance(App.class.getClassLoader(),new Class[] {Map.class},
new TimingDynamicInvocationHandler(new HashMap<>()));
//调用接口Map的方法
mapProxyInstance.put("hello", "world");
System.out.println(mapProxyInstance.get("hello"));
System.out.println(mapProxyInstance instanceof Proxy);
}
/**
* 处理类的实现
* @author Administrator
*
*/
static class TimingDynamicInvocationHandler implements InvocationHandler {
//用于存放target的方法名和Method类的信息。
private final Map<String, Method> methods = new HashMap<>();
//被代理的对象,也就是真实对象(real object)
private Object target;
/**
* 传入被代理的对象,将它的所有方法名都记录下来
* @param target 真实对象
*/
public TimingDynamicInvocationHandler(Object target) {
this.target = target;
for(Method method: target.getClass().getDeclaredMethods()) {
this.methods.put(method.getName(), method);
}
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//对每一次方法的调用都记录所用时长
long start = System.nanoTime();
//通过被调用方法的方法名获取Method对象,然后调用真实对象的方法
Object result = methods.get(method.getName()).invoke(target, args);
long elapsed = System.nanoTime() - start;
System.out.println("excecuting "+method.getName()+":"+elapsed+"ns");
return result;
}
}
}
输出:
excecuting put:179980ns
excecuting get:8430ns
world
true
参考:
https://www.baeldung.com/java-dynamic-proxies
http://tutorials.jenkov.com/java-reflection/dynamic-proxies.html
https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Proxy.html