JDK动态代理

要知道动态代理,首先要知道代理模式。

代理模式下,有两个角色,核心任务的完成者叫做委托类,另一个叫做代理类。委托类的“能力”封装成接口,而代理类实现了委托类的所有接口,表示代理类和委托类具有相同的能力,代理类可以为委托类代理完成所有业务,但核心业务还是委托类完成。

代理模式分为两种,静态代理以及动态代理。

动态代理就好比一个万能的工具人,啥都能干,卖手机,卖汽车,买房…,只要有委托类将任务交给代理类代理,它就能干。动态代理相较于静态代理只能代理已知功能,灵活性更高。不需要像静态代理一样,一个功能就需要编写一个代理类,从而简化了代码(能少写点是点)。

动态,基于 java 的反射机制。JDK动态代理,是 java 基于一个实现了 InvocationHandler 接口的辅助类,为委托类动态生成一个代理类。

编写辅助类

InvocationHandler 接口中只声明了一个 invoke 方法。当我们获得到动态生成的代理类后,调用代理类的方法,会跳转进 invoke 方法,在委托类方法的基础上实现代理功能。

invoke 方法需要三个参数

  1. proxy 调用方法的代理对象
  2. 代理类调用的方法
  3. 调用方法时传入的参数

2,3较好理解,随着代理类调用的方法不同而改变,但为什么要代理对象参数呢?

原因是如果在代理功能中,需要调用代理对象的其他方法,传入的代理对象就起到了作用。

public class ProxyHandler implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("begin");//代理类完成其他功能
        Object invoke = method.invoke(this.object, args);//委托类完成核心功能
        return invoke;
    }
}

既然要为一个委托类动态生成对应的代理类,那么必须让辅助类知道要为谁生成代理类。即在辅助类中声明一个委托类的成员变量。但无从得知委托类是哪种类型,所以声明委托类成员变量为 Object 类型。

public class ProxyHandler implements InvocationHandler {
    //委托类
    private Object object = null;
	//绑定委托类
    public Object bind(Object object) {
        this.object = object;
        return Proxy.newProxyInstance(...);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("begin");//代理类完成其他功能
        Object invoke = method.invoke(this.object, args);//委托类完成核心功能
        return invoke;
    }
}

在方法中我们绑定了委托类,下一步就要为委托类动态生成一个代理类并返回。这里需要用到 Java 反射包中的 Proxy 类。

//委托类
private Object object = null;
//绑定委托类
public Object bind(Object object) {
    this.object = object;
    return Proxy.newProxyInstance(...);
}

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException
{

newProxyInstance 方法需要传入三个参数。

  1. ClassLoader 当生成一个动态代理类后,需要通过 ClassLoader 将代理类加载进 JVM。
  2. interfaces 委托类的接口,生成的动态代理类需要实现委托类的所有接口,以具有相同的“能力”。
  3. InvocationHandler 辅助类实例,当代理类调用方法时,会根据现在传入的辅助类实例,寻找类中实现的 invoke 方法,完成代理功能。

参数1:类加载器从哪里获取呢?很简单,因为所有类都是通过类加载器加载进 JVM 的,反之可以通过任何一个类去获取类加载器。

参数2:委托类实现的接口,可以通过已绑定的委托类,获取实现的接口。

public class ProxyHandler implements InvocationHandler {

    private Object object = null;

    public Object bind(Object object) {
        this.object = object;
        return Proxy.newProxyInstance(ProxyHandler.class.getClassLoader(),object.getClass().getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("begin");
        Object invoke = method.invoke(this.object, args);
        return invoke;
    }
}

编写测试类

//卖水果
public interface Fruit {
    String saleFruit();
}

public class Banana implements Fruit {
    @Override
    public String saleFruit() {
        return "卖香蕉";
    }
}

public class Orange implements Fruit {
    @Override
    public String saleFruit() {
        return "卖橙子";
    }
}

//卖车
public interface Car {
    String saleCar();
}

public class BMW implements Car {
    @Override
    public String saleCar() {
        return "销售宝马";
    }
}

public class Benz implements Car {
    @Override
    public String saleCar() {
        return "销售奔驰";
    }
}
public class Test1 {
    public static void main(String[] args) {
        //创建委托类
        Car car = new Benz();
        Fruit fruit = new Orange();
        //创建辅助类
        ProxyHandler proxyHandler = new ProxyHandler();
        //绑定委托类,获得动态代理类
        Fruit fruitProxy =(Fruit) proxyHandler.bind(fruit);
        System.out.println(fruitProxy.saleFruit());
        Car carProxy = (Car) proxyHandler.bind(car);
        System.out.println(carProxy.saleCar());
    }

}

对测试类进行Debug,查看程序运行流程

第一步:绑定委托类

在这里插入图片描述

第二步:返回动态生成代理类

在这里插入图片描述

第三步:调用代理方法

在这里插入图片描述

debug 过程中发现动态代理类的类名前带有一个 “$” 符,易知它代表了当前类是动态的。

第四步:寻找 invoke 方法,完成代理功能
在这里插入图片描述

输出了 “begin” ,可以看见当前 method 为 saleFruit 方法,object 为 Orange 实例。

第五步:由委托类完成核心功能
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值