就是让代理角色帮助真实角色完成一件事情。比如说,我叫我们朋友帮我完成博客,那么这个朋友就是代理,朋友不是我,但是和我完成同样的事,并且还可以对这件事加入他的行为逻辑。
不论是什么代理方法,其根本目的就是为了拓展一个类的方法,也就是想要加入自己的行为逻辑。
当然,我们可以直接修改类的方法,但是一旦类的方法多了起来,就会造成代码的冗余,而且极难进行维护。
静态代理相当于是多写了一个代理类,在调用的时候调用的是代理类,在代理类中的处理还是原生的处理逻辑,不过在前后添加上需要添加的代码。
其最根本的特征就是这个代理类需要程序员自己写出来。即在编译阶段就确定了代理对象是谁。
我们编写如下的测试案例:
public class StaticProxyTest {
@Test
public void Test01() {
Vehicle proxyForCar = new ProxyForCar(new Car());
proxyForCar.run("托马斯");
proxyForCar.fly("托马斯");
}
}
编写接口:
public interface Vehicle {
public void run(String s);
public void fly(String s);
}
解读:
public class Car implements Vehicle {
@Override
public void run(String name) {
System.out.println(name + "is running");
}
@Override
public void fly(String name) {
System.out.println(name + "is flying");
}
}
编写代理类:
public class ProxyForCar implements Vehicle {
Vehicle vehicle;
public ProxyForCar(Vehicle vehicle) {
this.vehicle = vehicle;
}
@Override
public void run(String arg) {
System.out.println("before invoke...");
vehicle.run(arg);
System.out.println("after invoke...");
}
@Override
public void fly(String arg) {
System.out.println("before invoke...");
vehicle.fly(arg);
System.out.println("after invoke...");
}
}
以上就是一个简单的静态代理的实现。可以发现缺点是显然的,静态代理无法实现切面编程,一旦我们需要代理一个新的接口方法,就要重新写一个方法,甚至重新写一个代理类,这样的开销成本无疑是很大的。
于是我们引入了动态代理。
我们这里将主要介绍基于接口实现的 JDK 的动态代理方式。
见名知义,动态即我们不需要在自己写代理类了,而是由 JVM 在运行阶段自动的帮我生成一个代理类,在程序结束的时候自动销毁。优势在于:
编写测试案例:
public class DynamicProxyTests {
@Test
public void Test01() {
Car car = new Car();
VehicleDynamicProxy vehicleDynamicProxy = new VehicleDynamicProxy(car);
Vehicle proxy = vehicleDynamicProxy.getProxy();
String fly = proxy.fly(10000);
System.out.println("result:\t" + fly);
}
}
编写接口:
public interface Vehicle {
public String fly(int height);
public void run();
}
实现类 ship :
public class Ship implements Vehicle {
@Override
public String fly(int height) {
System.out.println("wdnmd");
return "ship 的高度为" + height;
}
@Override
public void run() {
System.out.println("ship 在run");
}
}
实现类 Car:
public class Car implements Vehicle{
@Override
public String fly(int height) {
System.out.println("wdnmdCar");
return "car 的高度为" + height;
}
@Override
public void run() {
System.out.println("car 在run");
}
}
动态代理类:
public class VehicleDynamicProxy {
/**
* 被代理对象
*/
public Vehicle targetVehicle;
public VehicleDynamicProxy(Vehicle targetVehicle) {
this.targetVehicle = targetVehicle;
}
public Vehicle getProxy() {
//获取类的加载器
ClassLoader classLoader = targetVehicle.getClass().getClassLoader();
//获取类的接口数组
Class<?>[] interfaces = targetVehicle.getClass().getInterfaces();
//调用函数,用来的调用方法
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
try {
System.out.println("前置通知 before");
//调用被代理对象的方法
result = method.invoke(targetVehicle, args);
System.out.println("返回通知 afterReturning");
} catch (Exception e) {
//异常通知 AfterThrowing
throw new RuntimeException(e);
} finally {
//最终通知 After }
return result;
}
};
//此时的proxy对象是实现了Vehicle接口,继承了Proxy类的代理对象
Vehicle proxy = (Vehicle) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
return proxy;
}
}
解读:
接下来,我们将从源码的角度,详细的看看 JDK 动态代理的机制。
我们再抛出一个问题,那就是为什么在生成代理对象的时候一定要传入接口数组呢?似乎没有接口,我们也可以通过反射,来转发方法的执行。
【源码解析】JDK 动态代理实现 - yelanyanyu - 博客园 (cnblogs.com)