Java 动态代理 理解

发布时间:2019-11-18 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了Java 动态代理 理解脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

动态代理

这里暂时只做JDK动态代理分析。动态代理应用广泛,例如AOP。

clipboard.png

clipboard.png
clipboard.png
clipboard.png

Java 动态代理 理解

吐槽自己一下,设计的类,接口名不是很好。。anyway,大致就是这样。根据规范,Mama类实现InvocationHandler接口,实现invoke方法。之后通过Proxy类的静态方法newPRoxyInstance取得一个代理类实例eat(再次鄙视自己)。当eat.eat()时,调用了Mama的invoke方法。
很好奇,码是如何实现代理的。值得一提,JDK动态代理把equals(),toString(),hashCode()也代理了。

源码分析

Java 动态代理 理解

Java 动态代理 理解

Java 动态代理 理解


一路debug发现,最后调用了Proxy类下内部类ProxyClassFactory的apply方法,其中包含的下列代码最终动态地创建了proxy class 文件

Java 动态代理 理解

这时我们反编译看看,最后编译成功的proxy class

public final class KidProxy extends Proxy implements Eat {     private static Method m1;     private static Method m3;     private static Method m2;     private static Method m0;      public KidProxy(InvocationHandler VAR1) throws  {         suPEr(var1);     }      public final boolean equals(Object var1) throws  {         try {             return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();         } catch (RuntimeException | Error var3) {             throw var3;         } catch (Throwable var4) {             throw new UndeclaredThrowableException(var4);         }     }      public final void eat() throws  {         try {             super.h.invoke(this, m3, (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)).intValue();         } catch (RuntimeException | Error var2) {             throw var2;         } catch (Throwable var3) {             throw new UndeclaredThrowableException(var3);         }     }      static {         try {             m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});             m3 = Class.forName("com.ProxyDemo.Eat").getMethod("eat", new Class[0]);             m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);             m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);         } catch (NoSuchMethodException var2) {             throw new NoSuchMethodError(var2.getMessage());         } catch (ClassNotFoundException var3) {             throw new NoClaSSDefFoundError(var3.getMessage());         }     } }

通过构造函数KidProxy(InvocationHandler var1)初始化类instance,这个super(var1)即是Proxy的构造函数Proxy(InvocationHandler invocationHandler)即是静态方法newProxyInstance传过去的参数。具体的调用又是在newProxyInstance方法中的最后一句

return cons.newInstance(new Object[]{h});

可知是通过反射实例化proxy对象的,同样的在构造proxy class文件时,也是通过反射,通过其实现的interfaces的具体方法将需要实现的method写入proxy class文件的。在记载class文件时,通过static构建method。

static {         try {             m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});             m3 = Class.forName("com.ProxyDemo.Eat").getMethod("eat", new Class[0]);             m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);             m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);         } catch (NoSuchMethodException var2) {             throw new NoSuchMethodError(var2.getMessage());         } catch (ClassNotFoundException var3) {             throw new NoClassDefFoundError(var3.getMessage());         }     }

其中m3就是我要代理的方法。具体调用的时候,通过将方法delegate给invocationHandler实例。

总结

JDK动态代理
优点

  • 相比静态代理,不用每代理一个类就得写一个新的代理类。
    缺点

  • 只能代理实现了interface接口的类,因为java是单继承,代理类已经是Proxy类的子类了。实现代理没有实现接口的类,还得靠ASM技

脚本宝典总结

以上是脚本宝典为你收集整理的Java 动态代理 理解全部内容,希望文章能够帮你解决Java 动态代理 理解所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。