目录
代理类在程序运行时创建代理类的方式叫做动态代理。动态代理的代理类并不是由代码所定义的,而是由系统的运行时动态生成的。
在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须使用。
1、InvocationHandler接口和Proxy类
InvocationHandler
java.lang.reflect Interface InvocationHandler
InvocationHandler接口中只有一个方法:
public object invoke(Object obj,Method method,Object[] args)
三个参数:
Object obj:指代理对象
Method method:被代理的方法。文档中描述:所述方法对应于调用代理实例上的接口方法的实例。 方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。(即代理类的接口所实现的方法)
Object[] args:方法的参数。
Proxy
java.lang.reflect.Proxy
Proxy类的主要作用就是用来动态的创建代理类,其包含许多方法,其中最常用的方法为newProxyInstance()方法:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
三个参数的含义如下:
ClassLoader loader:被代理类的类加载器 (被代理类实例.getClass().getClassLoader())
Class[] interfaces:被代理类所实现的接口 (被代理类实例.getClass().getInterfaces())
InvocationHandler h:实现InvocationHandler的类实例
newProxyInstance()方法,返回一个代理类的实例,可以将其转换为被代理类的接口类型,该接口将方法调用分派给指定的调用处理程序。
2、动态代理的实现
其具体实现步骤如下:
1.创建被代理的类和接口
2.创建一个接口实现InvocationHandler的类,且它必须实现invoke()方法
3.通过Proxy的静态方法newProxyInstance来创建代理类的对象
4.通过代理类的对象来调用方法
1、创建被代理类的接口
public interface Moveable {
void move();
}
2、创建被代理类
public class Car implements Moveable{
@Override
public void move() {
System.out.println("汽车行驶中。。。");
}
}
3、创建一个接口实现InvocationHandler的类,且它必须实现invoke()方法
public class InvocationHandlerImpl implements InvocationHandler {
//要代理的类的对象
private Object object;
//构造方法,把被代理类的对象传递进来
public InvocationHandlerImpl(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//当代理对象,调用被代理对象的方法时,会自动跳转到代理对象关联的handler对象的invoke方法来进行调用
Long startTime = System.currentTimeMillis();
System.out.println("汽车开始行驶...");
method.invoke(object,args);
Long endTime = System.currentTimeMillis();
System.out.println("汽车行驶结束,使用时间为"+(endTime - startTime));
return null;
}
}
4、编写测试类,在测试类中通过Proxy的静态方法newProxyInstance来创建代理类的对象,并且通过代理类来调用方法。
public class Test {
public static void main(String[] args) {
//创建被代理类
Moveable car = new Car();
//把被代理类,传入
InvocationHandlerImpl handler =new InvocationHandlerImpl(car);
/*
* 通过Proxy的newProxyInstance方法来创建代理对象
* 第一个参数 car.getClass().getClassLoader()
* 第二个参数car.getClass().getInterfaces(),我们这里为代理对象提供的接口是被代理类所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
* 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
*/
Moveable proxyCar = (Moveable) Proxy.newProxyInstance(car.getClass().getClassLoader(),
car.getClass().getInterfaces(), handler);
//
proxyCar.move();
}
}
输出结果为:
汽车开始行驶...
汽车行驶中。。。
汽车行驶结束,使用时间为0
注意:
为什么我们这里可以将Proxy.newProxyInstance()转化为代理类的对象?
原因就是在newProxyInstance这个方法的第二个参数上,我们给这个代理对象提供了一组什么接口,那么我这个代理对象就会实现了这组接口,这个时候我们当然可以将这个代理对象强制类型转化为这组接口中的任意一个。
通过 Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,并且命名方式都是这样的形式,以$开头,proxy为中,最后一个数字表示对象的标号。
System.out.println(proxyCar.getClass().getName());
输出:
com.sun.proxy.$Proxy0