动态代理
动态代理类的字节码是在程序运行期间由JVM根据反射等机制动态的生成,所以==不存在代理类的class文件==。代理类和委托类的关系是在程序运行时确定。
相关的类和接口
java.lang.reflect.Proxy:
这是 Java 动态代理机制的主类,它提供了一组静态方法来==为一组接口动态地生成代理类及其对象==// 方法 1: 该方法用于获取指定代理对象所关联的调用处理器
static InvocationHandler getInvocationHandler(Object proxy)// 方法 4:该方法用于为指定类装载器、一组接口及调用处理器==生成动态代理类实例==
static Object newProxyInstance(ClassLoader loader, Class[] interfaces,
InvocationHandler h)
java.lang.reflect.InvocationHandler:
这是调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。- // 该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象
// 第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行
Object invoke(Object proxy, Method method, Object[] args)
- // 该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象
==动态代理类==与普通类的唯一区别就是其字节码是由 ==JVM 在运行时动态生成的而非预存在于任何一个 .class 文件中==。
通过类装载器来进行装载才能使用
具体实现步骤
通过实现 InvocationHandler 接口==创建自己的调用处理器==;
通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来==创建动态代理类==;
通过反射机制==获得动态代理类的构造函数==,其唯一参数类型是调用处理器接口类型;
通过构造函数==创建动态代理类实例,==构造时调用处理器对象作为参数被传入====
实际使用过程更加简单,因为 Proxy 的静态方法 newProxyInstance 已经为我们封装了步骤 2 到步骤 4 的过程,所以简化后的过程如下
// InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
InvocationHandler handler = new InvocationHandlerImpl(..);// 通过 Proxy 直接创建动态代理类实例
Interface proxy = (Interface)Proxy.newProxyInstance( classLoader,
new Class[] { Interface.class }, handler );
Java 动态代理机制的一些特点。
- 包:
如果所代理的接口都是 public 的,那么它将被定义在顶层包(即包路径为空)
如果所代理的接口中有非 public 的接口(因为接口不能被定义为 protect 或 private,所以除 public 之外就是默认的 package 访问级别),那么它将被定义在该接口所在包(假设代理了 com.ibm.developerworks 包中的某非 public 接口 A,那么新生成的代理类所在的包就是 com.ibm.developerworks),
这样设计的目的是为了最大程度的保证动态代理类不会因为包管理的问题而无法被成功定义并访问; - 类修饰符:
==该代理类具有 final 和 public 修饰符==,意味着它可以被所有的类访问,但是不能被再度继承; - 类名:
格式是“$ProxyN”,其中 N 是一个逐一递增的阿拉伯数字,代表 Proxy 类第 N 次生成的动态代理类,
值得注意的一点是,并不是每次调用 Proxy 的静态方法创建动态代理类都会使得 N 值增加,原因是如果对同一组接口(包括接口排列的顺序相同)试图重复创建动态代理类,它会很聪明地返回先前已经创建好的代理类的类对象,而不会再尝试去创建一个全新的代理类,
这样可以节省不必要的代码重复生成,提高了代理类的创建效率。 - 4)类继承关系:
该类的继承了Proxy类、实现了一组接口