zoukankan      html  css  js  c++  java
  • java静态代理和JDK动态代理

    静态代理

    编译阶段就生产了对应的代理类

    public interface IBussiness {
        void execute();
    }
    public class BussinessImpl implements IBussiness{
        @Override
        public void execute() {
            System.out.println("执行业务逻辑...");
        }
    }
    public class BussinessProxy implements IBussiness{
        
        private IBussiness bussinessImpl;
         
        public BussinessProxy(IBussiness bussinessImpl) {
            this.bussinessImpl = bussinessImpl;
        }
        
        @Override
        public void execute() {
            System.out.println("前拦截...");
            bussinessImpl.execute();
            System.out.println("后拦截...");
        }
    }
    public class Test {
    
        public static void main(String[] args) {
            
            IBussiness bussiness = new BussinessImpl();
            BussinessProxy  proxy = new BussinessProxy(bussiness);
            proxy.execute();
            
        }
    }

    JDK动态代理

    动态生成字节码,加载到内存中,利用反射去执行真正的方法

    关键代码:

    Proxy.newProxyInstance(ClassLoader, Interfaces, InvocationHandler);

    生成代理类时,要将类加载器,接口和InvocationHandler传递过去,

    类加载器的作用是,生成的字节码要加载到JVM当中

    接口的作用是,生成的代理类要知道代理的有哪些方法

    InvocationHandler的作用是,在代理类中实际执行的是InvocationHandler的invoke方法

    public interface Person {
        /**
         * 唱歌
         */
        void sing();
        /**
         * 跳舞
         * @param name 舞曲名
         * @return
         */
        String dance(String name);
    }
    public class PersonImpl implements Person{
    
        @Override
        public void sing() {
            System.out.println("开始唱歌");
        }
    
        @Override
        public String dance(String name) {
            System.out.println("" + name);
            return "不好玩";
        }
    }
    public class PersonImplProxy {
        
        private Person person = new PersonImpl();
        
        /**
         * 创建代理
         * @return 返回值是接口类型
         */
        public Person createProxy() {
            /**
             * 产生某个对象的代理对象
             * ClassLoader loader    当前代理对象的类加载器
             * Class<?>[] interfaces 代理对象的接口
             * InvocationHandler h   InvocationHandler对象
             */
            return (Person) Proxy.newProxyInstance(PersonImplProxy.class.getClassLoader(), person.getClass().getInterfaces(), new InvocationHandler() {
                
                /**
                 * @param proxy 把代理对象自身传进去
                 * @param method 代表当前调用的方法
                 * @param args 当前调用方法的参数
                 */
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    // 获取方法名
                    String methodName = method.getName();
                    if ("sing".equals(methodName)) {
                        System.out.println();
                        System.out.println("前置通知... 唱歌开始");
                        method.invoke(person, args);
                        System.out.println("后置通知... 唱歌结束");
                    } else if ("dance".equals(methodName)) {
                        System.out.println();
                        System.out.println("前置通知 ... 跳舞开始");
                        Object res = method.invoke(person, args);
                        System.out.println("后置通知 ... 跳舞结束");
                        return  res;
                    }
                    return null;
                }
            });
        }
        
    }
    public class Test {
        public static void main(String[] args) {
            //设置为true后,可以保存生成的代理类的字节码,
            //注意字节码文件用jd-gui.exe打开,用javap打开显示不全,javap是JDK自带的工具,他们之间的具体实现是不一样的
            System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
            PersonImplProxy proxy = new PersonImplProxy();
            Person person = proxy.createProxy();
            person.sing();
            System.out.println(person.dance("华尔兹三章"));
            System.out.println();
            System.out.println("生成的代理类的名称: " + person.getClass().getName());
    
        }
    
    }

    测试结果

    生成字节码文件

     将字节码文件反编译后

    public final class $Proxy0 extends Proxy implements Person {
        private static Method m1;
        private static Method m2;
        private static Method m3;
        private static Method m4;
        private static Method m0;
    
        public $Proxy0(InvocationHandler paramInvocationHandler) {
            super(paramInvocationHandler);
        }
    
        public final boolean equals(Object paramObject) {
            try {
                return ((Boolean) this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
            } catch (Error | RuntimeException localError) {
                throw localError;
            } catch (Throwable localThrowable) {
                throw new UndeclaredThrowableException(localThrowable);
            }
        }
    
        public final String toString() {
            try {
                return (String) this.h.invoke(this, m2, null);
            } catch (Error | RuntimeException localError) {
                throw localError;
            } catch (Throwable localThrowable) {
                throw new UndeclaredThrowableException(localThrowable);
            }
        }
    
        public final void sing() {
            try {
                this.h.invoke(this, m3, null);
                return;
            } catch (Error | RuntimeException localError) {
                throw localError;
            } catch (Throwable localThrowable) {
                throw new UndeclaredThrowableException(localThrowable);
            }
        }
    
        public final String dance(String paramString) {
            try {
                return (String) this.h.invoke(this, m4, new Object[] { paramString });
            } catch (Error | RuntimeException localError) {
                throw localError;
            } catch (Throwable localThrowable) {
                throw new UndeclaredThrowableException(localThrowable);
            }
        }
    
        public final int hashCode() {
            try {
                return ((Integer) this.h.invoke(this, m0, null)).intValue();
            } catch (Error | RuntimeException localError) {
                throw localError;
            } catch (Throwable localThrowable) {
                throw new UndeclaredThrowableException(localThrowable);
            }
        }
    
        static {
            try {
                m1 = Class.forName("java.lang.Object").getMethod("equals",
                        new Class[] { Class.forName("java.lang.Object") });
                m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
                m3 = Class.forName("com.irish.deligate.Person").getMethod("sing", new Class[0]);
                m4 = Class.forName("com.irish.deligate.Person").getMethod("dance",
                        new Class[] { Class.forName("java.lang.String") });
                m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
                return;
            } catch (NoSuchMethodException localNoSuchMethodException) {
                throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
            } catch (ClassNotFoundException localClassNotFoundException) {
                throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
            }
        }
    }

    可以看到代理类继承了Proxy,实现了我们传递的接口,当调用dance方法时,会转调InvocationHandler的invoke方法,将方法和参数传递过去,由invoke来具体执行代理的逻辑,InvocationHandler持有真正的对象,一般是在调用真正的对象方法前后,执行我们要进行增强的操作。

  • 相关阅读:
    requestAnimationFrame
    js来监控复制粘贴
    nodejs事件循环
    前端路由
    js基础查漏补缺(更新)
    http & https & http2.0
    进度条方案
    移动端适配方案
    性能优化之节流、防抖
    altium designer 里如何设置PCB默认字符默认大小(PCB丝印)
  • 原文地址:https://www.cnblogs.com/moris5013/p/10942658.html
Copyright © 2011-2022 走看看