Java动态代理的简单使用

导读:本篇文章讲解 Java动态代理的简单使用,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

代理设计模式的含义是:当我们需要一个功能时,不直接找拥有该功能的类,而去找他的代理类去实现功能,代理类可以在实现功能的同时做一些其他操作。代理模式涉及如下概念:

  • 被代理类:实际拥有某个功能的类
  • 代理类:被外界调用实现某个功能的类,通过持有被代理类实例的引用来实现功能

代理模式分为静态代理和动态代理,下面分别介绍

静态代理

了解动态代理之前,先介绍一下静态代理,它是理解动态代理的基础。我们思考一个场景,一个歌手(被代理类)有唱歌的功能,如果想让歌手唱歌,我们一般找不到歌手本人,而是找到经纪人(代理类),经纪人完成确定日程、收取费用等等一系列工作后再找到歌手实际来实现唱歌的功能,这就是一个代理模式的实际应用场景。我们按照上述场景通过静态代理来实现一下,步骤如下:

  • 定义一个唱歌的接口,接口中声明唱歌的方法
//定义接口,被代理类和代理类都需要实现
interface SingSong{
    void sing();
}
  • 定义被代理类(即歌手),实现上面定义的接口
//被代理类
class Singer implements SingSong{

    private String name;

    public Singer(String name) {
        this.name = name;
    }

    //被代理类实际来实现接口的功能
    @Override
    public void sing() {
        System.out.println(name + "唱歌");
    }
}
  • 定义代理类(即经纪人),实现与被代理类相同的接口,并定义一个被代理类的成员变量,通过构造方法接收。实现接口方法时做一些额外操作,最终要调用被代理类的方法来实际实现相应的功能
//代理类
class Agent implements SingSong{
    //代理类需持有被代理类的引用
    private Singer singer;

    public Agent(Singer singer) {
        this.singer = singer;
    }

    @Override
    public void sing() {
        //代理类实现接口功能时,可以做一些额外操作,然后再实际调用被代理类的方法实现功能
        System.out.println("安排日程");
        System.out.println("收费");
        singer.sing();
    }

实际测试代码如下:

public static void main(String[] args) {
        Agent agent = new Agent(new Singer("Jay"));
        agent.sing();
    }

输出结果为:
在这里插入图片描述
总结一下实现静态代理的思路和要点:

  • 要事先定义好一个所需功能的接口(唱歌),代理类和被代理类必须同时实现这个接口。被代理类(歌手)实现这个接口是因为本身它就是实际具备这个功能的载体,代理类(经纪人)实现这个接口是因为我们最终需要通过代理类调用接口的方法来实现功能,而不是直接调用被代理类
  • 代理类(经纪人)需要持有被代理类(歌手)实例的引用,因为我们调用代理类的方法最终都是想实际实现需求的功能,而代理类(经纪人)不具备实际的功能,只能找被代理类(歌手)
  • 我们调用代理类的方法实现功能时,代理类可以做一些额外操作,在需要时再调用被代理类实例的相应方法即可

动态代理

动态代理在代理模式的思想上和静态代理是一直的,就是实现上更加方便了,不需要我们自己写代理类,调用系统的方法动态生成代理类,但是注意功能的接口、被代理类还是需要我们自己实现的。我们还是以上面歌手、经纪人的场景为例,实现一下动态代理:

  • 前两步和静态代理一致,定义唱歌接口和被代理类
//定义接口,被代理类和代理类都需要实现
interface SingSong{
    void sing();
}

//被代理类
class Singer implements SingSong{

    private String name;

    public Singer(String name) {
        this.name = name;
    }

    //被代理类实际来实现接口的功能
    @Override
    public void sing() {
        System.out.println(name + "唱歌");
    }
}
  • 定义一个类实现InvocationHandler接口,实现invoke()方法。在类中定义一个被代理类的成员变量(构造方法中传入实例),在invoke()方法中做额外操作并最终调用被代理类实例的方法实现功能
//InvocationHandler的实现类
class Handler implements InvocationHandler{

    //需持有被代理类的引用
    private Singer singer;

    public Handler(Singer singer) {
        this.singer = singer;
    }

    //调用代理类的方法实际会调invoke
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("invoke");
        //判断调用的方法名
        if (method.getName().equals("sing")){
            //做代理工作,然后调用被代理类的方法实现功能
            System.out.println("安排日程");
            System.out.println("收费");
            method.invoke(singer, args);
        }
        return null;
    }
}
  • 调用Proxy类的静态方法newProxyInstance(ClassLoader loader,Class<?>[] interfaces,reflect.InvocationHandler h) 动态创建出一个代理对象,该方法接收3个参数:第1个参数是类加载器,使用被代理类的类加载器即可;第2个参数是代理类需要实现的接口,传入被代理类实现的接口即可;第3个参数是InvocationHandler实例,传入我们之前实现好的对象即可。得到动态生成的代理对象后,将该对象强转成实际功能的接口类型并调用相应的方法,这样做实际就会执行InvocationHandler中的invoke方法,从而实现代理类的功能
public static void main(String[] args) {
        //创建被代理类
        Singer singer = new Singer("Jay");
        //创建InvocationHandler实例,传入被代理类的实例
        Handler handler = new Handler(singer);
        //动态生成代理类
        Object proxyInstance = Proxy.newProxyInstance(singer.getClass().getClassLoader(), singer.getClass().getInterfaces(),handler);
        //调用代理类的相关方法,实际会调用到InvocationHandler中的invoke方法
        ((SingSong) proxyInstance).sing();
    }

输出结果如下:
在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/2674.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!