java高级:动态代理

动态代理介绍、准备功能

这节课我们学习一个Java的高级技术叫做动态代理。首先我们认识一下代理长什么样?

假设现在有一个明星坤坤,它有唱歌和跳舞的本领,作为明星是要用唱歌和跳舞来赚钱的,但是每次做节目,唱歌的时候要准备话筒、收钱,再唱歌;跳舞的时候也要准备场地、收钱、再唱歌。明星觉得我擅长的做的事情是唱歌,和跳舞,但是每次唱歌和跳舞之前或者之后都要做一些繁琐的事情,有点烦。于是就找个一个经济公司,请了一个代理人,代理明星处理这些事情,如果有人想请明星演出,直接找代理人就可以了。如下图所示

java高级:动态代理_第1张图片
我们说明星的代理是中介公司派的,那中介公司怎么知道,要派一个有唱歌和跳舞功能的代理呢?

解决这个问题,Java使用的是接口,明星想找代理,在Java中需要明星实现了一个接口,接口中规定要唱歌和跳舞的方法。Java就可以通过这个接口为明星生成一个代理对象,只要接口中有的方法代理对象也会有。

java高级:动态代理_第2张图片

接下来我们就先把有唱歌和跳舞功能的接口,和实现接口的大明星类定义出来,声明接口是为了声明大明星类中有的方法代理对象也会有,注意,大明星类也需要实现Star接口,这是java生成代理的一个约定。

java高级:动态代理_第3张图片

生成动态代理对象

有了上面的准备工作,下面我们需要写一个为BigStar生成动态代理对象的工具类ProxyUtil代表中介机构。使用工具类产生代理则需要用Java为开发者提供的一个生成代理对象的类叫Proxy类。注意Proxy类有多个,我们需要选择java.lang.reflect中的Proxy

通过Proxy类的newInstance(…)方法可以为实现了同一接口的类生成代理对象。 调用方法时需要传递三个参数,该方法的参数解释可以查阅API文档,如下。

java高级:动态代理_第4张图片

java高级:动态代理_第5张图片

这里代码逻辑比较抽象,所以写了大量的注释来解释逻辑,需要仔细阅读。

public class ProxyUtil {
    //因为是工具类所以可以定义一个静态方法来产生代理,产生谁的代理可以通过方法参数传递
    //这个方法生成的代理肯定是实现了Star接口的对象 所以这里可以将Star作为返回值
    public static Star createProxy(BigStar bigStar){//我们要为bigStar创造代理并返回
       /* newProxyInstance(ClassLoader loader,
                Class[] interfaces,
                InvocationHandler h)
                参数1:用于指定一个类加载器 用于加载生成的代理类 写法是固定的 背就行 一般用当前类的类加载器
                参数2:一个接口数组 指定生成的代理长什么样子 也就是有哪些方法 我们这里只有一个接口 把它包装成数组传进去即可
                参数3:用来指定生成的代理对象要干什么事情 这里传递的是一个InvocationHandler接口
                因为接口不能直接创建对象 所以一般是传递一个匿名内部类对象来指定代理对象干什么事情重写invoke方法就行
                */

        /* invoke方法是个回调方法 会被谁回调呢? 假设代理写好了 调用时是会写这样的代码的:
         * Star starProxy = ProxyUtil.createProxy(s);//得到一个s的代理对象
         * starProxy.sing("好日子") starProxy.dance() 而sing和dance会调用invoke方法!
         * 因为代理干什么事情用invoke决定 invoke需要三个参数 所以sing和dance也会传进这三个参数
         * 比如starProxy.sing("好日子") starProxy是第一个参数 sing是第二个 "好日子"是第三个
         * 第一个参数java把代理对象当做一个Object 也就是starProxy 第二个参数是调用的方法
         * 如果是sing调用 method代表的就是sing方法 第三个参数args会把方法的参数通过一个object数组传进来
         * 比如sing调用时就会把"好日子"传进数组 这就是invoke三个参数的含义
         */
        //newProxyInstance返回的是Object 所以需要强转
        Star starProxy = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
                new Class[]{Star.class}, new InvocationHandler() {
                    @Override // 重写invoke回调方法
                    //invoke是重点 代理干什么事情其实是由它决定
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // 代理对象要做的事情,会在这里写代码
                        if(method.getName().equals("sing")){
                            System.out.println("准备话筒,收钱20万");
                        }else if(method.getName().equals("dance")){
                            System.out.println("准备场地,收钱1000万");
                        }
                        //代理做完事情 再让明星做他该做的事
                        return method.invoke(bigStar, args);//bigStar代表明星 再把调用方法参数传进来
                        //注意这里的invoke不是这里写的invoke 而是反射里Method提供的invoke方法!
                        //调用sing 则会返回"谢谢大家!
                    }
                });
        return starProxy;//返回代理对象
    }
}

在写一个Test类调用我们写好的ProxyUtil工具类,为BigStar对象生成代理对象:

public class Test {
    public static void main(String[] args) {
        BigStar s = new BigStar("大明星坤坤");
        Star starProxy = ProxyUtil.createProxy(s);

        String rs = starProxy.sing("好日子");
        System.out.println(rs);

        starProxy.dance();
    }
}

运行结果:

java高级:动态代理_第6张图片




动态代理应用

学习完动态代理的基本使用之后,接下来我们再做一个应用案例。

你可能感兴趣的:(java,java,开发语言,代理模式)