目录
- [1. 模式概述](#1. 模式概述)
- [2. 模式结构](#2. 模式结构)
-
- [2.1 UML类图](#2.1 UML类图)
- [2.2 核心角色说明](#2.2 核心角色说明)
- [3. 代理模式实现机制](#3. 代理模式实现机制)
-
- [3.1 静态代理:编译时织入](#3.1 静态代理:编译时织入)
- [3.2 动态代理:运行时织入](#3.2 动态代理:运行时织入)
-
- [3.2.1 JDK动态代理(基于接口)](#3.2.1 JDK动态代理(基于接口))
- [3.2.2 CGLIB 动态代理(基于继承)](#3.2.2 CGLIB 动态代理(基于继承))
- [3.3 代理模式对比分析](#3.3 代理模式对比分析)
- [4. Spring AOP 中的代理实现](#4. Spring AOP 中的代理实现)
-
- [4.1 Spring代理机制概述](#4.1 Spring代理机制概述)
- [4.2 代理选择策略](#4.2 代理选择策略)
- [4.3 切面定义与实现](#4.3 切面定义与实现)
- [5. 模式的优劣分析](#5. 模式的优劣分析)
-
- [5.1 优点](#5.1 优点)
- [5.2 缺点](#5.2 缺点)
- [6. 代理模式的应用场景](#6. 代理模式的应用场景)
-
- [6.1 典型应用场景](#6.1 典型应用场景)
-
- [6.1.1 权限控制与安全代理](#6.1.1 权限控制与安全代理)
- [6.1.2 延迟加载代理(Lazy Loading)](#6.1.2 延迟加载代理(Lazy Loading))
- [6.1.3 远程代理(RPC框架)](#6.1.3 远程代理(RPC框架))
- [6.1.4 缓存代理](#6.1.4 缓存代理)
- [6.1.5 智能引用代理](#6.1.5 智能引用代理)
- [6.2 企业级应用案例](#6.2 企业级应用案例)
- [7. 代理模式的最佳实践](#7. 代理模式的最佳实践)
-
- [7.1 设计原则](#7.1 设计原则)
- [7.2 性能优化策略](#7.2 性能优化策略)
- [7.3 安全实践](#7.3 安全实践)
- 8.代理模式与其他模式对比
-
- [8.1 代理 vs 装饰器模式](#8.1 代理 vs 装饰器模式)
- [8.2 代理 vs 适配器模式](#8.2 代理 vs 适配器模式)
- 9.总结与进阶思考
-
- [9.1 核心总结](#9.1 核心总结)
- [9.2 进阶思考](#9.2 进阶思考)
1. 模式概述
代理模式(Proxy Pattern) 是一种结构型设计模式,通过创建代理对象 控制对真实对象的访问。代理对象充当真实对象的替身,在客户端和真实对象之间引入间接层,实现访问控制、功能增强等目的。这种模式的核心价值在于:
- 访问控制:限制对敏感对象的直接访问
- 功能增强:在不修改原始对象的情况下添加新功能
- 延迟加载:优化资源使用,按需创建昂贵对象
- 简化接口:为复杂系统提供更简洁的访问接口
客户端 代理对象 真实对象
代理模式在企业级开发中应用广泛,如Spring AOP中的事务管理、MyBatis的Mapper接口代理、远程方法调用(RPC)等场景。它遵循开放封闭原则,通过代理类扩展功能而非修改原有类,提高了系统的灵活性和可维护性。
2. 模式结构
2.1 UML类图
<<interface>> Subject +request() : void RealSubject +request() : void Proxy -realSubject: RealSubject +request() : void Client +main() : void
2.2 核心角色说明
| 角色 | 职责 | 实现要点 | 设计原则 |
|---|---|---|---|
| Subject | 定义真实主题和代理主题的共同接口 | 使用接口或抽象类定义 | 接口隔离原则 |
| RealSubject | 实际执行业务逻辑的真实对象 | 包含核心业务逻辑实现 | 单一职责原则 |
| Proxy | 控制对真实主题的访问,提供额外功能 | 持有真实主题的引用 | 开闭原则 |
| Client | 通过代理对象间接访问真实主题 | 无需知道代理存在 | 迪米特法则 |
这种结构分离了核心功能 与附加功能,符合单一职责原则,使得系统更易于扩展和维护。
3. 代理模式实现机制
3.1 静态代理:编译时织入
静态代理是在编译期就已经确定代理关系的实现方式。需要为每个被代理的类创建一个代理类,代理类和目标类实现相同的接口,代理类持有目标类的引用,并在调用目标方法前后执行增强逻辑。
核心特点:
- 编译期确定:代理关系在编译时就已经确定
- 一对一关系:一个代理类对应一个目标类
- 代码冗余:需要为每个目标类编写代理类
- 类型安全:编译期检查,类型安全
实现原理:
- 代理类和真实类实现相同接口
- 代理类持有真实类的引用
- 在代理类方法中添加额外逻辑
适用场景:
- 简单场景:代理逻辑固定且简单的场景
- 性能敏感:对性能要求极高,不能接受动态代理的开销
- 编译期检查:需要严格的编译期类型检查
- 小型项目:项目规模较小,代理类数量可控
java
// 1. 定义服务接口
interface PaymentService {
void processPayment(double amount);
}
// 2. 真实服务实现
class RealPaymentService implements PaymentService {
@Override
public void processPayment(double amount) {
System.out.println("处理支付: $" + amount);
}
}
// 3. 静态代理类
class PaymentProxy implements PaymentService {
private final PaymentService realService;
public PaymentProxy() {
this.realService = new RealPaymentService();
}
@Override
public void processPayment(double amount) {
// 前置增强:验证
validatePayment(amount);
logPayment(amount);
// 委托真实对象
realService.processPayment(amount);
// 后置增强:通知
sendNotification();
}
private void validatePayment(double amount) {
if (amount <= 0) throw new IllegalArgumentException("金额必须大于0");
}
private void logPayment(double amount) {
System.out.println("[LOG] 支付请求: $" + amount);
}
private void sendNotification() {
System.out.println("[NOTIFY] 支付成功通知已发送");
}
}
// 4. 客户端使用
public class Client {
public static void main(String[] args) {
PaymentService service = new PaymentProxy();
service.processPayment(150.0);
}
}
静态代理优缺点分析:
| 优点 | 缺点 |
|---|---|
| ✅ 编译期检查,类型安全 | ❌ 每个服务类需要创建代理类 |
| ✅ 性能接近直接调用 | ❌ 接口变更需修改代理类 |
| ✅ 逻辑清晰,易于理解 | ❌ 代理类数量随服务类增加 |
| ✅ 支持方法级控制 | ❌ 灵活性不足 |
3.2 动态代理:运行时织入
3.2.1 JDK动态代理(基于接口)
JDK动态代理基于接口 和反射 机制,在运行时动态生成代理类。通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口实现,要求被代理对象必须实现至少一个接口。
实现原理:
- 代理类生成:在运行时通过字节码技术生成代理类
- 接口代理:只能代理接口,不能代理类
- 反射调用:通过反射机制调用目标方法
- 处理器机制:通过InvocationHandler统一处理所有方法调用
JDK动态代理特点:
- 只能代理实现了接口的类
- 运行时生成代理类,减少编码量
- 通过反射调用方法,有一定性能开销
- 适合代理接口定义明确的服务
java
import java.lang.reflect.*;
// 1. 调用处理器(性能监控)
class PerformanceMonitor implements InvocationHandler {
private final Object target;
private final Map<String, MethodStats> statsMap = new ConcurrentHashMap<>();
public PerformanceMonitor(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start = System.nanoTime();
// 调用真实方法
Object result = method.invoke(target, args);
long duration = System.nanoTime() - start;
recordMethodStats(method, duration);
return result;
}
private void recordMethodStats(Method method, long duration) {
String methodName = method.getName();
statsMap.compute(methodName, (k, v) -> {
if (v == null) return new MethodStats(methodName, duration);
v.addExecution(duration);
return v;
});
}
public void printStats() {
System.out.println("\n===== 方法性能统计 =====");
statsMap.values().forEach(System.out::println);
}
static class MethodStats {
private final String methodName;
private long count;
private long totalTime;
private long maxTime;
public MethodStats(String methodName, long initialTime) {
this.methodName = methodName;
addExecution(initialTime);
}
public void addExecution(long time) {
count++;
totalTime += time;
if (time > maxTime) maxTime = time;
}
@Override
public String toString() {
return String.format("%s: 调用次数=%d, 平均耗时=%.2fms, 最大耗时=%.2fms",
methodName, count,
(totalTime / 1_000_000.0) / count,
maxTime / 1_000_000.0);
}
}
}
// 2. 客户端使用
public class DynamicProxyClient {
public static void main(String[] args) {
// 创建真实对象
DatabaseService realService = new RealDatabaseService();
// 创建动态代理
DatabaseService proxy = (DatabaseService) Proxy.newProxyInstance(
DatabaseService.class.getClassLoader(),
new Class[]{DatabaseService.class},
new PerformanceMonitor(realService)
);
// 通过代理调用
for (int i = 0; i < 5; i++) {
proxy.executeQuery("SELECT * FROM table_" + i);
}
// 打印性能统计
((PerformanceMonitor) Proxy.getInvocationHandler(proxy)).printStats();
}
}
JDK动态代理优缺点分析:
| 优点 | 缺点 |
|---|---|
| ✅ 一个处理器可以代理多个接口 | ❌ 只能代理接口,不能代理类 |
| ✅ 减少类数量,避免类爆炸 | ❌ 反射调用有性能开销(现代JVM已优化) |
| ✅ 灵活性高,可以动态添加功能 | ❌ 内部方法调用不会被代理 |
| ✅ 与Java标准库集成,无需额外依赖 | ❌ 接口方法必须是public |
性能优化建议:
- 缓存代理类:重复创建代理类开销大,应该缓存
- 避免过度代理:只在必要时使用代理
- 使用Method对象缓存:避免重复获取Method对象
- 考虑使用字节码增强:对性能要求极高的场景
3.2.2 CGLIB 动态代理(基于继承)
CGLIB(Code Generation Library)通过字节码增强技术生成目标类的子类作为代理,不需要接口支持。CGLIB是一个强大的高性能代码生成库,它通过继承目标类并重写方法来实现代理。与JDK动态代理不同,CGLIB不需要目标类实现接口。
核心机制:
- 字节码生成:在运行时通过ASM字节码框架生成目标类的子类
- 方法拦截:通过MethodInterceptor接口拦截方法调用
- FastClass机制:避免反射调用,提高性能
- 回调过滤器:支持对不同方法使用不同的拦截策略
实现原理:
- 使用Enhancer类创建代理
- 实现MethodInterceptor接口处理调用
- 生成目标类的子类作为代理类
依赖配置
xml
<!-- Maven依赖 -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
代码实现
java
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* CGLIB动态代理实现
* 方法拦截器示例
*/
public class CglibMethodInterceptor implements MethodInterceptor {
// 目标对象
private final Object target;
public CglibMethodInterceptor(Object target) {
this.target = target;
}
/**
* 创建代理对象
* @param target 目标对象
* @return 代理对象
*/
@SuppressWarnings("unchecked")
public static <T> T createProxy(T target) {
Enhancer enhancer = new Enhancer();
// 设置父类(目标类)
enhancer.setSuperclass(target.getClass());
// 设置回调(拦截器)
enhancer.setCallback(new CglibMethodInterceptor(target));
// 设置回调过滤器(可选)
enhancer.setCallbackFilter(method -> {
// 对不同的方法使用不同的拦截策略
if (method.getName().startsWith("get")) {
return 0; // 使用第一个回调
} else {
return 0; // 默认使用第一个回调
}
});
// 创建代理对象
return (T) enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
String methodName = method.getName();
// 过滤Object类的方法(如toString、hashCode等)
if (method.getDeclaringClass() == Object.class) {
return proxy.invokeSuper(obj, args);
}
// 前置增强
System.out.println("[CGLIB代理] 开始执行方法: " + methodName);
System.out.println("[CGLIB代理] 参数: " + (args != null ? Arrays.toString(args) : "无"));
long startTime = System.nanoTime();
Object result = null;
try {
// 调用目标方法
// 注意:这里使用invokeSuper调用父类(目标类)方法
// 使用invoke会递归调用代理方法,导致栈溢出
result = proxy.invokeSuper(obj, args);
// 返回结果增强
if (result instanceof String) {
result = "[CGLIB增强] " + result;
}
// 后置增强
System.out.println("[CGLIB代理] 方法执行成功: " + methodName);
System.out.println("[CGLIB代理] 返回值: " + result);
} catch (Exception e) {
// 异常增强
System.err.println("[CGLIB代理] 方法执行失败: " + methodName);
System.err.println("[CGLIB代理] 异常信息: " + e.getMessage());
throw e;
} finally {
// 最终增强
long endTime = System.nanoTime();
System.out.println("[CGLIB代理] 方法执行耗时: " + (endTime - startTime) + "ns");
}
return result;
}
}
高级特性实现
java
import net.sf.cglib.proxy.*;
import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 增强型CGLIB代理
* 支持多回调、性能监控等高级功能
*/
public class EnhancedCglibProxy {
private static final ConcurrentHashMap<Class<?>, Object> PROXY_CACHE = new ConcurrentHashMap<>();
private static final AtomicInteger PROXY_COUNTER = new AtomicInteger(0);
/**
* 创建带缓存的代理对象
*/
@SuppressWarnings("unchecked")
public static <T> T createCachedProxy(T target) {
Class<?> targetClass = target.getClass();
// 检查缓存
if (PROXY_CACHE.containsKey(targetClass)) {
return (T) PROXY_CACHE.get(targetClass);
}
// 创建代理
T proxy = createProxy(target);
// 加入缓存
PROXY_CACHE.put(targetClass, proxy);
return proxy;
}
/**
* 创建多回调代理
*/
@SuppressWarnings("unchecked")
public static <T> T createMultiCallbackProxy(T target) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
// 设置多个回调
Callback[] callbacks = new Callback[] {
new LoggingInterceptor(target), // 日志拦截
new SecurityInterceptor(target), // 安全拦截
new PerformanceInterceptor(target), // 性能监控
NoOp.INSTANCE // 直接调用,不拦截
};
enhancer.setCallbacks(callbacks);
// 设置回调过滤器
enhancer.setCallbackFilter(method -> {
String methodName = method.getName();
if (methodName.startsWith("get") || methodName.startsWith("query")) {
return 0; // 使用日志拦截
} else if (methodName.startsWith("add") || methodName.startsWith("update")) {
return 1; // 使用安全拦截
} else if (methodName.startsWith("delete")) {
return 2; // 使用性能监控
} else {
return 3; // 直接调用
}
});
return (T) enhancer.create();
}
// 各种拦截器实现
static class LoggingInterceptor implements MethodInterceptor {
private final Object target;
LoggingInterceptor(Object target) {
this.target = target;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("[日志] 开始执行: " + method.getName());
Object result = proxy.invokeSuper(obj, args);
System.out.println("[日志] 执行完成: " + method.getName());
return result;
}
}
static class SecurityInterceptor implements MethodInterceptor {
private final Object target;
SecurityInterceptor(Object target) {
this.target = target;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("[安全] 权限检查...");
// 实际权限检查逻辑
return proxy.invokeSuper(obj, args);
}
}
static class PerformanceInterceptor implements MethodInterceptor {
private final Object target;
PerformanceInterceptor(Object target) {
this.target = target;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
long startTime = System.nanoTime();
Object result = proxy.invokeSuper(obj, args);
long endTime = System.nanoTime();
System.out.println("[性能] 方法耗时: " + (endTime - startTime) + "ns");
return result;
}
}
@SuppressWarnings("unchecked")
private static <T> T createProxy(T target) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(new CglibMethodInterceptor(target));
return (T) enhancer.create();
}
}
使用示例
java
/**
* 不需要接口的普通类
*/
public class OrderService {
public void createOrder(String orderId, String productName) {
System.out.println("创建订单: " + orderId + ", 产品: " + productName);
// 模拟业务逻辑
try {
Thread.sleep(100); // 模拟耗时操作
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
public String getOrderStatus(String orderId) {
System.out.println("查询订单状态: " + orderId);
return "订单状态: 已发货";
}
public void cancelOrder(String orderId) {
System.out.println("取消订单: " + orderId);
throw new RuntimeException("订单取消失败: 已发货状态不能取消");
}
// final方法不会被代理
public final String getServiceName() {
return "OrderService";
}
// private方法不会被代理
private void internalProcess() {
System.out.println("内部处理逻辑");
}
}
/**
* CGLIB动态代理测试
*/
public class CglibProxyDemo {
public static void main(String[] args) {
System.out.println("=== CGLIB动态代理测试 ===");
// 创建目标对象(不需要接口)
OrderService realService = new OrderService();
// 创建基本代理
System.out.println("\n1. 测试基本CGLIB代理:");
OrderService basicProxy = CglibMethodInterceptor.createProxy(realService);
System.out.println("测试创建订单:");
basicProxy.createOrder("ORD001", "Java编程思想");
System.out.println("\n测试查询订单状态:");
String status = basicProxy.getOrderStatus("ORD001");
System.out.println("增强后的状态: " + status);
System.out.println("\n测试取消订单(异常处理):");
try {
basicProxy.cancelOrder("ORD001");
} catch (Exception e) {
System.err.println("捕获到异常: " + e.getMessage());
}
// 测试final方法
System.out.println("\n测试final方法(不会被代理):");
String serviceName = basicProxy.getServiceName();
System.out.println("服务名称: " + serviceName);
// 验证代理类型
System.out.println("\n2. 代理类型信息:");
System.out.println("代理类: " + basicProxy.getClass().getName());
System.out.println("父类: " + basicProxy.getClass().getSuperclass().getName());
System.out.println("是OrderService的子类: " + OrderService.class.isAssignableFrom(basicProxy.getClass()));
// 测试缓存代理
System.out.println("\n3. 测试缓存代理:");
OrderService cachedProxy1 = EnhancedCglibProxy.createCachedProxy(realService);
OrderService cachedProxy2 = EnhancedCglibProxy.createCachedProxy(realService);
System.out.println("两次获取的缓存代理是同一个对象: " + (cachedProxy1 == cachedProxy2));
// 测试多回调代理
System.out.println("\n4. 测试多回调代理:");
OrderService multiCallbackProxy = EnhancedCglibProxy.createMultiCallbackProxy(realService);
System.out.println("测试查询方法(使用日志拦截):");
multiCallbackProxy.getOrderStatus("ORD002");
System.out.println("\n测试创建方法(使用安全拦截):");
multiCallbackProxy.createOrder("ORD002", "设计模式");
System.out.println("\n测试删除方法(使用性能监控):");
try {
multiCallbackProxy.cancelOrder("ORD002");
} catch (Exception e) {
System.err.println("预期异常: " + e.getMessage());
}
}
}
限制与注意事项
- final类和方法:CGLIB无法代理final类和方法
- 构造函数:代理类会调用父类的无参构造函数,目标类需要有可访问的无参构造
- private方法:private方法不会被代理
- static方法:static方法不会被代理
- 性能考虑:虽然CGLIB避免了反射,但字节码生成也有开销
3.3 代理模式对比分析
| 特性 | 静态代理 | JDK动态代理 | CGLIB代理 |
|---|---|---|---|
| 实现方式 | 手动编码 | 反射API | 字节码增强 |
| 代理目标 | 具体类 | 接口 | 类 |
| 性能 | 高 | 中 | 高 |
| 依赖 | 无 | Java标准库 | CGLIB库 |
| 限制 | 需预定义代理类 | 目标需实现接口 | 无法代理final类 |
| 适用场景 | 简单系统 | 接口代理 | 类代理/复杂系统 |
4. Spring AOP 中的代理实现
4.1 Spring代理机制概述
Spring框架通过代理模式实现了AOP(面向切面编程)的核心功能。Spring根据目标对象是否实现接口,自动选择JDK动态代理或CGLIB代理。
4.2 代理选择策略
Spring的代理选择遵循以下规则:
- 如果目标对象实现了接口:默认使用JDK动态代理
- 如果目标对象没有实现接口:使用CGLIB代理
- 强制使用CGLIB:@EnableAspectJAutoProxy(proxyTargetClass=true)
- 代理模式优化:@EnableAspectJAutoProxy(exposeProxy=true)
4.3 切面定义与实现
java
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import java.util.Arrays;
/**
* 日志切面
* 记录方法执行日志和性能监控
*/
@Aspect
@Component
public class LoggingAspect {
private static final org.slf4j.Logger logger =
org.slf4j.LoggerFactory.getLogger(LoggingAspect.class);
/**
* 定义切入点:所有Service层的方法
*/
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {}
/**
* 定义切入点:所有Controller层的方法
*/
@Pointcut("execution(* com.example.controller.*.*(..))")
public void controllerLayer() {}
/**
* 定义切入点:所有Mapper接口的方法
*/
@Pointcut("execution(* com.example.mapper.*.*(..))")
public void mapperLayer() {}
/**
* 前置通知:在方法执行前记录日志
*/
@Before("serviceLayer()")
public void logBefore(JoinPoint joinPoint) {
String className = joinPoint.getTarget().getClass().getSimpleName();
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
logger.info("开始执行方法: {}.{}", className, methodName);
logger.info("方法参数: {}", Arrays.toString(args));
}
/**
* 后置通知:在方法正常返回后记录日志
*/
@AfterReturning(
pointcut = "serviceLayer()",
returning = "result"
)
public void logAfterReturning(JoinPoint joinPoint, Object result) {
String className = joinPoint.getTarget().getClass().getSimpleName();
String methodName = joinPoint.getSignature().getName();
logger.info("方法执行成功: {}.{}", className, methodName);
logger.info("返回结果: {}", result);
}
/**
* 异常通知:在方法抛出异常后记录日志
*/
@AfterThrowing(
pointcut = "serviceLayer()",
throwing = "error"
)
public void logAfterThrowing(JoinPoint joinPoint, Throwable error) {
String className = joinPoint.getTarget().getClass().getSimpleName();
String methodName = joinPoint.getSignature().getName();
logger.error("方法执行异常: {}.{}", className, methodName);
logger.error("异常信息: {}", error.getMessage(), error);
}
/**
* 最终通知:在方法执行完成后记录日志
*/
@After("serviceLayer()")
public void logAfter(JoinPoint joinPoint) {
String className = joinPoint.getTarget().getClass().getSimpleName();
String methodName = joinPoint.getSignature().getName();
logger.info("方法执行完成: {}.{}", className, methodName);
}
/**
* 环绕通知:性能监控和异常处理
*/
@Around("serviceLayer()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
String className = joinPoint.getTarget().getClass().getSimpleName();
String methodName = joinPoint.getSignature().getName();
StopWatch stopWatch = new StopWatch();
stopWatch.start();
logger.info("环绕通知 - 开始执行方法: {}.{}", className, methodName);
try {
// 执行目标方法
Object result = joinPoint.proceed();
stopWatch.stop();
logger.info("环绕通知 - 方法执行成功: {}.{}", className, methodName);
logger.info("方法执行耗时: {} ms", stopWatch.getTotalTimeMillis());
return result;
} catch (Exception e) {
stopWatch.stop();
logger.error("环绕通知 - 方法执行失败: {}.{}", className, methodName);
logger.error("执行耗时: {} ms", stopWatch.getTotalTimeMillis());
logger.error("异常类型: {}", e.getClass().getSimpleName());
logger.error("异常信息: {}", e.getMessage());
throw e;
}
}
/**
* 事务管理切面
*/
@Around("@annotation(org.springframework.transaction.annotation.Transactional)")
public Object manageTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
logger.info("开始事务管理...");
try {
Object result = joinPoint.proceed();
logger.info("事务提交成功");
return result;
} catch (Exception e) {
logger.error("事务回滚,原因: {}", e.getMessage());
throw e;
}
}
/**
* 缓存切面
*/
@Around("@annotation(com.example.annotation.Cacheable)")
public Object manageCache(ProceedingJoinPoint joinPoint) throws Throwable {
String cacheKey = generateCacheKey(joinPoint);
// 尝试从缓存获取
Object cachedValue = getFromCache(cacheKey);
if (cachedValue != null) {
logger.info("缓存命中: {}", cacheKey);
return cachedValue;
}
logger.info("缓存未命中,执行目标方法");
Object result = joinPoint.proceed();
// 缓存结果
saveToCache(cacheKey, result);
logger.info("结果已缓存: {}", cacheKey);
return result;
}
private String generateCacheKey(JoinPoint joinPoint) {
StringBuilder keyBuilder = new StringBuilder();
keyBuilder.append(joinPoint.getTarget().getClass().getSimpleName());
keyBuilder.append(".").append(joinPoint.getSignature().getName());
Object[] args = joinPoint.getArgs();
if (args != null && args.length > 0) {
for (Object arg : args) {
keyBuilder.append(".").append(arg != null ? arg.hashCode() : "null");
}
}
return keyBuilder.toString();
}
private Object getFromCache(String key) {
// 实际项目中会从Redis等缓存获取
return null;
}
private void saveToCache(String key, Object value) {
// 实际项目中会保存到Redis等缓存
}
}
最佳实践建议:
- 合理选择代理类型:根据目标对象特性选择JDK或CGLIB代理
- 避免过度使用AOP:只在横切关注点使用,避免影响核心逻辑
- 注意代理范围:Spring默认只代理public方法
- 处理内部调用问题 :使用
AopContext.currentProxy()解决内部调用 - 性能监控:对关键业务方法添加性能监控切面
5. 模式的优劣分析
5.1 优点
- 职责清晰:真实对象专注核心逻辑,代理处理附加功能
- 高扩展性:在不修改原始对象的情况下增加新功能
- 访问控制:代理对象控制对真实对象的访问权限
- 性能优化:实现延迟加载、缓存等优化手段
- 解耦合:客户端与真实对象解耦,提高系统灵活性
- 开闭原则:通过代理扩展功能,无需修改原有类
5.2 缺点
- 系统复杂度增加:引入额外抽象层,增加理解难度
- 性能开销:代理调用增加处理时间(特别是反射)
- 实现复杂度:动态代理涉及反射和字节码技术
- 类文件增多:静态代理导致类数量膨胀
- 调试困难:动态代理堆栈信息复杂,增加调试难度
6. 代理模式的应用场景
6.1 典型应用场景
6.1.1 权限控制与安全代理
场景描述:
在企业管理系统中,不同角色的用户对系统资源的访问权限不同。需要实现细粒度的权限控制,确保只有授权用户才能执行特定操作。
实现方案:
java
import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.util.Set;
/**
* 权限控制代理实现
*/
public class SecurityProxy implements java.lang.reflect.InvocationHandler {
private final Object target;
private final SecurityContext securityContext;
public SecurityProxy(Object target, SecurityContext securityContext) {
this.target = target;
this.securityContext = securityContext;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 检查方法级别的权限注解
RequiredPermission permission = method.getAnnotation(RequiredPermission.class);
if (permission != null) {
String requiredPermission = permission.value();
String requiredRole = permission.role();
// 检查权限
if (!hasPermission(requiredPermission)) {
throw new SecurityException("权限不足,需要权限: " + requiredPermission);
}
// 检查角色
if (!requiredRole.isEmpty() && !hasRole(requiredRole)) {
throw new SecurityException("角色不符,需要角色: " + requiredRole);
}
}
// 检查类级别的权限注解
Class<?> targetClass = target.getClass();
if (targetClass.isAnnotationPresent(Secured.class)) {
Secured secured = targetClass.getAnnotation(Secured.class);
String[] allowedRoles = secured.value();
if (!hasAnyRole(allowedRoles)) {
throw new SecurityException("访问被拒绝,需要以下角色之一: " +
String.join(", ", allowedRoles));
}
}
// 记录审计日志
auditLog(method, args);
// 执行目标方法
return method.invoke(target, args);
}
private boolean hasPermission(String permission) {
Set<String> userPermissions = securityContext.getCurrentUserPermissions();
return userPermissions.contains(permission);
}
private boolean hasRole(String role) {
Set<String> userRoles = securityContext.getCurrentUserRoles();
return userRoles.contains(role);
}
private boolean hasAnyRole(String[] roles) {
Set<String> userRoles = securityContext.getCurrentUserRoles();
for (String role : roles) {
if (userRoles.contains(role)) {
return true;
}
}
return false;
}
private void auditLog(Method method, Object[] args) {
String username = securityContext.getCurrentUsername();
String className = target.getClass().getSimpleName();
String methodName = method.getName();
AuditLogger.log(
"用户: " + username +
" 执行: " + className + "." + methodName +
" 参数: " + formatArgs(args)
);
}
private String formatArgs(Object[] args) {
if (args == null || args.length == 0) {
return "[]";
}
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < args.length; i++) {
if (i > 0) sb.append(", ");
sb.append(args[i] != null ? args[i].toString() : "null");
}
sb.append("]");
return sb.toString();
}
}
/**
* 权限注解定义
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequiredPermission {
String value() default "";
String role() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Secured {
String[] value();
}
/**
* 安全上下文接口
*/
public interface SecurityContext {
String getCurrentUsername();
Set<String> getCurrentUserRoles();
Set<String> getCurrentUserPermissions();
}
/**
* 审计日志记录器
*/
public class AuditLogger {
public static void log(String message) {
System.out.println("[审计日志] " + new java.util.Date() + " - " + message);
}
}
java
/**
* 受保护的业务服务
*/
@Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
public interface EmployeeService {
@RequiredPermission(permission = "employee:create", role = "ROLE_ADMIN")
void createEmployee(Employee employee);
@RequiredPermission(permission = "employee:read")
Employee getEmployee(String id);
@RequiredPermission(permission = "employee:update", role = "ROLE_MANAGER")
void updateEmployee(Employee employee);
@RequiredPermission(permission = "employee:delete", role = "ROLE_ADMIN")
void deleteEmployee(String id);
}
/**
* 客户端使用
*/
public class SecurityProxyDemo {
public static void main(String[] args) {
// 创建目标对象
EmployeeService realService = new EmployeeServiceImpl();
// 创建安全上下文(模拟)
SecurityContext securityContext = createSecurityContext();
// 创建安全代理
EmployeeService proxy = (EmployeeService) java.lang.reflect.Proxy.newProxyInstance(
EmployeeService.class.getClassLoader(),
new Class[]{EmployeeService.class},
new SecurityProxy(realService, securityContext)
);
// 测试权限控制
System.out.println("=== 权限控制测试 ===");
try {
System.out.println("\n1. 测试创建员工(需要ROLE_ADMIN):");
proxy.createEmployee(new Employee("001", "张三"));
} catch (SecurityException e) {
System.err.println("权限异常: " + e.getMessage());
}
try {
System.out.println("\n2. 测试查询员工(需要employee:read权限):");
Employee emp = proxy.getEmployee("001");
System.out.println("查询成功: " + emp);
} catch (SecurityException e) {
System.err.println("权限异常: " + e.getMessage());
}
}
private static SecurityContext createSecurityContext() {
return new SecurityContext() {
@Override
public String getCurrentUsername() {
return "user1";
}
@Override
public Set<String> getCurrentUserRoles() {
return java.util.Collections.singleton("ROLE_USER");
}
@Override
public Set<String> getCurrentUserPermissions() {
return java.util.Collections.singleton("employee:read");
}
};
}
}
6.1.2 延迟加载代理(Lazy Loading)
场景描述:
在电商系统中,商品详情包含大量信息(基本信息、库存、评价、推荐等),但用户可能只查看基本信息。使用延迟加载代理可以在需要时才加载完整信息,提高系统响应速度。
实现方案:
java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* 延迟加载代理实现
*/
public class LazyLoadingProxy<T> implements InvocationHandler {
private volatile T realObject;
private final Callable<T> objectLoader;
private final ExecutorService executorService;
private Future<T> futureResult;
public LazyLoadingProxy(Callable<T> objectLoader) {
this.objectLoader = objectLoader;
this.executorService = Executors.newSingleThreadExecutor();
}
@SuppressWarnings("unchecked")
public static <T> T createProxy(Class<T> interfaceClass, Callable<T> objectLoader) {
return (T) Proxy.newProxyInstance(
interfaceClass.getClassLoader(),
new Class[]{interfaceClass},
new LazyLoadingProxy<>(objectLoader)
);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 如果已经初始化,直接调用
if (realObject != null) {
return method.invoke(realObject, args);
}
// 检查方法是否需要触发加载
if (shouldTriggerLoading(method)) {
// 触发延迟加载
triggerLazyLoading();
}
// 如果已经初始化,调用真实对象
if (realObject != null) {
return method.invoke(realObject, args);
}
// 返回默认值或占位符
return getDefaultValue(method.getReturnType());
}
private synchronized void triggerLazyLoading() {
// 双重检查锁定
if (realObject != null) {
return;
}
if (futureResult == null) {
// 提交加载任务
futureResult = executorService.submit(() -> {
System.out.println("[延迟加载] 开始加载真实对象...");
T obj = objectLoader.call();
System.out.println("[延迟加载] 真实对象加载完成");
return obj;
});
}
try {
// 等待加载完成
realObject = futureResult.get();
// 清理资源
futureResult = null;
executorService.shutdown();
} catch (Exception e) {
throw new RuntimeException("延迟加载失败", e);
}
}
private boolean shouldTriggerLoading(Method method) {
String methodName = method.getName();
// 以下方法触发延迟加载
return methodName.startsWith("get") ||
methodName.startsWith("load") ||
methodName.startsWith("fetch");
}
private Object getDefaultValue(Class<?> returnType) {
if (returnType == boolean.class) return false;
if (returnType == byte.class) return (byte) 0;
if (returnType == short.class) return (short) 0;
if (returnType == int.class) return 0;
if (returnType == long.class) return 0L;
if (returnType == float.class) return 0.0f;
if (returnType == double.class) return 0.0;
if (returnType == char.class) return '\0';
if (returnType == Void.class || returnType == void.class) return null;
// 引用类型返回null
return null;
}
}
/**
* 商品详情服务接口
*/
public interface ProductDetailService {
// 基本信息(不触发延迟加载)
String getBasicInfo();
// 库存信息(触发延迟加载)
Inventory getInventory();
// 评价信息(触发延迟加载)
List<Review> getReviews();
// 推荐商品(触发延迟加载)
List<Product> getRecommendations();
}
/**
* 使用示例
*/
public class LazyLoadingDemo {
public static void main(String[] args) throws Exception {
System.out.println("=== 延迟加载代理测试 ===");
// 创建延迟加载代理
ProductDetailService proxy = LazyLoadingProxy.createProxy(
ProductDetailService.class,
() -> {
// 模拟耗时的对象创建过程
Thread.sleep(2000);
return new ProductDetailServiceImpl();
}
);
System.out.println("\n1. 调用不触发加载的方法:");
String basicInfo = proxy.getBasicInfo();
System.out.println("基本信息: " + basicInfo);
System.out.println("注意:真实对象尚未加载");
System.out.println("\n2. 调用触发加载的方法:");
System.out.println("开始获取库存信息...");
long startTime = System.currentTimeMillis();
Inventory inventory = proxy.getInventory();
long endTime = System.currentTimeMillis();
System.out.println("库存信息: " + inventory);
System.out.println("加载耗时: " + (endTime - startTime) + "ms");
System.out.println("\n3. 再次调用方法(已加载完成):");
startTime = System.currentTimeMillis();
List<Review> reviews = proxy.getReviews();
endTime = System.currentTimeMillis();
System.out.println("评价信息: " + reviews.size() + "条评价");
System.out.println("调用耗时: " + (endTime - startTime) + "ms");
}
}
6.1.3 远程代理(RPC框架)
场景描述:
在微服务架构中,服务之间需要远程调用。远程代理封装了网络通信细节,使客户端可以像调用本地方法一样调用远程服务。
实现方案:
java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 简单的RPC远程代理实现
*/
public class RpcProxy implements InvocationHandler {
private final String serviceUrl;
private final Class<?> serviceInterface;
private final Map<Method, String> methodCache = new ConcurrentHashMap<>();
public RpcProxy(String serviceUrl, Class<?> serviceInterface) {
this.serviceUrl = serviceUrl;
this.serviceInterface = serviceInterface;
initMethodCache();
}
@SuppressWarnings("unchecked")
public static <T> T createProxy(String serviceUrl, Class<T> serviceInterface) {
return (T) Proxy.newProxyInstance(
serviceInterface.getClassLoader(),
new Class[]{serviceInterface},
new RpcProxy(serviceUrl, serviceInterface)
);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 过滤Object类的方法
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
// 构建RPC请求
RpcRequest request = new RpcRequest();
request.setServiceName(serviceInterface.getName());
request.setMethodName(method.getName());
request.setParameterTypes(method.getParameterTypes());
request.setParameters(args);
// 发送请求
RpcResponse response = sendRequest(request);
// 处理响应
if (response.isError()) {
throw response.getError();
}
return response.getResult();
}
private RpcResponse sendRequest(RpcRequest request) {
try {
// 序列化请求
String requestBody = serialize(request);
// 发送HTTP请求
URL url = new URL(serviceUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setDoOutput(true);
// 写入请求体
try (java.io.OutputStream os = connection.getOutputStream()) {
os.write(requestBody.getBytes());
os.flush();
}
// 读取响应
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
String responseBody = readResponse(connection);
return deserialize(responseBody, RpcResponse.class);
} else {
throw new RuntimeException("RPC调用失败,响应码: " + responseCode);
}
} catch (Exception e) {
throw new RuntimeException("RPC调用异常", e);
}
}
private void initMethodCache() {
// 缓存方法信息,优化性能
for (Method method : serviceInterface.getMethods()) {
String key = method.getName() + "_" +
java.util.Arrays.toString(method.getParameterTypes());
methodCache.put(method, key);
}
}
private String serialize(Object obj) {
// 使用JSON序列化
return new com.fasterxml.jackson.databind.ObjectMapper()
.writeValueAsString(obj);
}
private <T> T deserialize(String json, Class<T> type) {
try {
return new com.fasterxml.jackson.databind.ObjectMapper()
.readValue(json, type);
} catch (Exception e) {
throw new RuntimeException("反序列化失败", e);
}
}
private String readResponse(HttpURLConnection connection) throws Exception {
try (java.io.BufferedReader reader = new java.io.BufferedReader(
new java.io.InputStreamReader(connection.getInputStream()))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
return response.toString();
}
}
}
/**
* RPC请求和响应对象
*/
class RpcRequest {
private String serviceName;
private String methodName;
private Class<?>[] parameterTypes;
private Object[] parameters;
// getters and setters
}
class RpcResponse {
private Object result;
private Throwable error;
private boolean isError;
// getters and setters
}
/**
* 远程服务接口
*/
public interface UserRemoteService {
User getUserById(String id);
List<User> searchUsers(String keyword);
void updateUser(User user);
}
/**
* 使用示例
*/
public class RpcProxyDemo {
public static void main(String[] args) {
System.out.println("=== RPC远程代理测试 ===");
// 创建远程代理
UserRemoteService proxy = RpcProxy.createProxy(
"http://localhost:8080/api/user",
UserRemoteService.class
);
// 像调用本地方法一样调用远程服务
try {
System.out.println("\n1. 查询用户信息:");
User user = proxy.getUserById("123");
System.out.println("查询结果: " + user);
System.out.println("\n2. 搜索用户:");
List<User> users = proxy.searchUsers("张");
System.out.println("搜索结果: " + users.size() + "个用户");
} catch (Exception e) {
System.err.println("RPC调用异常: " + e.getMessage());
}
}
}
6.1.4 缓存代理
场景描述:
在内容管理系统中,热门文章的访问频率很高。使用缓存代理可以缓存查询结果,减少数据库压力,提高响应速度。
实现方案:
java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
* 缓存代理实现
*/
public class CacheProxy implements InvocationHandler {
private final Object target;
private final CacheManager cacheManager;
private final Map<Method, CacheConfig> cacheConfigs = new ConcurrentHashMap<>();
public CacheProxy(Object target, CacheManager cacheManager) {
this.target = target;
this.cacheManager = cacheManager;
initCacheConfigs();
}
@SuppressWarnings("unchecked")
public static <T> T createProxy(T target, CacheManager cacheManager) {
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new CacheProxy(target, cacheManager)
);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 获取缓存配置
CacheConfig config = cacheConfigs.get(method);
// 如果没有缓存配置,直接调用
if (config == null) {
return method.invoke(target, args);
}
// 生成缓存key
String cacheKey = generateCacheKey(method, args, config);
// 尝试从缓存获取
Object cachedValue = cacheManager.get(cacheKey);
if (cachedValue != null) {
System.out.println("[缓存命中] key: " + cacheKey);
return cachedValue;
}
System.out.println("[缓存未命中] key: " + cacheKey + ", 执行目标方法");
// 执行目标方法
Object result = method.invoke(target, args);
// 缓存结果
if (result != null && config.isCacheable(result)) {
cacheManager.put(cacheKey, result, config.getTtl(), config.getTimeUnit());
System.out.println("[缓存写入] key: " + cacheKey + ", ttl: " + config.getTtl() + config.getTimeUnit());
}
return result;
}
private void initCacheConfigs() {
// 解析方法上的缓存注解
for (Method method : target.getClass().getMethods()) {
Cacheable cacheable = method.getAnnotation(Cacheable.class);
if (cacheable != null) {
cacheConfigs.put(method, new CacheConfig(cacheable));
}
}
}
private String generateCacheKey(Method method, Object[] args, CacheConfig config) {
StringBuilder keyBuilder = new StringBuilder();
// 使用配置的缓存名称
keyBuilder.append(config.getCacheName());
keyBuilder.append(":");
// 添加类名和方法名
keyBuilder.append(target.getClass().getSimpleName());
keyBuilder.append(".");
keyBuilder.append(method.getName());
// 添加参数哈希
if (args != null && args.length > 0) {
keyBuilder.append(":");
for (Object arg : args) {
keyBuilder.append(arg != null ? arg.hashCode() : "null");
keyBuilder.append("_");
}
}
return keyBuilder.toString();
}
}
/**
* 缓存管理器接口
*/
interface CacheManager {
Object get(String key);
void put(String key, Object value, long ttl, TimeUnit timeUnit);
void remove(String key);
void clear();
}
/**
* 基于内存的缓存管理器实现
*/
class MemoryCacheManager implements CacheManager {
private static class CacheEntry {
final Object value;
final long expireTime;
CacheEntry(Object value, long expireTime) {
this.value = value;
this.expireTime = expireTime;
}
boolean isExpired() {
return System.currentTimeMillis() > expireTime;
}
}
private final Map<String, CacheEntry> cache = new ConcurrentHashMap<>();
private final ScheduledExecutorService cleanupExecutor =
Executors.newSingleThreadScheduledExecutor();
public MemoryCacheManager() {
// 定期清理过期缓存
cleanupExecutor.scheduleAtFixedRate(this::cleanupExpired, 1, 1, TimeUnit.MINUTES);
}
@Override
public Object get(String key) {
CacheEntry entry = cache.get(key);
if (entry == null) {
return null;
}
if (entry.isExpired()) {
cache.remove(key);
return null;
}
return entry.value;
}
@Override
public void put(String key, Object value, long ttl, TimeUnit timeUnit) {
long expireTime = System.currentTimeMillis() + timeUnit.toMillis(ttl);
cache.put(key, new CacheEntry(value, expireTime));
}
@Override
public void remove(String key) {
cache.remove(key);
}
@Override
public void clear() {
cache.clear();
}
private void cleanupExpired() {
cache.entrySet().removeIf(entry -> entry.getValue().isExpired());
}
}
/**
* 缓存配置类
*/
class CacheConfig {
private final String cacheName;
private final long ttl;
private final TimeUnit timeUnit;
CacheConfig(Cacheable annotation) {
this.cacheName = annotation.value();
this.ttl = annotation.ttl();
this.timeUnit = annotation.unit();
}
boolean isCacheable(Object result) {
// 可以根据结果类型决定是否缓存
return result != null;
}
// getters
}
/**
* 缓存注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Cacheable {
String value() default "default";
long ttl() default 300;
TimeUnit unit() default TimeUnit.SECONDS;
}
/**
* 文章服务接口
*/
public interface ArticleService {
@Cacheable(value = "article", ttl = 600)
Article getArticleById(String id);
@Cacheable(value = "hotArticles", ttl = 300)
List<Article> getHotArticles(int limit);
void updateArticle(Article article);
}
/**
* 使用示例
*/
public class CacheProxyDemo {
public static void main(String[] args) throws Exception {
System.out.println("=== 缓存代理测试 ===");
// 创建缓存管理器
CacheManager cacheManager = new MemoryCacheManager();
// 创建目标对象
ArticleService realService = new ArticleServiceImpl();
// 创建缓存代理
ArticleService proxy = CacheProxy.createProxy(realService, cacheManager);
// 测试缓存效果
System.out.println("\n1. 第一次查询文章(缓存未命中):");
long startTime = System.currentTimeMillis();
Article article1 = proxy.getArticleById("123");
long endTime = System.currentTimeMillis();
System.out.println("查询结果: " + article1.getTitle());
System.out.println("查询耗时: " + (endTime - startTime) + "ms");
System.out.println("\n2. 第二次查询同一文章(缓存命中):");
startTime = System.currentTimeMillis();
Article article2 = proxy.getArticleById("123");
endTime = System.currentTimeMillis();
System.out.println("查询结果: " + article2.getTitle());
System.out.println("查询耗时: " + (endTime - startTime) + "ms");
System.out.println("\n3. 更新文章后查询(缓存失效):");
article1.setTitle("更新后的标题");
proxy.updateArticle(article1);
startTime = System.currentTimeMillis();
Article article3 = proxy.getArticleById("123");
endTime = System.currentTimeMillis();
System.out.println("查询结果: " + article3.getTitle());
System.out.println("查询耗时: " + (endTime - startTime) + "ms");
System.out.println("\n4. 查询热门文章列表:");
List<Article> hotArticles = proxy.getHotArticles(10);
System.out.println("热门文章数量: " + hotArticles.size());
}
}
6.1.5 智能引用代理
场景描述:
在大对象管理场景中,需要监控对象的访问情况,实现自动清理不常用的对象,优化内存使用。
实现方案:
java
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 智能引用代理实现
* 监控对象访问,自动管理对象生命周期
*/
public class SmartReferenceProxy implements InvocationHandler {
private final Object target;
private final ReferenceType referenceType;
private final AtomicInteger accessCount = new AtomicInteger(0);
private final long createdTime = System.currentTimeMillis();
private volatile long lastAccessTime = createdTime;
private static final Map<Object, SmartReferenceProxy> proxyRegistry =
new ConcurrentHashMap<>();
private static final ReferenceQueue<Object> referenceQueue =
new ReferenceQueue<>();
public enum ReferenceType {
STRONG, // 强引用
SOFT, // 软引用(内存不足时回收)
WEAK // 弱引用(GC时回收)
}
private SmartReferenceProxy(Object target, ReferenceType referenceType) {
this.target = target;
this.referenceType = referenceType;
}
@SuppressWarnings("unchecked")
public static <T> T createProxy(T target, ReferenceType referenceType) {
SmartReferenceProxy handler = new SmartReferenceProxy(target, referenceType);
T proxy = (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler
);
// 注册代理
proxyRegistry.put(proxy, handler);
// 根据引用类型创建不同的引用
switch (referenceType) {
case SOFT:
new SoftReference<>(proxy, referenceQueue);
break;
case WEAK:
new WeakReference<>(proxy, referenceQueue);
break;
case STRONG:
default:
// 强引用不需要特殊处理
break;
}
return proxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 更新访问统计
accessCount.incrementAndGet();
lastAccessTime = System.currentTimeMillis();
// 记录访问日志
logAccess(method);
// 执行目标方法
return method.invoke(target, args);
}
private void logAccess(Method method) {
System.out.printf("[智能引用] 对象访问 - 方法: %s, 总访问次数: %d, 最后访问: %tT%n",
method.getName(),
accessCount.get(),
new java.util.Date(lastAccessTime)
);
}
/**
* 获取对象访问统计
*/
public AccessStatistics getStatistics() {
long currentTime = System.currentTimeMillis();
long idleTime = currentTime - lastAccessTime;
return new AccessStatistics(
accessCount.get(),
createdTime,
lastAccessTime,
idleTime
);
}
/**
* 访问统计信息
*/
public static class AccessStatistics {
private final int totalAccessCount;
private final long createdTime;
private final long lastAccessTime;
private final long idleTime;
public AccessStatistics(int totalAccessCount, long createdTime,
long lastAccessTime, long idleTime) {
this.totalAccessCount = totalAccessCount;
this.createdTime = createdTime;
this.lastAccessTime = lastAccessTime;
this.idleTime = idleTime;
}
// getters
}
/**
* 监控线程,定期清理和报告
*/
static class ReferenceMonitor extends Thread {
private volatile boolean running = true;
@Override
public void run() {
while (running) {
try {
// 检查引用队列
checkReferenceQueue();
// 报告统计信息
reportStatistics();
// 休眠一段时间
Thread.sleep(5000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
private void checkReferenceQueue() {
java.lang.ref.Reference<?> ref;
while ((ref = referenceQueue.poll()) != null) {
System.out.println("[监控] 对象已被回收: " + ref);
}
}
private void reportStatistics() {
if (proxyRegistry.isEmpty()) {
return;
}
System.out.println("\n=== 对象访问统计报告 ===");
System.out.println("活动对象数量: " + proxyRegistry.size());
proxyRegistry.forEach((proxy, handler) -> {
AccessStatistics stats = handler.getStatistics();
System.out.printf("对象: %s, 访问次数: %d, 空闲时间: %dms%n",
proxy.getClass().getSimpleName(),
stats.totalAccessCount,
stats.idleTime
);
});
}
public void shutdown() {
running = false;
interrupt();
}
}
}
/**
* 大对象接口
*/
public interface LargeObject {
byte[] getData();
void process();
String getId();
}
/**
* 使用示例
*/
public class SmartReferenceDemo {
public static void main(String[] args) throws Exception {
System.out.println("=== 智能引用代理测试 ===");
// 启动监控线程
SmartReferenceProxy.ReferenceMonitor monitor =
new SmartReferenceProxy.ReferenceMonitor();
monitor.setDaemon(true);
monitor.start();
// 创建不同引用类型的代理
System.out.println("\n1. 创建软引用代理:");
LargeObject softProxy = SmartReferenceProxy.createProxy(
createLargeObject("soft-obj"),
SmartReferenceProxy.ReferenceType.SOFT
);
System.out.println("\n2. 创建弱引用代理:");
LargeObject weakProxy = SmartReferenceProxy.createProxy(
createLargeObject("weak-obj"),
SmartReferenceProxy.ReferenceType.WEAK
);
System.out.println("\n3. 创建强引用代理:");
LargeObject strongProxy = SmartReferenceProxy.createProxy(
createLargeObject("strong-obj"),
SmartReferenceProxy.ReferenceType.STRONG
);
// 模拟访问
System.out.println("\n4. 模拟对象访问:");
for (int i = 0; i < 3; i++) {
System.out.println("\n第 " + (i + 1) + " 轮访问:");
softProxy.getData();
weakProxy.process();
strongProxy.getId();
// 间隔一段时间
Thread.sleep(1000);
}
// 获取统计信息
System.out.println("\n5. 查看统计信息:");
printStatistics(softProxy, "软引用对象");
printStatistics(weakProxy, "弱引用对象");
printStatistics(strongProxy, "强引用对象");
// 模拟内存压力,触发GC
System.out.println("\n6. 模拟内存压力:");
simulateMemoryPressure();
// 等待监控线程报告
Thread.sleep(10000);
// 停止监控
monitor.shutdown();
}
private static LargeObject createLargeObject(String id) {
return new LargeObject() {
private final byte[] data = new byte[1024 * 1024]; // 1MB数据
@Override
public byte[] getData() {
System.out.println("获取对象数据: " + id);
return data;
}
@Override
public void process() {
System.out.println("处理对象: " + id);
}
@Override
public String getId() {
return id;
}
};
}
private static void printStatistics(Object proxy, String label) {
SmartReferenceProxy handler = SmartReferenceProxy.proxyRegistry.get(proxy);
if (handler != null) {
SmartReferenceProxy.AccessStatistics stats = handler.getStatistics();
System.out.printf("%s - 访问次数: %d, 空闲时间: %dms%n",
label, stats.totalAccessCount, stats.idleTime);
}
}
private static void simulateMemoryPressure() {
System.out.println("创建大量对象模拟内存压力...");
List<byte[]> memoryHog = new ArrayList<>();
for (int i = 0; i < 100; i++) {
memoryHog.add(new byte[1024 * 1024]); // 每次分配1MB
}
// 触发GC
System.gc();
// 清理引用,让GC可以回收
memoryHog.clear();
}
}
6.2 企业级应用案例
| 框架/技术 | 代理应用 | 实现方式 |
|---|---|---|
| Spring Framework | AOP切面编程 | JDK/CGLIB代理 |
| MyBatis | Mapper接口实现 | JDK动态代理 |
| Hibernate | 延迟加载 | CGLIB代理 |
| Spring Security | 方法安全控制 | AOP代理 |
| Dubbo | 远程服务调用 | 动态代理 |
| Java RMI | 远程对象访问 | 动态代理 |
| Mockito | 测试模拟对象 | 动态代理 |
7. 代理模式的最佳实践
7.1 设计原则
-
单一职责原则 :代理类专注访问控制,真实类专注业务逻辑
java// 真实类 - 业务逻辑 class PaymentProcessor { public void processPayment(double amount) { // 核心支付逻辑 } } // 代理类 - 附加功能 class PaymentProxy { private PaymentProcessor processor; public void processPayment(double amount) { validate(amount); // 验证 log(amount); // 日志 processor.processPayment(amount); // 委托 notify(); // 通知 } } -
开闭原则:通过代理扩展功能,无需修改真实类
-
迪米特法则:客户端仅与代理交互,不与真实类直接耦合
7.2 性能优化策略
- 代理对象缓存:复用已创建的代理实例,特别是在高并发场景下。
java
public class ProxyCacheManager {
private static final ConcurrentHashMap<CacheKey, Object> PROXY_CACHE =
new ConcurrentHashMap<>();
private static class CacheKey {
final Class<?> targetClass;
final Class<?>[] interfaces;
CacheKey(Class<?> targetClass, Class<?>[] interfaces) {
this.targetClass = targetClass;
this.interfaces = interfaces;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CacheKey cacheKey = (CacheKey) o;
return targetClass.equals(cacheKey.targetClass) &&
Arrays.equals(interfaces, cacheKey.interfaces);
}
@Override
public int hashCode() {
int result = targetClass.hashCode();
result = 31 * result + Arrays.hashCode(interfaces);
return result;
}
}
@SuppressWarnings("unchecked")
public static <T> T getCachedProxy(T target, Class<T> interfaceType) {
CacheKey key = new CacheKey(
target.getClass(),
new Class<?>[]{interfaceType}
);
return (T) PROXY_CACHE.computeIfAbsent(key, k ->
createProxy(target, interfaceType)
);
}
private static <T> T createProxy(T target, Class<T> interfaceType) {
return (T) Proxy.newProxyInstance(
interfaceType.getClassLoader(),
new Class<?>[]{interfaceType},
new CachingInvocationHandler(target)
);
}
}
-
延迟初始化 :真实对象按需创建
javapublic class LazyInitProxy implements InvocationHandler { private volatile Object target; private final Supplier<?> creator; public Object invoke(Object proxy, Method method, Object[] args) { if (target == null) { synchronized (this) { // 双重检查锁定 if (target == null) { target = creator.get(); } } } return method.invoke(target, args); } } -
方法缓存优化:缓存Method对象,避免重复反射获取。
java
public class OptimizedMethodInterceptor implements MethodInterceptor {
private final Map<Method, FastMethod> methodCache = new ConcurrentHashMap<>();
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
FastMethod fastMethod = methodCache.computeIfAbsent(method, m ->
createFastMethod(m, proxy)
);
return fastMethod.invoke(obj, args);
}
private FastMethod createFastMethod(Method method, MethodProxy proxy) {
// 使用字节码生成优化方法调用
return new FastMethod() {
@Override
public Object invoke(Object obj, Object[] args) throws Throwable {
return proxy.invokeSuper(obj, args);
}
};
}
interface FastMethod {
Object invoke(Object obj, Object[] args) throws Throwable;
}
}
7.3 安全实践
-
封装真实对象:避免直接暴露
java// 正确做法:私有封装 public class SafeProxy { private final Object target; } -
防御性编程:验证代理参数
javapublic Object invoke(Object proxy, Method method, Object[] args) { // 参数验证 if (args == null || args.length == 0) { throw new IllegalArgumentException("参数错误"); } // ... } -
权限最小化:代理仅暴露必要方法
-
异常处理:合理处理代理中的异常
javatry { return method.invoke(target, args); } catch (InvocationTargetException e) { throw e.getTargetException(); // 抛出真实异常 }
8.代理模式与其他模式对比
8.1 代理 vs 装饰器模式
| 维度 | 代理模式 | 装饰器模式 |
|---|---|---|
| 目的 | 控制访问 | 增强功能 |
| 关系 | 代理知道真实对象 | 装饰器与被装饰对象实现相同接口 |
| 创建 | 代理可控制创建 | 装饰器接收已有对象 |
| 关注点 | 访问机制 | 功能扩展 |
8.2 代理 vs 适配器模式
| 维度 | 代理模式 | 适配器模式 |
|---|---|---|
| 目的 | 控制访问 | 接口转换 |
| 关系 | 相同接口 | 不同接口间转换 |
9.总结与进阶思考
9.1 核心总结
- 静态代理:简单直观,适合接口稳定、代理类少的场景
- JDK动态代理:接口代理标准方案,依赖Java反射
- CGLIB代理:无接口代理首选,字节码增强技术
- Spring AOP:企业级代理最佳实践,自动选择代理方式
9.2 进阶思考
-
. 性能深度优化:
- 使用Byte Buddy或Javassist替代CGLIB
- 预生成代理类减少运行时开销
- GraalVM原生镜像优化代理模式
-
云原生时代:
- 服务网格(Service Mesh)中的边车代理
- Kubernetes API服务器中的准入控制器
- 微服务网关的代理模式应用
-
架构演进:
静态代理 JDK动态代理 CGLIB字节码增强 Spring AOP 云原生服务网格
代理模式演进趋势:
- 框架集成:现代框架(如Spring、Quarkus)内置代理优化
- 编译时织入:减少运行时开销(如Micronaut AOT)
- 云原生支持:服务网格中的代理模式新形态
- 多语言应用:跨语言代理解决方案(如gRPC代理)
架构师箴言 :"代理模式是系统边界的守护者,它在安全与效率之间找到平衡点。优秀的架构师懂得在何处设置代理,正如将军懂得在何处设置哨卡。"
------ Martin Fowler,《企业应用架构模式》