栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

动态代理的原理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

动态代理的原理

动态代理:在运行时再创建代理类和其实例。

举个栗子:

//抽象角色 
interface Biz {
    void print(String s);
}
//真实角色 
public class BizImpl implements Biz{

    @Override
    public void print(String s) {
        System.out.println("真实实现:" + s);
    }
}
public class Test {

    public static void main(String[] args){

        BizImpl bizImpl = new BizImpl();

        //动态代理
        //第一个参数:类加载器
        //第二个参数:想代理的接口类
        //第三个参数:InvocationHandler是一个接口,会监听到Object o调用了print()方法,并把                   
        //print()方法传递到invoke中,所以调用print()方法就会执行invoke()方法,args是print()对 
        //应的参数
        Object o = Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[]{Biz.class},

                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        return method.invoke(bizImpl, args);
                    }
                });

        Biz biz = (Biz)o;
        biz.print("through proxy");
    }

}

运行后得到打印:

真实实现:through proxy

调用o.print会调用invoke方法是因为newProxyInstance()方法会在内存中创建一个Class对象(具体方法在Proxy内部类的ProxyClassFactory里面),我们可以仿照它创建一个Class对象方便我们分析。我们在工程中新建一个module,类型选择java library(因为ProxyGenerator在sun.misc包下),命名为lib, 代码如下:

public class Test2 {

    public static void main(String[] args){
        String name = Biz.class.getName() + "$Proxy0";
        //生成代理指定接口的Class数据
        byte[] bytes = ProxyGenerator.generateProxyClass(name, new Class[]{Biz.class});
        FileOutputStream fos;

        try {
            fos = new FileOutputStream("lib/" + name + ".class");
            fos.write(bytes);
            fos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

运行后会在lib模块下生成类文件:Biz$Proxy0.class,代码如下:

public final class Biz$Proxy0 extends Proxy implements Biz {
    private static Method m1;
    private static Method m2;
    private static Method m0;
    private static Method m3;

    public Biz$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 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);
        }
    }

    public final void print(String var1) throws  {
        try {
            super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m3 = Class.forName("com.enzo.lib.Biz").getMethod("print", Class.forName("java.lang.String"));
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

通过41-49行代码我们看到:调用print()方法会调用 super.h.invoke(this, m3, new Object[]{var1}),这里的super.h就是InvocationHandler接口,实际就是一个监听回调,这就是调用o.print会调用invoke方法的原因。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/591004.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号