可恶的动态代理!!!!我要消灭你

一、与动态代理的恩怨

学了一段时间了(大学四年+待业半年),感觉自己学习了一个寂寞,在此发誓要每天回顾一个旧的小知识点,把东西都搞懂。
动态代理之前对它的概念及其模糊,代理代理,不就是帮他人办事嘛,但是具体的实现还是不明白。
看了看视频,看了一些大佬的文章,有一点点的理解,记录一下,顺便希望可以得到大家的指正。

二、概念

讲动态代理的概念之前,先说一下“代理”

代理

打个比方吧,太专业的词藻说不出来。
我要买草莓果酱,我需要到淘宝找卖草莓果酱的商家下单,商家要到草莓果酱的工厂,拿到果酱,寄快递给我。
简而言之:
1、顾客找卖草莓果酱的淘宝商家
2、商家找草莓果酱的工厂
这个过程中,淘宝卖家就是“代理”,顾客要通过淘宝卖家这个“代理”才能够买到果酱。
小可爱疑问:为什么顾客不直接找工厂买呢?
顾客没工厂资源,你谁呀?还有你直接找工厂买了,“代理”怎么中间商赚差价,还有一点比较重要的后面说。

·········静态代理
代理—|··············JDK动态代理
·········动态代理—|
·························CGLIB动态代理

静态代理

定义一个目标类的接口:功能是卖果酱,返回价格

//目标类接口
public interface Jam {
    //返回价格
    int sellJam(int number);
}

定义一个工厂实现这个目标类的接口,返回工厂的价格

public class StrawberryFactory implements Jam {
    @Override
    public int sellJam(int number) {
        //返回工厂价格
        return 10*number;
    }
}

定义一个商家也要实现这个目标类的接口(商家也要卖果酱),返回商家的价格

public class StrawberryMerchant implements Jam {
    //获取目标类:找到一个做草莓果酱工厂
    StrawberryFactory factory = new StrawberryFactory();

    @Override
    //实现卖果酱的功能
    public int sellJam(int number) {
        //向工厂下单,告诉工厂需要多少草莓果酱
        int factoryMoney = factory.sellJam(number);//返回工厂价格

        //收取辛苦费用
        int money = factoryMoney+10;

        //给顾客
        return money;
    }
}

顾客下单

public class Client {
    public static void main(String[] args) {
        //获取代理对象:卖草莓果酱的商家
        StrawberryMerchant merchant = new StrawberryMerchant();
        int money = merchant.sellJam(10);
        System.out.println("10罐草莓果酱的价格是"+money);
    }
}

执行结果

10罐草莓果酱的价格是110

Process finished with exit code 0
如果我现在还想买苹果果酱呢?那就还需要找一个卖苹果果酱的商家,这个苹果果酱的商家找加工苹果果酱的工厂。
如果还想买葡萄果酱呢?这样有点麻烦,还不如找一个既卖草莓果酱,又卖苹果果酱,还卖葡萄果酱的淘宝卖家
---------这个需求动态代理可以实现

··············优点: 1、实现简单 2、容易理解
静态代理----|
··············缺点: 1、当目标类增加了,代理类也需要增加。代理类数量多。2、当接口中增加或者修改一个功能,会影响实现这个接口的类。

动态代理(jdk)

jdk动态代理是基于反射来实现的。
使用动态代理有三个要点:
1、必须实现 InvocationHandler 接口,表明该类是一个动态代理执行类。
2、InvocationHandler 接口内有一实现方法如下:

public Object invoke(Object proxy, Method method, Object[] args) 

使用时需要重写这个方法
3、获取代理类,需要使用

Proxy.newProxyInstance(Clas loader, Class[] interfaces, InvocationHandler h) 

这个方法去获取Proxy对象(Proxy 类类型的实例)。
注意到 Proxy.newProxyInstance 这个方法,它需要传入 3 个参数。解析如下:

// 第一个参数,是类的加载器
// 第二个参数是委托类的接口类型,证代理类返回的是同一个实现接口下的类型,保持代理类与抽象角色行为的一致
// 第三个参数就是代理类本身,即告诉代理类,代理类遇到某个委托类的方法时该调用哪个类下的invoke方法
Proxy.newProxyInstance(Class loader, Class<?>[] interfaces, InvocationHandler h)

再来看看 invoke 方法,用户调用代理对象的什么方法,实质上都是在调用处理器的invoke 方法,通过该方法调用目标方法,它也有三个参数:

// 第一个参数为 Proxy 类类型实例,如匿名的 $proxy 实例
// 第二个参数为委托类的方法对象
// 第三个参数为委托类的方法参数
// 返回类型为委托类某个方法的执行结果
public Object invoke(Object proxy, Method method, Object[] args)

开始买果酱
目标类:

//苹果果酱工厂
public class AppleFactory implements Jam {
    @Override
    public int sellJam(int number) {
        //返回工厂价格
        return 5*number;
    }
}
//草莓果酱工厂
public class StrawberryFactory implements Jam {
    @Override
    public int sellJam(int number) {
        //返回工厂价格
        return 10*number;
    }
}

代理

public class MerchantHandler implements InvocationHandler {
    //创建一个工厂,是什么工厂并不知道
    private Object factory = null;

    public MerchantHandler(Object factory) {
        this.factory = factory;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //向工厂下单,返回工厂价
        int factoryMoney = (int) method.invoke(factory, args);

        //收取辛苦费
        int money = factoryMoney+10;
        return money;
    }
}

顾客下单

public class Client {
    public static void main(String[] args) {
        //获取目标类对象:需求是啥?要草莓果酱和苹果果酱,
        Jam strawberry = new StrawberryFactory();
        Jam apple = new AppleFactory();
        //引入MerchantHandler,需求告诉handler
        MerchantHandler strawberryHandler = new MerchantHandler(strawberry);
        MerchantHandler appleHandler = new MerchantHandler(apple);
        //获取代理对象
        Jam sProxy = (Jam) Proxy.newProxyInstance(strawberry.getClass().getClassLoader(),
                strawberry.getClass().getInterfaces(), strawberryHandler);
        Jam aProxy = (Jam) Proxy.newProxyInstance(apple.getClass().getClassLoader(),
                apple.getClass().getInterfaces(),appleHandler);
        //调用方法
        int sMoney = sProxy.sellJam(10);
        int aMoney = aProxy.sellJam(10);

        System.out.println("10罐草莓果酱的价格是"+sMoney);
        System.out.println("10罐苹果果酱的价格是"+aMoney);

    }
}

执行结果

10罐草莓果酱的价格是110
10罐苹果果酱的价格是60

Process finished with exit code 0

java | 什么是动态代理? - JavaFish的文章 - 知乎
https://zhuanlan.zhihu.com/p/65501610

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值