美文网首页
jdk动态代理-生成的代理类的字节码

jdk动态代理-生成的代理类的字节码

作者: BenjaminCool | 来源:发表于2019-12-08 12:25 被阅读0次

    被代理的类

    package com.example.demo.jdkproxytest;
    
    /**
     * Created by PengRong on 2018/12/25.
     * 创建Person 接口 用于定义 委托类和代理类之间的约束行为
     */
    public interface Person {
        /**
         * @param name 人名
         * @param dst  工作目的地
         */
        void goWorking(String name, String dst);
    
        /**
         * 获取名称
         *
         * @return
         */
        String getName();
    
        /**
         * 设置名称
         *
         * @param name
         */
        void setName(String name);
    }
    
    

    接口实现类, 被代理类

    package com.example.demo.jdkproxytest;
    
    /**
     * Created by PengRong on 2018/12/25.
     * 动态代理委托类实现, 实现接口 Person。 被动态生成的代理类代理
     */
    public class SoftwareEngineer implements Person {
    
        private String name;
    
    
        public SoftwareEngineer() {
        }
    
        public SoftwareEngineer(String name) {
            this.name = name;
        }
    
    
        @Override
        public void goWorking(String name, String dst) {
            System.out.println("name =" + name + " , 去 " + dst + " 工作");
        }
    
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
    }
    
    
    

    InvocationHandler

    package com.example.demo.jdkproxytest;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.util.Arrays;
    
    /**
     * Created by PengRong on 2018/12/25.
     * PersonInvocationHandler 类 实现InvocationHandler接口,这个类中持有一个被代理对象(委托类)的实例target。该类别JDK Proxy类回调
     * InvocationHandler 接口中有一个invoke方法,当一个代理实例的方法被调用时,代理方法将被编码并分发到 InvocationHandler接口的invoke方法执行。
     */
    public class PersonInvocationHandler<T> implements InvocationHandler {
        /**
         * 被代理对象引用,invoke 方法里面method 需要使用这个 被代理对象
         */
        T target;
    
        public PersonInvocationHandler(T target) {
            this.target = target;
        }
    
        /**
         * 在
         *
         * @param proxy  代表动态生成的 动态代理 对象实例
         * @param method 代表被调用委托类的接口方法,和生成的代理类实例调用的接口方法是一致的,它对应的Method 实例
         * @param args   代表调用接口方法对应的Object参数数组,如果接口是无参,则为null; 对于原始数据类型返回的他的包装类型。
         * @return
         * @throws Throwable
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        /**
         * 在转调具体目标对象之前,可以执行一些功能处理
         */
            System.out.println("被动态代理类回调执行, 代理类 proxyClass =" + proxy.getClass() + " 方法名: " + method.getName() + "方法. 方法返回类型:" + method.getReturnType()
                    + " 接口方法入参数组: " + (args == null ? "null" : Arrays.toString(args)));        /**
             * 代理过程中插入监测方法,计算该方法耗时
             */
            MonitorUtil.start();
            Thread.sleep(1);        /** 调用呗代理对象的真实方法,*/
            Object result = method.invoke(target, args);
            MonitorUtil.finish(method.getName());
            return result;
        }
    }
    
    

    MonitorUtil

    
    package com.example.demo.jdkproxytest;
    
    /**
     * Created by PengRong on 2018/12/25.
     * 方法用时监控类
     */
    public class MonitorUtil {
        private static ThreadLocal<Long> tl = new ThreadLocal<>();
    
        public static void start() {
            tl.set(System.currentTimeMillis());
        }
    
        /**
         * 结束时打印耗时
         *
         * @param methodName 方法名
         */
        public static void finish(String methodName) {
            long finishTime = System.currentTimeMillis();
            System.out.println(methodName + "方法执行耗时" + (finishTime - tl.get()) + "ms");
        }
    }
    
    
    

    测试类

    package com.example.demo.jdkproxytest;
    
    
    import sun.misc.ProxyGenerator;
    
    import java.io.FileOutputStream;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import java.util.Arrays;
    import java.util.Properties;
    
    /**
     * 动态代理类测试
     * Created by PengRong on 2018/12/25.
     */
    public class JdkDynamicProxyTest {
        public static void main(String[] args) throws Exception {
            // 打开保存JDK动态代理生成的类文件
            saveGeneratedJdkProxyFiles();
    
            /**
             * 第一种方法: 通过 Proxy.newProxyInstance 方法 获取代理对象
             */
            System.out.println("-------------------第一种创建代理类方法--------------");
    
            //创建一个实例对象,这个对象是被代理的对象,委托类
            Person person = new SoftwareEngineer("Vincent");
    
            //创建一个与代理类相关联的InvocationHandler,每一个代理类都有一个关联的 InvocationHandler,并将代理类引用传递进去
            InvocationHandler Handler = new PersonInvocationHandler<>(person);
    
            //创建一个 代理对象 personProxy 来代理 person,创建的代理对象的每个执行方法都会被替换执行Invocation接口中的invoke方法
            Person personProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, Handler);
    
            /** 代理类信息 */
            System.out.println("package = " + personProxy.getClass().getPackage() + " SimpleName = " + personProxy.getClass().getSimpleName() + " name =" + personProxy.getClass().getName() + " CanonicalName = " + "" + personProxy.getClass().getCanonicalName() + " 实现的接口 Interfaces = " + Arrays.toString(personProxy.getClass().getInterfaces()) + " superClass = " + personProxy.getClass().getSuperclass() + " methods =" + Arrays.toString(personProxy.getClass().getMethods()));        // 通过 代理类 执行 委托类的代码逻辑
            personProxy.goWorking(personProxy.getName(), "深圳");
    
    
            System.out.println("-------------------第二种创建代理类方法--------------");
    
            /**
             *  动态代理对象步骤
             *      1、 创建一个与代理对象相关联的 InvocationHandler,以及真实的委托类实例
             *      2、Proxy类的getProxyClass静态方法生成一个动态代理类stuProxyClass,该类继承Proxy类,实现 Person.java接口;JDK动态代理的特点是代理类必须继承Proxy类
             *      3、通过代理类 proxyClass 获得他的带InvocationHandler 接口的构造函数 ProxyConstructor
             *      4、通过 构造函数实例 ProxyConstructor 实例化一个代理对象,并将  InvocationHandler 接口实例传递给代理类。
             */
    //        // 1、创建 InvocationHandler 实例并设置代理的目标类对象
    //        Person persontwo = new SoftwareEngineer("Vincent");
    //        InvocationHandler Handlertwo = new PersonInvocationHandler<>(persontwo);
    //
    //        // 2 创建代理类,是一个字节码文件, 把 proxyClass 保存起来就能看到 他继承Proxy 类,实现Person接口
    //        Class<?> proxyClass = Proxy.getProxyClass(Person.class.getClassLoader(), new Class<?>[]{Person.class});
    //
    //        /** 代理类信息 */
    //        System.out.println("package = " + proxyClass.getPackage() + " SimpleName = " + proxyClass.getSimpleName() + " name =" + proxyClass.getName() + " CanonicalName = " + "" + proxyClass.getCanonicalName() + " 实现的接口 Interfaces = " + Arrays.toString(proxyClass.getInterfaces()) + " superClass = " + proxyClass.getSuperclass() + " methods =" + Arrays.toString(proxyClass.getMethods()));        // 3、  通过 proxyClass 获得 一个带有InvocationHandler参数的构造器constructor
    //        Constructor<?> ProxyConstructor = proxyClass.getConstructor(InvocationHandler.class);
    //
    //        // 4、通过构造器创建一个  动态代理类 实例
    //        Person stuProxy = (Person) ProxyConstructor.newInstance(Handlertwo);
    //
    //        /** 检测生成的类是否是代理类 */
    //        System.out.println("stuProxy isProxy " + Proxy.isProxyClass(stuProxy.getClass()));
    //
    //        /** 获取 代理类关联的 InvocationHandler 是哪个*/
    //        InvocationHandler handlerObject = Proxy.getInvocationHandler(stuProxy);
    //        System.out.println(handlerObject.getClass().getName());
    //        stuProxy.goWorking(stuProxy.getName(), "广州");
    //
    //        // 保存代理类
    //        String pathdir = "/Users/benjamin/IntelliJIdeaProjects/springboot-mydemo/demo/jdkdynamicclasses";
    //        saveClass("$PersonProxy0", proxyClass.getInterfaces(), pathdir);
        }
    
        /**
         * 生成代理类 class 并保持到文件中
         *
         * @param className  生成的代理类名称
         * @param interfaces 代理类需要实现的接口
         * @param pathdir    代理类保存的目录路径,以目录分隔符结尾
         */
        public static void saveClass(String className, Class<?>[] interfaces, String pathdir) {        /**
         * 第一个参数是 代理类 名 。
         * 第二个参数是 代理类需要实现的接口
         */
            byte[] classFile = ProxyGenerator.generateProxyClass(className, interfaces);
    
            /**
             * 如果目录不存在就新建所有子目录
             */
            Path path1 = Paths.get(pathdir);
            if (!path1.toFile().exists()) {
                path1.toFile().mkdirs();
            }
    
            String path = pathdir + className + ".class";
            try (FileOutputStream fos = new FileOutputStream(path)) {
                fos.write(classFile);
                fos.flush();
                System.out.println("代理类class文件写入成功");
            } catch (Exception e) {
                System.out.println("写文件错误");
            }
        }
    
        /**
         * 设置保存Java动态代理生成的类文件。
         *
         * @throws Exception
         */
        public static void saveGeneratedJdkProxyFiles() throws Exception {
            Field field = System.class.getDeclaredField("props");
            field.setAccessible(true);
            Properties props = (Properties) field.get(null);
            props.put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        }
    }
    
    

    生成的代理类的字节码

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package com.sun.proxy;
    
    import com.example.demo.jdkproxytest.Person;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    
    public final class $Proxy0 extends Proxy implements Person {
        private static Method m1;
        private static Method m4;
        private static Method m3;
        private static Method m2;
        private static Method m5;
        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 void setName(String var1) throws  {
            try {
                super.h.invoke(this, m4, new Object[]{var1});
            } catch (RuntimeException | Error var3) {
                throw var3;
            } catch (Throwable var4) {
                throw new UndeclaredThrowableException(var4);
            }
        }
    
        public final String getName() throws  {
            try {
                return (String)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 void goWorking(String var1, String var2) throws  {
            try {
                super.h.invoke(this, m5, new Object[]{var1, var2});
            } catch (RuntimeException | Error var4) {
                throw var4;
            } catch (Throwable var5) {
                throw new UndeclaredThrowableException(var5);
            }
        }
    
        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"));
                m4 = Class.forName("com.example.demo.jdkproxytest.Person").getMethod("setName", Class.forName("java.lang.String"));
                m3 = Class.forName("com.example.demo.jdkproxytest.Person").getMethod("getName");
                m2 = Class.forName("java.lang.Object").getMethod("toString");
                m5 = Class.forName("com.example.demo.jdkproxytest.Person").getMethod("goWorking", Class.forName("java.lang.String"), Class.forName("java.lang.String"));
                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动态代理-生成的代理类的字节码

          本文链接:https://www.haomeiwen.com/subject/rdlmgctx.html