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方法,打印结果:


3110861-08acc0d4b4fb669b.png
图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). 执行主函数, 打印结果


3110861-3de3782e785b128c.png
图2.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值