资讯专栏INFORMATION COLUMN

Java 动态代理 理解

3fuyu / 3250人阅读

摘要:之后通过类的静态方法取得一个代理类实例再次鄙视自己。值得一提,动态代理把也代理了。总结动态代理优点相比静态代理,不用每代理一个类就得写一个新的代理类。缺点只能代理实现了接口的类,因为是单继承,代理类已经是类的子类了。

动态代理

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




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

源码分析


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

这时我们反编译看看,最后编译成功的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技术。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70352.html

相关文章

  • java动态代理及RPC框架介绍

    摘要:这种语法,在中被称为动态代理。在动态代理机制中,这个角色只能是接口。动态代理就是实现的技术之一。 所谓动态代理,指的是语言提供的一种语法,能够将对对象中不同方法的调用重定向到一个统一的处理函数中来。python重写__getattr__函数能够做到这一点,就连世界上最好的语言也提供称为魔术方法的__call。这种语法除了能更好的实现动态代理外,还是RPC框架实现原理的一部分。 动态代理...

    2shou 评论0 收藏0
  • 你真的完全了解Java动态代理吗?看这篇就够了

    摘要:动态地代理,可以猜测一下它的含义,在运行时动态地对某些东西代理,代理它做了其他事情。所以动态代理的内容重点就是这个。所以下一篇我们来细致了解下的到底是怎么使用动态代理的。 之前讲了《零基础带你看Spring源码——IOC控制反转》,本来打算下一篇讲讲Srping的AOP的,但是其中会涉及到Java的动态代理,所以先单独一篇来了解下Java的动态代理到底是什么,Java是怎么实现它的。 ...

    haitiancoder 评论0 收藏0
  • java动态代理理解

    摘要:动态代理能干嘛提供了另外一种实现接口的方式,不用也能实现接口。有了动态代理,中的网络交互部分可以完全写在框架中,对用户来说编程更加方便。 静态代理 public class TargetClass{ void method1() } public class ProxyClass{ private TargetClass target; public...

    IamDLY 评论0 收藏0
  • JAVA代理模式的理解和应用

    摘要:代理模式代理模式通俗一点的解释就是在操作一个对象和对象中的方法时,不是直接操作这个对象,还是通过一个代理对象来操作这个实际的目标对象。 代理模式: 代理模式通俗一点的解释就是在操作一个对象和对象中的方法时,不是直接操作这个对象,还是通过一个代理对象来操作这个实际的目标对象。应用场景一般是需要在执行某个已经写好的方法前后再添加一段逻辑,比如执行方法前打印日志,或者在执行方法之前和之后打时...

    CatalpaFlat 评论0 收藏0
  • 10分钟看懂动态代理设计模式

    摘要:动态代理是语言中非常经典的一种设计模式,也是所有设计模式中最难理解的一种。本文将通过一个简单的例子模拟动态代理实现,让你彻底明白动态代理设计模式的本质,文章中可能会涉及到一些你没有学习过的知识点或概念。 动态代理是Java语言中非常经典的一种设计模式,也是所有设计模式中最难理解的一种。本文将通过一个简单的例子模拟JDK动态代理实现,让你彻底明白动态代理设计模式的本质,文章中可能会涉及到...

    atinosun 评论0 收藏0

发表评论

0条评论

3fuyu

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<