Java动态代理解决的是什么问题?

一.
动态代理指利用反射去获取和调用目标类的方法。

为什么要代理?
如果A类要去调用C类的方法,但是C类拒绝让A类调用,但同意让B类去调用,那么我们的A类就可以通过B类去调用C的方法。 此时的B类就是C类(目标类)的代理对象

通俗来讲就是 我是厂长卖cpu的,如果一个人要来我这里买个cup那我肯定是拒绝的(量小瞧不上=.=),但是可以通过我旗下的代理商购买这款cpu(代理商每次都从我这里进购大量的货)。

此时代理商就扮演了重要的作用。

所谓代理无非就是类似中介,中间人,媒婆等角色。当你想要某种服务的时候 又没办法直接联系提供服务的人的时候,就可以找中介(目标类的代理对象)

二. 代理分静态代理和动态代理。
假如我是制造cpu的大厂,我旗下的代理商有 某bao,某wei,某duo,某yu等。
然后一个cup购买者想要购买cpu,那么他可以通过代理商购买;

静态代理:首先我这个厂C是卖cpu的吧,所以他需要有卖cpu的方法。不妨叫sellCPU();
此时代理商B也是要卖cpu的吧,所以他也同样要有sellCPU() 方法;只不过代理商的sellCPU()方法的内部是通过持有对象A并且调用A的sellCPU(),并且扩展了一些新的功能(比如我加价,在工厂的销售价格上再加钱)
由于代理商和厂家有相同的方法,那么我们可以直接把这个方法封装为接口

根据上述来实现一下代码:
Sell接口:

public interface Sell {
    
    
    int sellCPU(int count);
}

CPU工厂类:

public class BigCPUFactory implements Sell{
    
    
    @Override
    public int sellCPU(int count) {
    
    
        return 2 * count;
    }
}

MouBao代理商

public class MouBao implements Sell{
    
    
    BigCPUFactory factory;
    public MouBao(BigCPUFactory factory) {
    
    
        this.factory = factory;
    }
    @Override
    public int sellCPU(int count) {
    
    
        int allMoney = factory.sellCPU(count);
        System.out.println("我是MouBao代理商,每件我还要再加2块钱");
        allMoney += 2*count;
        return allMoney;
    }
}

MouDuo代理商

public class MouDuo implements Sell{
    
    
    BigCPUFactory factory;
    public MouDuo(BigCPUFactory factory) {
    
    
        this.factory = factory;
    }    
    @Override
    public int sellCPU(int count) {
    
    
        int allMoney = factory.sellCPU(count);
        System.out.println("我是MouDuo代理商,每件我还要再加1块钱");
        allMoney += count;
        return allMoney;
    }
}

cpu消费者:


public class CPUConsumer {
    
    
    public static void main(String[] args) {
    
    
        System.out.println("========我要买5个CPU======");
        MouBao mouBao = new MouBao(new BigCPUFactory());
        MouDuo mouDuo = new MouDuo(new BigCPUFactory());
        int money = mouBao.sellCPU(5);
        System.out.println("=========通过MouBao买5个CUP花了: " + money);
        money = mouDuo.sellCPU(5);
        System.out.println("=========通过MouBao买5个CUP花了: " + money);
    }
}

在这里插入图片描述

说说静态代理的好处:

  1. 实现简单,代码清晰,逻辑简单

缺点:

  1. 类与接口之间的耦合度太高。
    假如我的Factory要卖的东西变多了,即Sell接口(代理商和目标类的共有方法)也会发生改变,那么我的所有代理商类就都要修改代码。 假如我的代理商跑满全球,那么代码要改到吐。

此时我们就会想,有没有一种方法可以不写各种代理类,但是可以实现代理类的对象呢?

当然是可以的。 就是java的动态代理,实现的原理就是反射机制。

这里说一下jdk动态代理的实现(利用proxy这个类)。

  1. 写一个实现InvocationHandler类
  2. 重写invoke方法
  3. 利用Proxy的静态类newProxyInstance方法创建并强转为目标类方法所属的接口类,
  4. 利用强转后的对象调用 目标类的方法

例:
Sell类

public interface Sell {
    
    
    int sell(int count);
}

MyInvocationHander类

public class MyInvocationHander implements InvocationHandler {
    
    

    Object target; //传入的目标类(这里指哪些厂)
    public MyInvocationHander(Object target) {
    
    
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        int money = (Integer) method.invoke(target, args);
        money += 10;
        return money;
    }
}

CPUFactory

public class CPUFactory implements Sell{
    
    

    @Override
    public int sell(int count) {
    
    
        return 2 * count;
    }
}

Consumer:

public class Consumer {
    
    
    public static void main(String[] args) {
    
    
//        SellSomething factory = new UsbFactory();
        CPUFactory factory = new CPUFactory();
        InvocationHandler hander = new MyInvocationHander(factory);
        Sell proxy = (Sell) Proxy.newProxyInstance(factory.getClass().getClassLoader(), factory.getClass().getInterfaces(), hander);
   //通过Proxy的静态方法来创建代理对象,并强转成目标类方法所属的接口类,这里是Sell       
        int money = proxy.sell(2);
        System.out.println("通过动态代理买到2个CPU的花费为:  " + money);
    }
}

在这里插入图片描述
jdk提供的动态代理主要依靠java.lang.reflect包
里面有三个类
1.InvocationHandler接口,只包括一个方法 invoke()
这个方法是 我们这个代理对象要实现的具体逻辑代码,如上面写的

public class MyInvocationHander implements InvocationHandler {
    
    

    Object target; //传入的目标类(这里指哪些厂)
    public MyInvocationHander(Object target) {
    
    
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        int money = (Integer) method.invoke(target, args);
        money += 10;
        return money;
    }
}

invoke携带三个参数:

  1. proxy是jdk创建的代理对象,无需赋值
  2. method是通过反射获取到的目标类中的Method(方法)对象,
    Method的使用是 method.invoke(目标类,参数)-- 具体可以学习java反射
  3. args是目标类中方法所需要的参数

聊聊动态代理的好处:

  1. 我们的invocationHandler不用实现接口,也就意味着不像静态代理一样需要写很多的代理实现类,当接口改变的时候,影响的也只有我们的Factory,大范围缩小了改动
  2. 很多都是固定写法,写熟了就很快

因此回归主题,java动态代理解决的是类爆炸(很多类)后的扩展性问题。即不用写太多代理类,改动的时候我们只需要改动Factory类就可以了。 即解决了静态代理带来的坏处

猜你喜欢

转载自blog.csdn.net/XJ200012/article/details/127587820