原文链接:
注:文章中用常用的流程实现 动态代理,流程逻辑比较清晰。文章后面对 “为什么要使用接口” 原理分析还未细看。
jdk的动态代理为什么用接口,内部是什么原理呢?看了几篇文章貌似都没讲的清楚明白,因此来解释一下。
先通过一个简单例子实现功能:
1 //接口 2 public interface SayService { 3 4 void say(String name); 5 } 6 //实现类 7 public class SayServiceImpl implements SayService{ 8 9 @Override10 public void say(String name) {11 System.out.println(name);12 }13 }
然后再自定义一个增强类, 实现InvocationHandler接口:
1 import java.lang.reflect.InvocationHandler; 2 import java.lang.reflect.Method; 3 4 public class WavingInvocationHandler implements InvocationHandler{ 5 6 private Object target; 7 8 public void setTarget(Object target) { 9 this.target = target;10 }11 12 @Override13 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {14 System.out.println("方法执行之前!");15 Object obj = method.invoke(target, args);16 System.out.println("方法执行之后!");17 return obj;18 }19 }
编写测试方法:
1 import sun.misc.ProxyGenerator; 2 3 import java.io.File; 4 import java.io.FileNotFoundException; 5 import java.io.FileOutputStream; 6 import java.io.IOException; 7 import java.lang.reflect.Proxy; 8 9 public class Test {10 11 public static void main(String[] args) {12 13 //接口14 SayService sayService = new SayServiceImpl();15 //织入类16 WavingInvocationHandler handler = new WavingInvocationHandler();17 handler.setTarget(sayService);18 //代理类--增强的对象19 SayService s = (SayService) Proxy.newProxyInstance(20 sayService.getClass().getClassLoader(),21 sayService.getClass().getInterfaces(), handler);22 23 s.say("say()");//执行代理对象完成业务24 /**25 方法执行之前!26 say()27 方法执行之后!28 */29 30 //将jdk中生成代理类输出到本地.Class文件,之后可以通过反编译软件打开查看31 createProxyClassFile("test12345",sayService.getClass().getInterfaces());32 33 }34 35 private static void createProxyClassFile(String name,Class [] interfaces){36 byte[] data = ProxyGenerator.generateProxyClass(name,interfaces);//该方法为jdk中生成代理类的核心方法37 FileOutputStream out =null;38 try {39 out = new FileOutputStream(name+".class");40 System.out.println((new File(name)).getAbsolutePath());41 out.write(data);42 } catch (FileNotFoundException e) {43 e.printStackTrace();44 } catch (IOException e) {45 e.printStackTrace();46 }finally {47 if(null!=out) try {48 out.close();49 } catch (IOException e) {50 e.printStackTrace();51 }52 }53 }54 55 }
好奇心强的小伙伴一定看过newProxyInstance方法看过了,里面的getProxyClass方法创建代理类:
1 /*2 * Look up or generate the designated proxy class.3 */4 Class cl = getProxyClass0(loader, intfs);
具体是里面的哪个方法生成的,小伙伴们不用找半天了,慢慢debug后会发现,就是上面提到的
1 ProxyGenerator.generateProxyClass()
通过该方法生成的代理类如下:通过反编译查看源码,一看便知接口的作用
JDK的动态代理是靠多态和反射来实现的,它生成的代理类需要实现你传入的接口,并通过反射来得到接口的方法对象(下文中的m3),并将此方法对象传参给增强类(上文中的WavingInvocationHandler类)的invoke方法去执行,从而实现了代理功能,故接口是jdk动态代理的核心实现方式,没有它就无法通过反射找到方法,所以这也是必须有接口的原因。不知道大家明白否
1 public final class test12345 extends Proxy implements SayService { 2 //1、该类实现你传入的接口并实现方法 3 // 2、通过构造方法传入你定义的增强类对象 4 // 3、通过反射该接口,得到接口里的Method对象并传参给增强类,然后执行Invoke实现功能 5 private static Method m1; 6 private static Method m2; 7 private static Method m3; 8 private static Method m0; 9 10 public test12345(InvocationHandler paramInvocationHandler) {11 super(paramInvocationHandler);//2.此处的super指向Proxy中的构造方法并赋值(下文的h就是此处的增强类对象),12 }13 14 //略去无关的hashcode和equals方法15 public final void say(String paramString) {16 try {17 this.h.invoke(this, m3, new Object[]{paramString});//3.此处的h就是InvocationHandler对象,invoke就是你增强类里的方法,传入接口的方法和参数并执行你增强类里的invoke方法,即完成了整个操作!18 } catch (Error | RuntimeException localError) {19 throw localError;20 } catch (Throwable localThrowable) {21 throw new UndeclaredThrowableException(localThrowable);22 }23 }24 25 static { //1.静态代码块给属性赋值,初始化接口中的方法对象(主要是下面的m3)26 try {27 m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});28 m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);29 m3 = Class.forName("com.chenrui.core.jdk.SayService").getMethod("say", new Class[]{Class.forName("java.lang.String")});30 m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);31 } catch (NoSuchMethodException localNoSuchMethodException) {32 throw new NoSuchMethodError(localNoSuchMethodException.getMessage());33 } catch (ClassNotFoundException localClassNotFoundException) {34 throw new NoClassDefFoundError(localClassNotFoundException.getMessage());35 }36 }37 }
--------------------- 作者:锐锐 来源:CSDN 原文:https://blog.csdn.net/ray890206/article/details/70146029 版权声明:本文为博主原创文章,转载请附上博文链接!