jdk动态代理&cglb动态代理到底生成了啥(一)

1.jdk动态代理

jdk的动态代理就是根据代理类的接口替我们动态生成实现类,先看案例:

顶层接口

public interface IPerson {
    String stduy(String name);
}


 这是被代理的类,需要对study方法进行功能增强.

public class Tom implements IPerson {
    @Override
    public String stduy(String name) {
        System.out.println(“执行原生方法”);
        return Tom.class.getName()+name;
    }
}

 Proxy.newProxyInstance()需要传三个参数,一个是类加载器,一个是被代理类的实现接口,第三个是InvocationHandler(接口)的实现类对象,这里是使用的匿名内部类的方式来写的

    public class JDKProxy {
        //需要代理的对象。这里我们使用Iperson来接收Tom对象
        private T target;
        public void setTarget(T target) {
                this.target = target;
        }

        public T getProxy(){
        Object o = Proxy.newProxyInstance(target.getClass().getClassLoader(),                target.getClass().getInterfaces(), new InvocationHandler() {
            /**
             *
             * @param proxy 生产的代理对象
             * @param method 执行的方法
             * @param args 执行的方法的入参
             * @return 返回方法执行的结果
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("方法执行前");
                //执行原有的方法
                Object invoke = method.invoke(target, args);
                System.out.println("方法执行后");
                return invoke;
            }
        });
        return (T)o;
    }
}

测试:

public class Test {
    public static void main(String[] args) {
        JDKProxy iPersonJDKProxy = new JDKProxy<>();
        //需要被代理的对象
        IPerson tom = new Tom();
        iPersonJDKProxy.setTarget(tom);
        //获取代理对象,此时这个对象就不再是上面的tom了
        IPerson proxy = iPersonJDKProxy.getProxy();
        proxy.stduy("java");
    }
}

这时候产生了一个问题,这个代理类到底是啥。其实动态代理的原理很简单.jdk就是用字符串去拼接了一个类,我们正常写代理都是在idea里面直接写,但是动态代理写代码是类似于这样的:

     StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("public class Tom implements Iperson{")
            //拼接方法和字段
        stringBuffer.append("}")  ;

然后把这个类生成到磁盘。再用classloader把这个生成的临时的class文件加载到jvm,之后这个文件就会被删除了。那有办法看到这个代理类到生成了个啥.

jdk动态代理&cglb动态代理到底生成了啥(一)_第1张图片

源码里面这一段就是就是生成jdk拼接好的类后的byte数组。我们只需要把他生成到我们想要的位置即可.这个方法参数1就是代理类 的名字,这个查看的方法就是dbug查看,参数二就是被代理类的接口,参数三不管.

jdk动态代理&cglb动态代理到底生成了啥(一)_第2张图片

 来看具体的代码实现:

public class Test  {
    public static void main(String[] args) throws Exception{
        JDKProxy iPersonJDKProxy = new JDKProxy<>();
        //需要被代理的对象
        IPerson tom = new Tom();
        iPersonJDKProxy.setTarget(tom);
        //获取代理对象,此时这个对象就不再是上面的tom了
        IPerson proxy = iPersonJDKProxy.getProxy();
        proxy.stduy("java");
        
        //代理类的字节码数组
        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                "$Proxy0", new Class[]{IPerson.class});
       FileOutputStream fileOutputStream = new FileOutputStream(""d://$Proxy0.class"");
        fileOutputStream.write(proxyClassFile);
        fileOutputStream.flush();
        fileOutputStream.close();
    }
}

运行后:

 这个类是字节码文件,咱也看不懂。直接把文件拖拽到idea.

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import jdkProxy.IPerson;

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

    public $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 stduy(String var1) throws  {
        try {
            return (String)super.h.invoke(this, m3, 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);
        }
    }

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

这个类就是字符串拼接好然后写道磁盘的一个类,这些都是jdk帮我们完成的.

看类名字:

public final class $Proxy0 extends Proxy implements IPerson

代理类实现了Iperson接口,还继承了Proxy这个类。

其中最重要的一个方法代理类会实现接口的方法:


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

(String)super.h.invoke(this, m3, new Object[]{var1});

(String):就是我们study方法的返回值,被强转了.

super:就是父类,指的就是Proxy.

h:指的就是我们前面生成了InvocationHandler的内部类的对象.

invoke:就是我们生成了InvocationHandler的内部类后,重写的那个方法.

this:就是指代理类$Proxy0的对象

m3:就是接口的方法对象.在代理类的静态代码块中

m3 = Class.forName("jdkProxy.IPerson").getMethod("stduy", Class.forName("java.lang.String"));

new Object[]{var1}:就是方法的m3方法的入参.

到此神秘的面纱就解开了。下篇继续讲解,cglb生成的代理类长啥样

你可能感兴趣的:(java,开发语言)