• JDK动态代理源码剖析


    关键代码:

    1.Proxy.newInstance:

    private static final Class<?>[] constructorParams = { InvocationHandler.class };
    Class<?> cl = getProxyClass0(loader, intfs);
    final Constructor<?> cons = cl.getConstructor(constructorParams);
    return cons.newInstance(new Object[]{h});
    

    2.Proxy.getProxyClass0:

    // otherwise, it will create the proxy class via the ProxyClassFactory
    return proxyClassCache.get(loader, interfaces);
    

    3.WeakCache.get(由2注释可知,首次是由ProxyClassFactory生成的class对象,proxyClassCache即WeakCache):

    Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    

    可见,这里调用ProxyClassFactory的apply方法;

    4.ProxyClassFactory.apply:

    long num = nextUniqueNumber.getAndIncrement();
    String proxyName = proxyPkg + proxyClassNamePrefix + num;
    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
    return defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);
    

    这里先取一个原子整数作为序号,生成代理对象名称,com.sun.proxy.$Proxy0.class,
    然后通过ProxyGenerator.generateProxyClass获得class的字节码,然后调用native方法defineClass0创建class对象。

    由上可知,先在ProxyClassFactory的apply方法中通过ProxyGenerator.generateProxyClass得到字节码,调用defineClass0由字节码得到class对象(是个native方法),然后在Proxy.newInstance里得到这个class对象的构造器,然后反射得到代理对象实例。
    通过ProxyGenerator.generateProxyClass(Openjdk能看到该类的源码)可以生成代理对象的字节码byte[] data,然后将其写到磁盘文件(.class后缀),即可看到代理对象的class文件了:

    FileOutputStream fos = new FileOutPutStream("$Proxy0.class");
    fos.write(data);
    fos.close();
    

    使用jd反编译:

    该class继承了Proxy,实现了被代理对象的接口。构造方法传入InvocationHandler,调用super(invocationHandler);实现的被代理接口的方法里面其实是调用的invocationHandler.invoke方法(Object proxy参数传入的代理对象this)。
    

    使用动态代理:

    1)实现InvocationHandler接口(增强),并持有被代理对象实例,并在它的invoke方法里面写增强逻辑,该方法的参数是代理对象,方法和参数,在invoke合适的位置调用被代理对象的方法(使用反射的方式method.invoke(target, args));
    2)使用Proxy.newInstance创建代理对象,classloader(加载生成的动态代理类字节码为class对象)使用被代理对象的classloader即可(target.getClass.getClassLoader),interfaces使用被代理对象的接口数组(target.getClass.getInterfaces)。
    
    return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
    
  • 相关阅读:
    接口设计安全
    PHP通过OpenSSL生成证书、密钥并且加密解密数据,以及公钥,私钥和数字签名的理解
    OpenSSL使用小结
    sql的三种去重
    关于if语句&&运算符先判断空异常
    关于数据库可为null的datetime 字段
    sql server去重
    asp.net updatepanel 局部更新后调用js
    级联 -- 逻辑
    关于滑动验证的思路构思
  • 原文地址:https://www.cnblogs.com/kibana/p/10176847.html
Copyright © 2020-2023  润新知