• 代理模式之JDK动态代理


    在这里插入图片描述

    package com.bzyd.test.jdk_proxy_;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * @Description JDK动态代理示例
     * @Author dangxianyue
     * @Date 2022/9/25 1:05
     */
    public class JdkDynamicProxyTest {
    
        public static void main(String[] args) {
            // 让代理对象的class文件写入到磁盘
            System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
            Suitor suitor = new Suitor();//被代理者
            InvocationHandler h = new ProxyEnhancer(suitor);//增强器
            /**
             * 创建代理类实例,Proxy就是个空壳,需要指定一下三个参数,才能生成代理类实例
             * 第一个参数,ClassLoader loader,指定代理类的类加载器
             * 第二个参数:Class[] interfaces,指定代理类要实现的接口列表
             * 第三个参数:InvocationHandler h,指定代理类的增强逻辑
             */
            Object _proxy = Proxy.newProxyInstance(suitor.getClass().getClassLoader(), suitor.getClass().getInterfaces(), h);
            System.out.println("_proxy: " + _proxy.getClass().getSuperclass().getName());
            //_proxy: java.lang.reflect.Proxy
            //从这里可以看出,JDK创建出来的代理类对象都继承了Proxy类,
            //实际上是,_proxy extends Proxy implements LoveLetter,但不是被代理者Suitor的子类,这是和Cglib代理的区别之一
            //而Java是单继承的,所以被代理者Suitor必须实现接口
            //@Aurowired
            //private xxxImpl xxx;
            //当用到代理类的场景时,这里用实现类接收会报错,得用接口去接收
    
            LoveLetter loveLetter = (LoveLetter) _proxy;
            loveLetter.sendLetter("小丽");//调用代理类对象
    
            //结果:
            //_proxy: java.lang.reflect.Proxy
            //增强逻辑【送情书】>>>>>>>>>>>>>开始
            //写情书:小丽,我喜欢你! (此处可以看出类内调用没有被代理增强)
            //送情书:小丽,这是有人送你的情书!
            //增强逻辑【送情书】>>>>>>>>>>>>>结束
        }
    }
    
    /**
     * 求爱接口
     */
    interface LoveLetter {
    
        /**
         * 写情书
         *
         * @param name
         */
        void writeLetter(String name);
    
        /**
         * 送情书
         *
         * @param name
         */
        void sendLetter(String name);
    }
    
    /**
     * 追求者,被代理者
     * JDK代理是接口代理,被代理类必须实现某个接口
     */
    class Suitor implements LoveLetter {
    
        @Override
        public void writeLetter(String name) {
            System.out.println("写情书:" + name + ",我喜欢你!");
        }
    
        @Override
        public void sendLetter(String name) {
            //注意,类内自调用,即,反射调用被代理者原逻辑,而原逻辑内又调用本类方法
            //相当于this.writeLetter(name),调用到的是被代理者的方法,而不是通过代理类调用到的增强方法
            //所以这就是为什么类内调用不被代理增强的原因
            //也就是@Transactional事务注解,在类内调用时无效的原因!!!
            writeLetter(name);
            System.out.println("送情书:" + name + ",这是有人送你的情书!");
        }
    
    }
    
    
    /**
     * 代理增强类
     * 封装增强逻辑
     * 必须实现java.lang.reflect.InvocationHandler接口
     */
    class ProxyEnhancer implements InvocationHandler {
    
        /**
         * 被代理对象,反射调用方法要用到实例,所以得自己保存
         */
        private Suitor suitor;
    
        public ProxyEnhancer(Suitor suitor) {
            this.suitor = suitor;
        }
    
        /**
         * 增强逻辑
         * 底层原理是使用反射调用对象的方法
         * 效率比AspectJ预编译静态代理慢得多
         * 但不需要额外的编译,是在运行时动态生成代理增强类
         *
         * @param proxy  Proxy.newProxyInstance创建出来的代理类Proxy的一个实例
         * @param method 被代理对象suitor反射出来的被代理的方法
         * @param args   方法参数,反射调用要用到
         * @return
         * @throws Throwable
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
            String s = "writeLetter".equals(method.getName()) ? "写情书" :
                    ("sendLetter".equals(method.getName()) ? "送情书" : "");
            System.out.println("增强逻辑【"+s+"】>>>>>>>>>>>>>开始");
            Object invoke = method.invoke(suitor, args);
            System.out.println("增强逻辑【"+s+"】>>>>>>>>>>>>>结束");
            return invoke;
        }
    }
    
  • 相关阅读:
    HashMap
    Redis介绍、安装、性能优化
    数据库学习02
    【AD9361 数字接口CMOS &LVDS】A CMOS
    Ansible自动化部署工具-role模式安装filebeat实际案例分析
    JavaScript 垃圾回收机制
    【剑指Offer】8.二叉树的下一个结点
    SQL开发笔记之专栏介绍
    产品原型工具的迭代路径——高效、协作、交互、简便
    Unity --- 摄像机的选择与设置
  • 原文地址:https://blog.csdn.net/weixin_44360895/article/details/127039032