JDK version: 1.8
动态代理中所说的“动态”, 是针对使用Java代码实际编写了代理类的“静态”代理而言的, 它的优势不在于省去了编写代理类那一点编码工作量,
而是实现了可以在原始类和接口还未知的时候, 就确定代理类的代理行为,当代理类与原始类脱离直接联系后, 就可以很灵活地重用于不同的应用场景之中。
- 目前Java开发包中包含了对动态代理的支持, 但是其实现只支持对接口的的实现。其实现主要通过 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口。
- Proxy 类主要用来获取动态代理对象, InvocationHandler 接口用来约束调用者实现。
- 动态代理是很多框架和技术的基础, spring 的 AOP 实现就是基于动态代理实现的。
Proxy类
Proxy 提供用于创建动态代理类实例的静态方法, 它还是与之创建的所有动态代理类的超类。
介绍一下 Proxy 类中最常用的方法 java.lang.reflect.Proxy#newProxyInstance,
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { ... return cons.newInstance(new Object[]{h}); ... }
该方法返回动态代理类实例. 该方法有三个参数
- loader: the class loader to define the proxy class. 与原始类的类加载器一致
- interfaces: the list of interfaces for the proxy class to implement. 原始类实现的接口
- h: InvocationHandler 实例, 动态代理类实例会调用 InvocationHandler 实例的 invoke 方法
InvocationHandler接口
InvocationHandler 接口中只有一个方法.
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
该方法有三个参数
- proxy: 动态代理类的实例
- method: 原始类的 Method 实例
- args: 被代理 Method 需要的参数
下面通过编写一个简单地动态代理类举例说明:
1 public class DomainProxyTest { 2 3 interface IGreet { 4 5 void sayHello(); 6 7 void sayHi(); 8 } 9 10 static class Greet implements IGreet { 11 12 @Override 13 public void sayHello() { 14 System.out.println("Hello World!"); 15 } 16 17 @Override 18 public void sayHi() { 19 System.out.println("Hi there!"); 20 } 21 } 22 23 static class DynamicProxy implements java.lang.reflect.InvocationHandler { 24 25 Object originalObj; 26 27 Object bind(Object originalObj) { 28 this.originalObj = originalObj; 29 return java.lang.reflect.Proxy 30 .newProxyInstance(originalObj.getClass().getClassLoader(), originalObj.getClass().getInterfaces(), this); 31 } 32 33 @Override 34 public Object invoke(Object proxy, java.lang.reflect.Method method, Object[] args) throws Throwable { 35 System.out.println("welcome!"); 36 return method.invoke(originalObj, args); 37 } 38 } 39 40 public static void main(String[] args) { 41 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); 42 IGreet greet = (IGreet) new DynamicProxy().bind(new Greet()); 43 greet.sayHello(); 44 greet.sayHi(); 45 } 46 }
编译 Java 文件:
javac DomainProxyTest.java
执行 class 文件:
发现生成了一个名称为 $Proxy0.class 的文件, 该文件就是 Java 动态生成的代理类. 反编译看一下其内容:
import DomainProxyTest.IGreet; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; final class $Proxy0 extends Proxy implements IGreet { private static Method m1; private static Method m3; private static Method m4; private static Method m2; private static Method m0; public $Proxy0(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final void sayHello() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final void sayHi() throws { try { super.h.invoke(this, m4, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode() throws { try { return (Integer)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m3 = Class.forName("DomainProxyTest$IGreet").getMethod("sayHello"); m4 = Class.forName("DomainProxyTest$IGreet").getMethod("sayHi"); m2 = Class.forName("java.lang.Object").getMethod("toString"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
代码逻辑很简单, 呼应了文章上面对动态代理的描述.
点击链接加入QQ群: 282575808【互联网技术交流群】:https://jq.qq.com/?_wv=1027&k=Iw86cqY6