Java Proxy动态代理

1. 动态代理概念:

  • 代理对象存在的价值: 主要用于拦截对真实业务对象的访问。
  • 代理对象有什么方法: 一般来说,真实业务对象具有什么方法,那么代理对象就会具备相应的方法。

2. 设计要素

  • 代理谁?
    须设计一个类变量,以及一个构造函数,记住代理类代理哪个对象。
  • 如何生成代理对象?
    设计一个方法生成代理对象(在方法内编写代码生成代理对象是此处编程的难点)

3. Proxy类

Java提供了一个Proxy类,调用它的newInstance方法可以生成某个对象的代理对象,使用该方法生成代理对象时,需要三个参数:

  • 生成代理对象使用哪个类装载器。
  • 生成哪个对象的代理对象,通过接口指定。
  • 生成的代理对象的方法里干什么事,由开发人员编写handler接口的实现来指定。

4. 注意

  • Proxy类负责创建代理对象时,如果指定了handler(处理器),那么不管用户调用代理对象的什么方法,该方法都是调用处理器的invoke方法。
  • 由于invoke方法被调用需要三个参数:代理对象、方法、方法的参数,因此不管代理对象哪个方法调用处理器的invoke方法,都必须把自己所在的对象、自己(调用invoke方法的方法)、方法的参数传递进来。

5. 约定:要想创建某一个对象的代理对象,那么该对象必须实现一个接口。

6. 简单示例

1). 创建接口Person

public interface Person {
    /**
     * 唱歌
     */
    void sing();
    /**
     * 跳舞
     */
    void dance();
}

2). 创建实现Person接口的PersonImpl类

public class PersonImpl implements Person{

    @Override
    public void sing() {
        System.out.println("开始唱歌");
    }

    @Override
    public void dance() {
        System.out.println("开始跳舞");
    }

}

3). 创建代理类

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 {
                // 编写代码
                return null;
            }
        });
    }
    
}

4). 编写Demo类中主函数main()

public class Demo {
    public static void main(String[] args) {
        PersonImplProxy proxy = new PersonImplProxy();
        Person person = proxy.createProxy();
        person.sing();
        person.dance();
    }
}

5). 实现代理对象中的createProxy方法中的invoke方法

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("啦啦啦啦啦啦啦啦");
                    method.invoke(person, args);
                } else if ("dance".equals(methodName)) {
                    System.out.println("哈哈哈哈哈哈哈哈");
                    method.invoke(person, args);
                } else {
                    System.out.println("啊啊啊啊啊啊啊啊");
                }
                return null;
            }
        });
    }
    
}

6). 调用main方法,打印结果:


图1.png

7. 高级进阶--接口方法中带参数带返回值

1). 创建Person接口

public interface Person {
    /**
     * 唱歌
     * @param name 歌曲名
     * @return
     */
    String sing(String name);
    /**
     * 跳舞
     * @param name 舞曲名
     * @return
     */
    String dance(String name);
}

2). 创建实现Person接口的PersonImpl类

public class PersonImpl implements Person {

    @Override
    public String sing(String name) {
        System.out.println("唱" + name);
        return "唱完了";
    }

    @Override
    public String dance(String name) {
        System.out.println("跳" + name);
        return "不好玩";
    }

}

3). 创建PersonImpl的代理类

public class PersonImplProxy {
    private Person person = new PersonImpl();
    
    public Person createProxy() {
        return (Person) Proxy.newProxyInstance(PersonImplProxy.class.getClassLoader(), person.getClass().getInterfaces(), new InvocationHandler() {
            
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 编写代码
                return null;
            }
        });
    }
}

4). 编写Demo类中主函数

public class Demo {
    public static void main(String[] args) {
        PersonImplProxy proxy = new PersonImplProxy();
        Person person = proxy.createProxy();
        System.out.println(person.sing("说散就散"));
        System.out.println(person.dance("体面"));
    }
}

5). 实现代理对象中的invoke方法

public class PersonImplProxy {
    private Person person = new PersonImpl();
    
    public Person createProxy() {
        return (Person) Proxy.newProxyInstance(PersonImplProxy.class.getClassLoader(), person.getClass().getInterfaces(), new InvocationHandler() {
            
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 编写代码
                String methodName = method.getName();
                if ("sing".equals(methodName)) {
                    System.out.println("啦啦啦啦啦啦");
                    return method.invoke(person, args);
                } else if ("dance".equals(methodName)) {
                    System.out.println("哈哈哈哈哈哈");
                    return method.invoke(person, args);
                } else {
                    System.out.println("哈哈哈哈哈哈");
                }
                return null;
            }
        });
    }
}

6). 执行主函数, 打印结果


图2.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 一、代理的概念与作用 1.1、生活中的代理 杭州人从在杭州本地从杭州的代理商(线下商店)中买联想电脑和直接跑到北京...
    侠客有情剑无情QAQ阅读 12,628评论 3 13
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 14,023评论 6 13
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 136,092评论 19 139
  • 今天阅读的故事是《十二生肖之龙王闹海》,是讲的鲁西西和皮皮鲁他们有次遇到了一条龙,然后他们把它带回了家,还给...
    恩瑾阅读 3,211评论 0 0
  • 补发4月4日的内容,并修改: 最近,报名学习Angie的《个人品牌崛起技能特训营》,下面将第一课的心得分享如下: ...
    蝶无双阅读 4,093评论 1 9

友情链接更多精彩内容