代理模式
可以通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。
静态代理
缺点
- 冗余:代理对象需要实现和目标对象一致的接口。
- 扩展性:一旦接口新增方法,代理对象也需要更新。
// 1. 定义接口
public interface Calculator {
int add(int a, int b);
}
// 2. 真实实现类
public class RealCalculator implements Calculator {
@Override
public int add(int a, int b) {
return a + b;
}
}
// 3. 静态代理类
public class CalculatorStaticProxy implements Calculator {
private final Calculator real; // 持有真实对象
public CalculatorStaticProxy(Calculator real) {
this.real = real;
}
@Override
public int add(int a, int b) {
// 前置操作
System.out.println("【StaticProxy】准备计算:" + a + " + " + b);
// 调用真实对象的方法
int result = real.add(a, b);
// 后置操作
System.out.println("【StaticProxy】计算完毕,结果:" + result);
return result;
}
}
// 4. 客户端调用
public class Client {
public static void main(String[] args) {
Calculator realCalc = new RealCalculator();
Calculator proxyCalc = new CalculatorStaticProxy(realCalc);
int sum = proxyCalc.add(3, 5);
// 控制台输出:
// 【StaticProxy】准备计算:3 + 5
// 【StaticProxy】计算完毕,结果:8
}
}
动态代理
- 使用JDK API反射实现
- 无需手动编写代理类,由InvocationHandler处理
- 用了反射,性能略低
- 扩展性好,新增功能不用更改代理类
- 常用于AOP,权限校验,日志等场景。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 1. 业务接口及实现(同静态代理示例中的 Calculator & RealCalculator)
// 2. 自定义 InvocationHandler
public class CalculatorDynamicHandler implements InvocationHandler {
private final Object target; // 真实对象
public CalculatorDynamicHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置操作
System.out.println("【DynamicProxy】调用前:" + method.getName() + ", 参数:" + args[0] + ", " + args[1]);
// 反射调用真实对象的方法
Object result = method.invoke(target, args);
// 后置操作
System.out.println("【DynamicProxy】调用后,结果:" + result);
return result;
}
}
// 3. 客户端生成并使用代理
public class Client {
public static void main(String[] args) {
Calculator realCalc = new RealCalculator();
// 动态生成代理对象
Calculator proxyCalc = (Calculator) Proxy.newProxyInstance(
realCalc.getClass().getClassLoader(),
new Class<?>[]{Calculator.class},
new CalculatorDynamicHandler(realCalc)
);
int sum = proxyCalc.add(7, 2);
// 控制台输出:
// 【DynamicProxy】调用前:add, 参数:7, 2
// 【DynamicProxy】调用后,结果:9
}
}
- CGLIB代理:不依赖接口,直接对类进行代理,但是目标被代理类以及方法,不能为final。