前言
本文将带着几个问题来看
- 到底“动态代理”动态在哪里?
- InvocationHandler为什么没有任何实现?
- 对于传入的newProxyInstance()的接口类型,是否有限制?
- 如何确认某个类 是不是代理类?
动态代理的实现
编写你要代理的interface
public interface Animal {
void say();
void jump();
}
某实现了Animal的类
public class Dog extends Animal {
public void say() {
System.out.println("I am a dog.");
}
public void jump() {
System.out.println("i jump with 4 legs");
}
}
使用InvocationHandler接口
在使用动态代理时,我们需要定义一个位于代理类与委托类之间的中介类,这个中介类被要求实现InvocationHandler接口。
/**
* 调用处理程序
*/
public interface InvocationHandler {
Object invoke(Object proxy, Method method, Object[] args);
}
这是固定模板的部分
中介类
public class DynamicProxy implements InvocationHandler {
//obj为委托类对象;
private Object obj;
public DynamicProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before");
Object result = method.invoke(obj, args);
System.out.println("after");
return result;
}
}
中介类持有一个委托类对象引用,在invoke方法中调用了委托类对象的相应方法,看到这里是不是觉得似曾相识?
通过聚合方式持有委托类对象引用,把外部对invoke的调用最终都转为对委托类对象的调用。
动态生成代理类
public class Main {
public static void main(String[] args) {
//创建中介类实例
DynamicProxy inter = new DynamicProxy(new Dog());
//获取代理类实例sell
Animal animal = (Animal)(Proxy.newProxyInstance(Animal.class.getClassLoader(), new Class[] {Animal.class}, inter));
//通过代理类对象调用代理类方法,实际上会转到invoke方法调用
animal.say();
animal.jump();
}
}
文字描述太累赘,改用这样的图来表示。
这就是动态代理了。
回到问题解答
到底“动态代理”动态在哪里?
动态代理之所以被称为动态,是因为运行时才将它的类创建出来。代码开始执行时,还没有proxy类,它是根据需要从你传入的接口集创建的。
InvocationHandler为什么没有任何实现?
InvocationHandler不是proxy,它只是一个帮助类,proxy会把调用转发给他处理。
对于传入的newProxyInstance()的接口类型,是否有限制?
有限制。
我们要传值给newProxyInstance()的一个接口数组,此数组内只能有接口,不能有类。
要考虑访问限制,如果接口不是public,就需要在一个package,不同的接口内,不可有名称和参数完全一样的方法。
如何确认某个类 是不是代理类?
通过isProxyClass可以进行判断,true则是动态代理类。
小结
动态代理模式,在不少流行的第三方框架中都有出现。
需要好好的学习一下。