动态代理的实现是基于java的三种API的,下面先来介绍一下:
1、java.lang.reflect.Proxy
这是 Java 动态代理机制生成的所有动态代理类的父类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。
<span style="font-size:14px;">// 方法 1: 该方法用于获取指定代理对象所关联的调用处理器 static InvocationHandler getInvocationHandler(Object proxy) // 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象 static Class getProxyClass(ClassLoader loader, Class[] interfaces) // 方法 3:该方法用于判断指定类对象是否是一个动态代理类 static boolean isProxyClass(Class cl) // 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例 static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) </span>当然啦,我觉得这些方法不需要记住,只需要在用的时候去查API,多用也就容易上手啦~~
2、java.lang.reflect.InvocationHandler
这是调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。每次生成动态代理类对象时都要指定一个对应的调用处理器对象。
<span style="font-size:14px;">// 该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象 // 第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行 Object invoke(Object proxy, Method method, Object[] args) </span>3、java.lang.ClassLoader(看到java类装载器,突然想到drp的时候还提到了tomcat类装载器)
这是类装载器类,负责将类的字节码装载到 Java 虚拟机(JVM)中并为其定义类对象,然后该类才能被使用。Proxy 静态方法生成动态代理类同样需要通过类装载器来进行装载才能使用,它与普通类的唯一区别就是其字节码是由 JVM 在运行时动态生成的而非预存在于任何一个 .class 文件中。
每次生成动态代理类对象时都需要指定一个类装载器对象 。
下面用和上边相似的例子说一下:
1、 创建一个处理器,用来动态生成代理
<span style="font-size:14px;">/****************创建自己的调用处理器 *****************/ import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class TestInvocationHandler implements <span style="color:#ff0000;">InvocationHandler</span> { //代理类持有委托类的引用 private Object delegate; public TestInvocationHandler(Object delegate){ this.delegate=delegate; } /** * @param proxy:代理类实例 * @param method:被调用的方法 * @param args:参数 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long stime = System.currentTimeMillis(); //利用反射机制将请求分派给委托类处理。Method的invoke返回Object对象作为方法执行结果。 //因为示例程序没有返回值,所以这里忽略了返回值处理 method.invoke(delegate, args); long ftime = System.currentTimeMillis(); System.out.println("执行任务耗时"+(ftime - stime)+"毫秒"); return null; } } </span>2、
<span style="font-size:14px;">/*************生成动态代理对象的工厂,工厂方法列出了如何生成动态代理类对象的步骤。***************/ import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class DynamicTestFactory { public static ITest getInstance() { ITest delegate=new Test(); InvocationHandler testInvocationHandler=new TestInvocationHandler(delegate); ITest proxy = null; proxy = (ITest)Proxy.newProxyInstance(delegate.getClass().getClassLoader(),delegate.getClass().getInterfaces(),testInvocationHandler); return proxy; } } </span>3、客户端调用工厂,隐藏方法
<span style="font-size:14px;">public class DynamicClient { /** * @param args */ public static void main(String[] args) { ITest delegate=DynamicTestFactory.getInstance(); delegate.addStudent("坏学生"); } } </span>
由图可见,Proxy 类是它的父类,这个规则适用于所有由 Proxy 创建的动态代理类。而且该类还实现了其所代理的一组接口,这就是为什么它能够被安全地类型转换到其所代理的某接口的根本原因。
那动态代理有哪些优点呢?如果认真看过前面对静态代理的解释的话,我想,动态代理的优点就是避免了静态代理的缺点。
动态代理接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。
Proxy 已经设计得非常优美,但是还是有一点点小小的遗憾之处,那就是它始终无法摆脱仅支持 interface 代理的桎梏,因为它的设计注定了这个遗憾。回想一下那些动态生成的代理类的继承关系图,它们已经注定有一个共同的父类叫 Proxy。Java 的继承机制注定了这些动态代理类们无法实现对 class 的动态代理,原因是多继承在 Java 中本质上就行不通。