Java动态代理的简单使用

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

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

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

静态代理

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

  • 定义一个唱歌的接口,接口中声明唱歌的方法
//定义接口,被代理类和代理类都需要实现
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();
    }

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值