定义
给目标对象一个代理对象,并由代理对象控制对目标对象的引用。联想到生活中就像是海外代购
既然是代理,就说明他要做的事情要比你直接去做要做的多,这就联系到了方法的增强,也就联系到了AOP,面向切面。简单讲就是:继承这个体系相当于是纵向,而AOP相当于是横向。但是java自带的增强只能增强接口中的方法,服务器开发中spring对这点做的很好,无论是不是接口方法都可以对其进行增强。在Android中可以考虑使用cglib,这里暂不讨论。
这里以一个汽车的启动过程为实例来讲解java的代理:
public interface ICar {
//汽车启动
void start();
//汽车运行
void run();
//汽车停止
void stop();
}
//创建汽车的实现类
public class CarImpl implements ICar {
@Override
public void start() {
System.out.println("CarImpl start");
}
@Override
public void run() {
System.out.println("CarImpl run");
}
@Override
public void stop() {
System.out.println("CarImpl stop");
}
}
//创建测试类
public static void main(String[] args) {
CarImpl car = new CarImpl();
car.start();
car.run();
car.stop();
}
以上类的创建便完成了一个汽车从启动到停止的一个模拟过程,这是思考一个问题,在汽车启动的时候需要先检查车,在启动成功了之后要提醒司机注意天气,那么在现有的逻辑上怎么处理?这里给出两种解决办法,1.可以采用装饰者模式对汽车的实现类进行包装。2.因为start是接口方法,可以采用java的动态代理
- 可以采用装饰者模式对汽车的实现类进行包装
public class CarImplWrapper implements ICar {
private ICar car;
public CarImplWrapper(ICar car) {
this.car = car;
}
@Override
public void start() {
System.out.println("先检查车");
car.start();
System.out.println("请注意天气");
}
@Override
public void run() {
car.run();
}
@Override
public void stop() {
car.start();
}
}
public static void main(String[] args) {
CarImpl car = new CarImpl();
//装饰者模式增强方法
CarImplWrapper wrapper = new CarImplWrapper(car);
wrapper.start();
wrapper.run();
wrapper.stop();
}
采用上述方法,的确满足了我们的要求,在汽车启动前进行汽车的检查,启动成功后提醒司机注意天气,但是如果汽车的启动过程设计的过多的时候,也就是我们的接口中的方法过多的时候,采用对实现类进行包装的话那么接口中的每个方法都要在包装类里面进行调用。为解决这个问题,我们可以采用java中的反射类里面的Proxy类来进行解决
- 采用Java的动态代理
public static void main(String[] args) {
CarImpl car = new CarImpl();
wrapper.start();
wrapper.run();
wrapper.stop();
//利用反射里面的动态代理增强方法
ICar iCar = (ICar) Proxy.newProxyInstance(car.getClass().getClassLoader(), car.getClass().getInterfaces(), (proxy, method, args1) -> {
if (method.getName().equalsIgnoreCase("start")){
System.out.println("代理增强1");
method.invoke(car, args1);
System.out.println("代理增强2");
return null;
}
return method.invoke(car, args1);
});
iCar.start();
iCar.run();
iCar.stop();
}
Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 第一个参数:因为采用反射,所以需要ClassLoader类,可以采用当前类的classloader也可以采用接口实现类的classloader,第二个参数是接口类的数组,这里一定要使用实现类的接口数组,第三个数组采用内部类形式实现即可,具体使用方式参考上述代码