设计模式-代理模式-JDK动态代理(Proxy.newProxyInstance)

上接:设计模式-代理模式-java

介绍

Proxy对象的生成,使用了JDK的Api,动态的在内存中构建代理对象(需要指定接口)

结构

  1. 接口:通过接口或抽象类声明业务方法。
  2. 目标类:实现目标接口,实现具体业务
  3. 代理(Proxy)类:动态生成代理对象,不需要创建代理类

优点

为解决静态代理中,代理类必须实现接口的问题,Java给出了动态代理,动态代理具有如下特点:

Proxy对象不需要实现接口

缺点

目标类必须实现接口

生成代理对象的api

Proxy

Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )

参数说明:

  1. ClassLoader loader:指定当前目标对象使用类加载器。
    方法固定:target.getClass().getClassLoader()

  2. Class<?>[] interfaces:目标对象实现的接口
    如果传入接口类对象,代码是:target.getClass().getInterfaces()
    如果传入接口,代码是:new Class[]{接口.class}。如:mybatis生成mapper接口(dao接口)对象原理

  3. InvocationHandler h:调用目标对象的方法时,其实质是调用该方法。传入目标对象方法的参数,也会传入到该方法中

返回值: 返回代理对象

InvocationHandler

InvocationHandler.invoke(Object proxy, Method method, Object[] args)

参数说明:

  1. Object proxy:jdk动态生成的代理类对象
  2. Method method:当前执行的方法
  3. Object[] args:当前执行的方法的参数

返回值: 与 目标对象的方法返回值相同

例子

定义 接口类

同 设计模式-代理模式-java

定义 演员类

同 设计模式-代理模式-java

定义导演类(主启动类)

public class Director {
    public static void main(String[] args) {
        IActor actor=new Actor();

        /*
         * 动态实现代理
         * 注意:只能强转成 IActor 接口,不能强转成 Actor 类
         */
        IActor agent=(IActor) Proxy.newProxyInstance(
                actor.getClass().getClassLoader(),
                actor.getClass().getInterfaces(),
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //取出参数
                        Integer money=(Integer) args[0];
                        Integer days=(Integer) args[1];

                        //代理类可以在目标对象的方法之前,增加额外的代码
                        if( money/days<1){
                            System.out.println("Agent==每天酬劳低于1万,不合作!");
                            return false;
                        }
                        System.out.println(String.format("Agent==经纪人扣30%%劳务费:%s,实付70%%给演员",money*3/10));
                        //代理类可以修改传入目标对象的参数,返回值
                        args[0]=money*7/10;
                        //调用目标类对象的方法
                        Object res = method.invoke(actor, args);
                        //代理类可以在目标对象的方法之后,增加额外的代码
                        System.out.println("Agent==合作愉快,期待下次合作!");
                        return true;

                    }
                }
        );

        int money=350;
//        int money=280;
        int days=300;
        System.out.println(String.format("Director==谈合作:%s万,%s天,可以吗?",money,days));
        boolean b=agent.deal(money,days);
        if(b) {
            System.out.println("Director==开拍");
        }else{
            System.out.println("Director==演员没谈成,不能开拍");
        }
    }
}

注意: IActor agent=(IActor)new Agent(actor).getProxyInstance(); 只能强转成 IActor 接口,不能强转成 Actor 类
这就是为什么在java中,很多地方都说:面向接口编程的原因


原文出处:/show_1IX2q8u8R2V.html