代理模式是一种结构型设计模式,它允许通过代理对象控制对真实对象的访问。代理模式在软件开发中经常被使用,以实现额外的功能或控制对对象的访问
在代理模式中,有三个主要角色:
1.真实对象(Real Object):它是代理模式中实际执行业务逻辑的对象。代理模式的目标是控制对真实对象的访问,而真实对象是代理的实际工作对象。
2.代理对象(Proxy Object):它持有对真实对象的引用,并提供与真实对象相同的接口,以便在需要时可以代替真实对象。代理对象可以在调用真实对象之前或之后执行额外的操作,从而实现对真实对象的控制。
3.客户端(Client):它通过代理对象来访问真实对象,并执行相应的操作。客户端只需要知道代理对象的接口,而不需要直接访问真实对象。
代理模式的主要优点包括:
代理模式可以提供额外的功能,例如在访问真实对象之前或之后执行日志记录、权限检查、缓存等操作。
- 代理模式可以实现对真实对象的保护,控制客户端对真实对象的直接访问。
- 代理模式可以实现延迟加载(Lazy Loading),即在需要时才创建真实对象,从而提高系统的性能和资源利用率。
代理模式的一些常见应用场景包括:
- 远程代理(Remote Proxy):用于在不同的地址空间中访问远程对象,例如远程方法调用(Remote Method Invocation)。
- 虚拟代理(Virtual Proxy):用于延迟加载大对象,以减少系统启动时间和内存消耗。
- 安全代理(Protection Proxy):用于控制对对象的访问权限,例如在访问敏感信息时进行身份验证。
- 缓存代理(Caching Proxy):用于缓存对象的结果,以提高系统的性能。
这里介绍一下以基于使用Java java.lang.reflect.Proxy;的动态代理设计
Car类
public class Car implements Vehicle{
@Override
public void run() {
System.out.println("Car is running");
}
}
上层接口类
public interface Vehicle {
void run();
}
代理类
private Vehicle vehicle;//表示真正执行的对象,提供给目标使用
public VehicleProxyProvider(Vehicle vehicle) {
this.vehicle = vehicle;
}
public Vehicle getProxy() {
/**
* public static Object newProxyInstance(ClassLoader loader,
* Class<?>[] interfaces,
* InvocationHandler h)
* @return
*/
//获取类加载器-》代理类的类加载器
ClassLoader classLoader =
vehicle.getClass().getClassLoader();
// 2.获取接口类型数组, 为什么是接口信息,而不是方法,是因为我们都是走接口的.
Class<?>[] interfaces =
vehicle.getClass().getInterfaces();
//创建InvocationHandler对象,InvocationHandler是接口不能直接创建
//需要使用内部类
// 3. 创 建 InvocationHandler 对 象 - 以 匿 名 内 部 类 的 方 式 方 式 来 获 取
//这个对象有一个方法是 invoke 到时可以通过反射,动态调用目标对象的方
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
System.out.println("开始执行代理对象方法...");
//method:是public abstract void com.klame.Aop1.Vehicle.run()
Object result = method.invoke(vehicle, args);
System.out.println("代理对象方法执行结束...");
return result;
}
};
//newProxyInstance可以返回一个代理对象,代理对象可以实现接口,也可以继承类
//ClassLoader loader:类的加载器
//Class<?>[] interfaces:代理对象实现的接口
//InvocationHandler h:代理对象的方法被调用时,会触发执行h的invoke方法
Vehicle proxy = (Vehicle) Proxy.newProxyInstance(classLoader, interfaces,
invocationHandler);
return proxy;
}
}
测试类
public class TestVehcle {
@Test
public void testVehicle() {
Vehicle vehicle = new Car();
VehicleProxyProvider vehicleProxyProvider =
new VehicleProxyProvider(vehicle);
Vehicle proxy = vehicleProxyProvider.getProxy();
System.out.println("proxy 编译类型是 Vehicle");
System.out.println("proxy 运行类型" + proxy.getClass());
proxy.run();
//执行的是代理对象的public Object invoke(Object proxy, Method method,
// Object[] args)方法,不会执行Car的run方法。
}
}
- proxy 运行类型是 com.sun.proxy.$Proxy0 该类型被转型成 Vehicle因此可以调用 Vehicle 的接口方法
- 当执行 run() 的时候会调用, 根据 Java 的动态绑定机制, 这时直接调用 Car
的 run(),而是 proxy 对象的 invocationHandler 的 invoke 方法 - invoke 方法使用反射机制来调用 run()方法注意这个 run 方法也可以是
Vehicle 的其它方法),这时就可以在调用 run()方法前,进行前置处理和后置处理 - 也就是说 proxy 的 target_vehicle 运行类型只要是实现了 Vehicle 接口 ,就可以去调用不同的方法, 是动态的,变化的,底层就是 使用反射完成的.