阶段小结——动态代理

代理模式简介:
简介整理并摘自网络
1. 代理分为静态代理和动态代理。
2. 静态代理:

创建一个接口,然后创建被代理的类实现该接口并且实现该接口中的抽象方法。之后再创建一个代理类,同时使其也实现这个接口。在代理类中持有一个被代理对象的引用,而后在代理类方法中调用该对象的方法。
类和接口都是在程序运行前就定义好了的,使用静态代理很容易就完成了对一个类的代理操作。但是静态代理的缺点也暴露了出来:由于代理只能为一个类服务,如果需要代理的类很多,那么就需要编写大量的代理类,比较繁琐。

  1. 动态代理:

利用反射机制在运行时创建代理类。
接口、被代理类不变,我们构建一个handler类来实现InvocationHandler接口。
动态代理具体步骤:
通过实现 InvocationHandler 接口创建自己的调用处理器;
通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

以下为个人理解
如何实现动态代理?
前置条件:
1. 需要有一个接口类,负责方法的声明
2. 需要有一个目标类,实现接口类中的方法
3. 需要有一个代理类,实现接口InvocationHandler

实例讲解:
例如,我们要实现 销售U盘 的一个功能,其中供应商每个U盘定价85元,代理商会从供应商拿货,并加价25元卖出去。那么根据上面的条件,我们就需要:

  1. 一个接口UsbSell,声明sell方法。`
public interface UsbSell {
    public float sell(int amount);
}
  1. 一个目标类UsbKingFactory,负责初步实现接口中的方法。
// 目标类,实现接口
public class UsbKingFactory implements UsbSell{
    @Override
    public float sell(int amount) {
        return amount * 85.0f;
    }
}
  1. 一个代理类,负责对目标类中方法的 调用 以及 增强
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MySellHandler implements InvocationHandler{
    private Object target;

    // 提供一个构造方法,来接收目标对象target,在本例中传入了对象 factory
    public MySellHandler(Object target) {
        this.target = target;
    }

    // 代理对象的方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 调用目标对象里的方法
        Object result = method.invoke(target,args);
        if(result != null){
            // 代理商从 目标对象 购入U盘后,加价25元
            float price = (float) result;
            price += 25.0 * (int)args[0];
            result = price;
        }
        System.out.println("若出现此语句,表明执行的是MySellHandler中的invoke方法。");
        // 返回处理结果
        return result;
    }
}
  1. 至此,我们还需要有一个Test类来运行测试实际效果。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class MainShop {
    public static void main(String[] args) {
        // 1.创建目标对象
        UsbSell factory = new UsbKingFactory();

        // 2.创建InvocationHandler对象,传入目标对象
        InvocationHandler handler = new MySellHandler(factory);

        // 3.创建代理对象,分别传入 目标对象的类加载器, 目标对象的接口, handler
        // 个人理解:UsbSell proxy = new UsbKingFactory();
        //         故 proxy可以调用 UsbSell 这个接口里的方法
        //         前两个参数指明了目标对象的类加载器和接口
        //         最后一个参数handler指明了要用handler里的invoke方法来代替factory里“任何要被执行“的方法
        UsbSell proxy = (UsbSell) Proxy.newProxyInstance(factory.getClass().getClassLoader(),
                factory.getClass().getInterfaces(),handler);

        // 这里的sell是代理类中的sell,即MySellHandler中的invoke方法
        float price = proxy.sell(2);
        System.out.println("通过动态代理对象,调用方法sell:" + price);
    }
}
  1. 运行效果如下
若出现此语句,表明执行的是MySellHandler中的invoke方法。
通过动态代理对象,调用方法sell:220.0

此时我们已经成功达到了我们预期效果,最后简单总结一下就是,

  1. 首先有一个接口来声明方法,然后目标类去实现这个接口。
  2. 我们另外定义一个handler类,实现InvocationHandler接口,重写invoke方法即可,方法的参数由JDK自动帮我们完成,不需要我们管,我们只需要负责在invoke中将代理类要做的事写上去即可。

例如本例中代理商要从供货商拿货并加价25卖出去,那么最终售卖价格就是,原价+25,那么我们可以首先在Handler类中创建一个代理商对象以及声明一个构造方法,用来接收代理商,然后在invoke中调用代理商实现的sell方法获得其售价,然后我们加上25并return该最终结果出去。

  1. 创建对象传入的参数一般是固定的,例如

UsbSell proxy = (UsbSell)
Proxy.newProxyInstance(factory.getClass().getClassLoader(),
factory.getClass().getInterfaces(),handler);

  1. 另外对于Handler类中invoke参数做一些解释: method指代目标类中执行的方法,我们就是要对该方法进行代理和增强,后面的args就是该方法需要的参数。如下。

// 调用目标对象里的方法
Object result = method.invoke(target,args);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值