• 动态代理与静态代理


    代理是基本的设计模式之一,使用代理对象代替真实对象的方法调用,可以扩展真实对象某些方法的功能。

    在 java 中又分为静态代理和动态代理, 先看静态代理:

    静态代理

    public class DynamicDemo {
    
        public static void main(String[] args) {
            /**
             * 静态代理示例
             */
            System.out.println("=======静态代理========");
    
            // user 真实对象
            Save user = new UserDAO();
            // userTransaction 是代理对象
            Save userTransaction = new UserTransaction(user);
            // 使用代理对象执行方法
            userTransaction.save("dc1");
        }
    
    }
    
    interface Save {
        /**
         * 保存
         */
        void save(String name);
    
        /**
         * 删除
         * @param name
         */
        void delete(String name);
    }
    
    class UserDAO implements Save {
    
        public void save(String name) {
            System.out.println("真实对象执行 save 方法");
        }
    
        public void delete(String name) {
            System.out.println("真实对象执行 delete 方法");
        }
    }
    
    /**
     * 手动编写代理类
     */
    class UserTransaction implements Save {
    
        /**
         * 真实对象
         */
        private Save realObject;
    
        UserTransaction(Save save) {
            this.realObject = save;
        }
    
        /**
         * 在真实对象前后做一些操作
         */
        public void save(String name) {
            System.out.println("静态代理: 在真实对象做事之前,代理要做的事情");
            // 真实对象开始执行save方法
            realObject.save(name);
            System.out.println("静态代理: 在真实对象做事之后,代理要做的事情");
    
        }
    
        public void delete(String name) {
    
            /**
             * 什么都不做,直接执行真实对象的 delete 方法。
             * 这里就体现了静态代理方式的弊端,哪怕我只想代理一个方法,也需要实现所有方法。
             * 只用真实对象代理。有很多无意义的代码
             */
            realObject.save(name);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

    通过以上代码可以知道java中的静态代理有几个关键的地方:

    1. 代理对象和真实对象实现了相同的接口,或者继承同一个类。换句话说就是可以向上转型为相同的对象
    2. 真实对象要作为代理对象中一个属性。方便真实对象调用方法

    有时我们只想扩展原对象的某个方法,给这个方法添加一些功能。但是我们仍要编写一个代理类,实现真实类中的所有方法。导致很多冗余代码, java 中的动态代理可以解决这个问题

    动态代理

    先看代码:

    public class DynamicDemo {
    
        public static void main(String[] args) {
            /**
             * 动态代理示例
             */
            System.out.println("======动态代理======");
    
            // 动态生成一个代理对象
            Save saveProxy = (Save) Proxy.newProxyInstance(
                    // 真实对象的类加载器
                    user.getClass().getClassLoader(),
                    // 要代理的接口,数组
                    new Class[]{ Save.class},
                    // 将 user 真实对象传入代理处理类
                    new DynamicHandler(user)
            );
            // 代理对象执行方法,内部会调用真实对象执行对应方法
            saveProxy.save("dc1");
        }
    
    }
    
    interface Save {
        /**
         * 保存
         */
        void save(String name);
    
        /**
         * 删除
         * @param name
         */
        void delete(String name);
    }
    
    class UserDAO implements Save {
    
        public void save(String name) {
            System.out.println("真实对象执行 save 方法");
        }
    
        public void delete(String name) {
            System.out.println("真实对象执行 delete 方法");
        }
    }
    
    /**
     * 代理对象要执行的方法
     */
    class DynamicHandler implements InvocationHandler {
    
        private Object realObject;
        public DynamicHandler(Object real) {
            this.realObject = real;
        }
    
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("代理对象类:" + proxy.getClass());
            System.out.println("要代理的方法是: " + method.getName() );
            System.out.println("参数是:");
            for (Object arg : args) {
                System.out.printf(arg + " ");
            }
            System.out.println("");
            if(method.getName().equals("delete")){
                System.out.println("执行了 delete 方法");
            }
    
            /**
             * 这里的操作体现了动态代理的优点: 在需要代理的方法前后编写功能
             */
            if(method.getName().equals("save")){
                System.out.println("执行了 save 方法");
                System.out.println("真实对象执行save方法前");
            }
            // 真实对象执行方法
            method.invoke(this.realObject,args);
    
            if(method.getName().equals("save")){
                System.out.println("真实对象执行save方法后");
            }
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    从上面代码中可以发现,实现动态代理的关键点:

    1. InvocationHandler 的实现类,invoke 方法中编写你要扩展的功能
    2. InvocationHandler 的实现类中要有一个属性保存真实对象。也就是例中的 realObject, 以便真实对象调用方法,如果不需要真实对象调用方法,那么也就不需要这个真实对象了。
    3. 使用 Proxy.newProxyInstance 方法创建代理对象。

    动态代理实际上是JVM在运行期动态创建class字节码并加载的过程,它并没有什么黑魔法。它创建的字节码就是我们在静态代理中编写的代理类。只不过不用我们手动编写了而已。

  • 相关阅读:
    Oracle database 创建只读账号(新建用户与只读用户)
    买卖股票的最佳时机 II
    C语言学生信息管理系统
    E056-web安全应用-File Inclusion文件包含漏洞进阶
    十三、【分布式微服务企业快速架构】SpringCloud分布式、微服务、云架构之Eclipse 创建 XML 文件
    Vue框架--Vue列表渲染(1)
    【Apache Doris】审计日志插件 | 快速体验
    0基础,跟我一起学python---基础篇
    计算机网络——WLAN简解
    ChatGPT 设计游戏剧情 | 基于 AI 5 天创建一个农场游戏,完结篇!
  • 原文地址:https://blog.csdn.net/a141210104/article/details/127655527