先看看静态代理是如何操作的
定义接口:
1 public interface Person { 2 public void sayHello(String content, int age); 3 public void sayGoodBye(boolean seeAgin, double time); 4 }
实际的类:
1 public class Student implements Person{ 2 3 @Override 4 public void sayHello(String content, int age) { 5 // TODO Auto-generated method stub 6 System.out.println("student say hello" + content + " "+ age); 7 } 8 9 @Override 10 public void sayGoodBye(boolean seeAgin, double time) { 11 // TODO Auto-generated method stub 12 System.out.println("student sayGoodBye " + time + " "+ seeAgin); 13 }
14 }
代理类:
1 public class ProxyTest implements Person{ 2 3 private Person o; 4 5 public ProxyTest(Person o){ 6 this.o = o; 7 } 8 9 @Override 10 public void sayHello(String content, int age) { 11 // TODO Auto-generated method stub 12 System.out.println("ProxyTest sayHello begin"); 13 //在代理类的方法中 间接访问被代理对象的方法 14 o.sayHello(content, age); 15 System.out.println("ProxyTest sayHello end"); 16 } 17 18 @Override 19 public void sayGoodBye(boolean seeAgin, double time) { 20 // TODO Auto-generated method stub 21 System.out.println("ProxyTest sayHello begin"); 22 //在代理类的方法中 间接访问被代理对象的方法 23 o.sayGoodBye(seeAgin, time); 24 System.out.println("ProxyTest sayHello end"); 25 } 26 27 public static void main(String[] args) { 28 // TODO Auto-generated method stub 29 //s为被代理的对象,某些情况下 我们不希望修改已有的代码,我们采用代理来间接访问 30 Student s = new Student(); 31 //创建代理类对象 32 ProxyTest proxy = new ProxyTest(s); 33 //调用代理类对象的方法 34 proxy.sayHello("welcome to java", 20); 35 System.out.println("******"); 36 //调用代理类对象的方法 37 proxy.sayGoodBye(true, 100); 38 39 } 40 41 }
可以看到,静态代理类要求实现与实际类型相同的接口,这个虽然在某些情况下有使用场景,但是其实扩展起来很麻烦,需要一个个的进行重载,相比之下,动态代理就好多了。
动态代理也需要一个代理类,实现特定的接口InvocationHandler:
1 public class MyInvocationHandler implements InvocationHandler{ 2 3 private Object object; 4 5 public MyInvocationHandler(Object object){ 6 this.object = object; 7 } 8 9 @Override 10 public Object invoke(Object proxy, Method method, Object[] args) 11 throws Throwable { 12 // TODO Auto-generated method stub 13 System.out.println("MyInvocationHandler invoke begin"); 14 System.out.println("proxy: "+ proxy.getClass().getName()); 15 System.out.println("method: "+ method.getName()); 16 for(Object o : args){ 17 System.out.println("arg: "+ o); 18 } 19 //通过反射调用 被代理类的方法 20 method.invoke(object, args); 21 System.out.println("MyInvocationHandler invoke end"); 22 return null; 23 } 24 25 public static void main(String [] args){ 26 //创建需要被代理的类 27 Student s = new Student(); 28 //这一句是生成代理类的class文件,前提是你需要在工程根目录下创建com/sun/proxy目录,不然会报找不到路径的io异常 29 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true"); 30 //获得加载被代理类的 类加载器 31 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 32 //指明被代理类实现的接口 33 Class<?>[] interfaces = s.getClass().getInterfaces(); 34 // 创建被代理类的委托类,之后想要调用被代理类的方法时,都会委托给这个类的invoke(Object proxy, Method method, Object[] args)方法 35 MyInvocationHandler h = new MyInvocationHandler(s); 36 //生成代理类 37 Person proxy = (Person)Proxy.newProxyInstance(loader, interfaces, h); 38 //通过代理类调用 被代理类的方法 39 proxy.sayHello("yujie.wang", 20); 40 proxy.sayGoodBye(true, 100); 41 System.out.println("end"); 42 } 43 44 }
这个灵活性就好多了,不用关心自己代理的类到底有多少方法,只用实现一个invoke方法,去做自己想做的事情就好,如果需要根据特定的方法做事情,可能就需要根据method判断了,不如静态代理写在重载方法中感觉好。
那么,java到底是怎么实现动态代理的,不妨反编译一下,拿到的结果如下,可以看到其实是jvm帮你做了静态代理的事情:
1 public final class $Proxy0 extends Proxy implements Person{ 2 private static Method m4; 3 private static Method m1; 4 private static Method m0; 5 private static Method m3; 6 private static Method m2; 7 8 public $Proxy0(InvocationHandler paramInvocationHandler) 9 throws 10 { 11 super(paramInvocationHandler); 12 } 13 //实现了Person接口的方法,这就是我们调用这个方法Proxy.newProxyInstance必须提供第二个参数的作用 14 public final void sayGoodBye(boolean paramBoolean, double paramDouble) 15 throws 16 { 17 try 18 { 19 // 我们看到通过调用代理类的方法时,最终方法都会委托给InvocationHandler实现类的invoke方法 20 // m4为代理类通过反射获得的Method 21 this.h.invoke(this, m4, new Object[] { Boolean.valueOf(paramBoolean), Double.valueOf(paramDouble) }); 22 return; 23 } 24 catch (Error|RuntimeException localError) 25 { 26 throw localError; 27 } 28 catch (Throwable localThrowable) 29 { 30 throw new UndeclaredThrowableException(localThrowable); 31 } 32 } 33 34 public final boolean equals(Object paramObject) 35 throws 36 { 37 try 38 { 39 return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue(); 40 } 41 catch (Error|RuntimeException localError) 42 { 43 throw localError; 44 } 45 catch (Throwable localThrowable) 46 { 47 throw new UndeclaredThrowableException(localThrowable); 48 } 49 } 50 51 public final int hashCode() 52 throws 53 { 54 try 55 { 56 return ((Integer)this.h.invoke(this, m0, null)).intValue(); 57 } 58 catch (Error|RuntimeException localError) 59 { 60 throw localError; 61 } 62 catch (Throwable localThrowable) 63 { 64 throw new UndeclaredThrowableException(localThrowable); 65 } 66 } 67 //实现了Person接口的方法,这就是我们调用这个方法Proxy.newProxyInstance必须提供第二个参数的作用 68 public final void sayHello(String paramString, int paramInt) 69 throws 70 { 71 try 72 { 73 // 我们看到通过调用代理类的方法时,最终方法都会委托给InvocationHandler实现类的invoke方法 74 // m4为代理类通过反射获得的Method 75 this.h.invoke(this, m3, new Object[] { paramString, Integer.valueOf(paramInt) }); 76 return; 77 } 78 catch (Error|RuntimeException localError) 79 { 80 throw localError; 81 } 82 catch (Throwable localThrowable) 83 { 84 throw new UndeclaredThrowableException(localThrowable); 85 } 86 } 87 88 public final String toString() 89 throws 90 { 91 try 92 { 93 return (String)this.h.invoke(this, m2, null); 94 } 95 catch (Error|RuntimeException localError) 96 { 97 throw localError; 98 } 99 catch (Throwable localThrowable) 100 { 101 throw new UndeclaredThrowableException(localThrowable); 102 } 103 } 104 105 static 106 { 107 try 108 {//代理类通过反射 获得的接口方法Method 109 m4 = Class.forName("com.yujie.proxy.dynamic.Person").getMethod("sayGoodBye", new Class[] { Boolean.TYPE, Double.TYPE }); 110 m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); 111 m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); 112 //代理类通过反射 获得的接口方法Method 113 m3 = Class.forName("com.yujie.proxy.dynamic.Person").getMethod("sayHello", new Class[] { Class.forName("java.lang.String"), Integer.TYPE }); 114 m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); 115 return; 116 } 117 catch (NoSuchMethodException localNoSuchMethodException) 118 { 119 throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); 120 } 121 catch (ClassNotFoundException localClassNotFoundException) 122 { 123 throw new NoClassDefFoundError(localClassNotFoundException.getMessage()); 124 } 125 } 126 }
本文参考了https://blog.csdn.net/u011784767/article/details/78281384