代理模式

代理模式

静态代理

静态代理模式的角色:

  • 抽象角色:一般使用接口或实现类类解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理角色会增加一些附属操作
  • 客户:访问代理对象的人

静态代理的实现:真实角色、代理角色继承(实现)抽象角色;代理角色中拥有真实角色;真实角色的业务方法被代理角色调用(代理角色可以扩展功能);客户通过访问代理角色来间接访问真实角色;

代理模式的好处:

  1. 使真实角色更加纯粹,专注自身的业务,而不同考虑一些公共的业务
  2. 公共业务交给代理对象!实现了业务的分工!
  3. 对于扩展业务使用扩展代理类中的业务即可!方便几种管理!

静态代理的缺点:

  • 一个真实对象就会产生一个代理对象;增加了代码量!

动态代理可以解决代码量增加的问题,因为动态代理使用了反射机制!静态代理一个真实类就要写一个代理类对应;使用动态代理可以不写代理类,使用调用处理程序生成任意真实类的代理类!

  • 动态代理的代理类是动态生成的,不是我们直接写的。

在这里插入图片描述

这样使用代理完成横向开发,可以实现不修改原有代码增加新的业务!

例如:淘宝代理商家卖东西

public interface Sell {
    public void putaway();
}
public class Merchant implements Sell {
    private int n;

    public void putaway(){
        System.out.println("商家上架商品");
    }
}
public class TaoBao implements Sell {
    private Sell sell;

    public TaoBao(Sell sell){
        this.sell = sell;
    }

    public void setSell(Sell sell) {
        this.sell = sell;
    }

    @Override
    public void putaway() {
        System.out.println("淘宝进行代理");
        sell.putaway();
    }
}
public class Client {
    public static void main(String[] args) {
        Merchant merchant = new Merchant();
        TaoBao taoBao = new TaoBao(merchant);
        taoBao.putaway();
    }
}

动态代理

从上述代码可以看出每次写一个真实类就必须再写一个代理类,如果真实类特别多的话代码量就非常大!那么有没有一个方法可以自动的根据真实类(真实接口)创建一个代理类呢?动态代理可以解决这个问题!

静态代理一个真实类就要写一个代理类对应;使用动态代理可以不写代理类,使用调用处理程序生成任意真实类的代理类!

动态代理使用反射机制实现,所以不需要增加代码!

  • 动态代理和静态代理的角色相同

  • 动态代理的代理类是动态生成的,不是我们直接写好的

  • 动态代理分为两类:基于接口的动态代理;基于类的动态代理。

    • 基于接口:JDK的动态代理
    • 基于类: cglib
    • Java字节码实现:javasist(第三种)

实现动态代理需要了解两个类:Proxy(代理)、InvocationHandler(调用处理程序)

注意!处理程序并不是代理类,而是用处理程序生成一个代理类!(InvocationHandler决定了代理类是的行为)。而Proxy可以生成代理对象!(代理对象是根据代理类生成的,而代理类是通过调用处理程序生成的)

动态代理的好处:

  1. 使真实角色更加纯粹,专注自身的业务,而不同考虑一些公共的业务
  2. 公共业务交给代理对象!实现了业务的分工!
  3. 对于扩展业务使用扩展代理类中的业务即可!方便几种管理!
  4. 一个动态代理类代理的是一个接口,一般就是对应的一类业务
  5. 一个动态代理类可以代理多个类,只要是实现类同一个接口即可!

例如:我需要一个咸鱼代理卖牛肉的商家,又要一个咸鱼代理买牛肉的买家。(如果使用静态代理我们需要分别写两个代理类,因为两个真实类的实现接口不同)

public interface Buy {
    void buy();
    void wobuy();
}

public class BuyImpl implements Buy{
    @Override
    public void buy() {
        System.out.println("我是买牛肉的");
    }

    @Override
    public void wobuy() {
        System.out.println("hahahaha");
    }
}
public interface Sell {
    void sell();
}

public class SellImpl implements Sell{
    @Override
    public void sell() {
        System.out.println("我是卖牛肉的");
    }
}
public class ProxyInvocationHandler implements java.lang.reflect.InvocationHandler {
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object invoke = method.invoke(target, args);
        this.dosome(method.getName());
        return invoke;
    }
    /*
    InvocationHandler是一个调用处理程序,实现了这个就实现了代理类的模板
    其中invoke方法是调用方法,其作用是根据真实类的每一个方法生成代理类,如果代理类有些额外业务的话可以放到invoke方法中。method.getName()可以获得方法的名称,可以根据方法的名字做对应的业务。
    Proxy.newProxyInstance是根据调用处理程序以及真实类的接口生成代理对象的。
    1.真实对象传入调用处理类
    2.invoke方法根据真实对象,构造对应的代理类的功能
    3.proxy通过调用处理类与真实对象生成代理对象
    */

    public void dosome(String s){
        if ("sell".equals(s)){
            System.out.println("咸鱼代理的卖家");
        }else if ("buy".equals(s)){
            System.out.println("咸鱼代理的买家");
        }
    }
}
public class Test {
    public static void main(String[] args) {
        Buy buy = new BuyImpl();
        Sell sell = new SellImpl();
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        pih.setTarget(buy);
        Buy proxy1 = (Buy) pih.getProxy();
        proxy1.buy();
        proxy1.wobuy();

        pih.setTarget(sell);
        Sell proxy = (Sell) pih.getProxy();
        proxy.sell();
    }
}
结果:
我是买牛肉的
咸鱼代理的买家
hahahaha
我是卖牛肉的
咸鱼代理的卖家
  • InvocationHandler是一个调用处理程序,实现了这个就实现了代理类的模板
    其中invoke方法是调用方法,其作用是根据真实类的每一个方法生成代理类,如果代理类有些额外业务的话可以放到invoke方法中。method.getName()可以获得方法的名称,可以根据方法的名字做对应的业务。Proxy.newProxyInstance是根据调用处理程序以及真实类的接口生成代理对象的。
  1. 真实对象传入调用处理类

  2. invoke方法根据真实对象,构造对应的代理类的功能

  3. proxy通过调用处理类与真实对象生成代理对象

再理解

public class ProxyInvocationHandler implements java.lang.reflect.InvocationHandler {
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object invoke = method.invoke(target, args);
        this.dosome(method.getName());
        return invoke;
    }

    public void dosome(String s){
        if ("sell".equals(s)){
            System.out.println("咸鱼代理的卖家");
        }else if ("buy".equals(s)){
            System.out.println("咸鱼代理的买家");
        }
    }
}
  1. 首先创建ProxyInvocationHandler对象,然后调用setTarget将真实对象放入调用处理类中。这样调用处理程序才知道真实对象是谁
  2. 调用getProxy后,会根据代理类的静态方法生成一个代理对象。因为是静态方法所以并不知道哪个是代理调用处理类,哪个是真实类,又使用的哪个类加载器。所以需要传入这些参数。
  3. 在newProxyInstance方法中获取调用对象(传进入的哪个this)的类对象的所有方法(getDeclaredMethods)调用调用对象的invoke方法将每个method遍历调用一遍。 所以你可以看到加上dosome方法其代理类的每个方法都会调用一遍,因为每个Method都被同一个invoke方法使用,invoke方法相同所以每次都会调用dosome,可以根据方法名分别做每个方法相应的扩展业务!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值