要知道动态代理,首先要知道代理模式。
代理模式下,有两个角色,核心任务的完成者叫做委托类,另一个叫做代理类。委托类的“能力”封装成接口,而代理类实现了委托类的所有接口,表示代理类和委托类具有相同的能力,代理类可以为委托类代理完成所有业务,但核心业务还是委托类完成。
代理模式分为两种,静态代理以及动态代理。
动态代理就好比一个万能的工具人,啥都能干,卖手机,卖汽车,买房…,只要有委托类将任务交给代理类代理,它就能干。动态代理相较于静态代理只能代理已知功能,灵活性更高。不需要像静态代理一样,一个功能就需要编写一个代理类,从而简化了代码(能少写点是点)。
动态,基于 java 的反射机制。JDK动态代理,是 java 基于一个实现了 InvocationHandler 接口的辅助类,为委托类动态生成一个代理类。
编写辅助类
InvocationHandler 接口中只声明了一个 invoke 方法。当我们获得到动态生成的代理类后,调用代理类的方法,会跳转进 invoke 方法,在委托类方法的基础上实现代理功能。
invoke 方法需要三个参数
- proxy 调用方法的代理对象
- 代理类调用的方法
- 调用方法时传入的参数
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 方法需要传入三个参数。
- ClassLoader 当生成一个动态代理类后,需要通过 ClassLoader 将代理类加载进 JVM。
- interfaces 委托类的接口,生成的动态代理类需要实现委托类的所有接口,以具有相同的“能力”。
- 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 实例。
第五步:由委托类完成核心功能