美文网首页
浅谈java原生动态代理

浅谈java原生动态代理

作者: overflow_e4e4 | 来源:发表于2019-05-06 17:01 被阅读0次

    浅谈java动态代理

    怎么使用动态代理

    共需4个类

    • 一个接口和一个实现他的类
    package invoke;
    
    public interface ICar {
        void run();
    }
    
    package invoke;
    
    public class Car implements ICar {
        @Override
        public void run() {
            System.out.println("car run");
        }
    }
    
    • 一个自定义的InvocationHandler
    package invoke;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    public class MyInvocationHandler implements InvocationHandler {
        private final ICar car;
    
        public MyInvocationHandler(ICar car) {
            this.car = car;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
                System.out.println("before");
                Object result = method.invoke(car, args);
                System.out.println("after");
                return result;
    
        }
    }
    
    
    • 一个test main函数
    package invoke;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    
    public class ProxyDemo {
    
        public static void main(String[] args) {
            InvocationHandler invocationHandler = new MyInvocationHandler(new Car());
    
            ICar proxy = (ICar) Proxy.newProxyInstance(Car.class.getClassLoader(),Car.class.getInterfaces() ,invocationHandler);
            proxy.run();
    
        }
    }
    
    
    • 运行结果
    before
    car run
    after
    
    Process finished with exit code 0
    

    一些细节

    1. 开启动态代理生成文件
      通过阅读源码需要设置系统变量可以知道只要设置sun.misc.ProxyGenerator.saveGeneratedFiles为true就可以吧动态代理生成的class文件写入文件系统。可以通过在代码中加入一句System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");或者在VMoptions中加入参数-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true来开启这个选项。生成的代理class文件在工程根目录的com\sun\proxy
    2. 反编译代理类
      这是我通过idea反编译得到的代理类的结构
    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package com.sun.proxy;
    
    import invoke.ICar;
    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 ICar {
        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 void run() 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);
            } 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("invoke.ICar").getMethod("run");
                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());
            }
        }
    }
    
    

    研究这个类,发现他通过反射得到了原来 ICar接口的所有方法,自己也实现了ICar接口并重写了这几个方法,只不过重写的时候都通过代理来调用各种方法,这里的super.h变量其实就是MyInvocationHandler的一个实现,所以最终调用会走到MyInvocationHandler.invoke的方法实现中。

    相关文章

      网友评论

          本文标题:浅谈java原生动态代理

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