深入理解设计模式之代理模式(Proxy Pattern)
一、引言
在软件开发中,我们经常需要在不修改原有代码的前提下,为对象添加额外的功能,比如权限控制、日志记录、性能监控、事务管理等。直接修改原有类不仅违反了开闭原则,还可能引入新的bug。代理模式为这类问题提供了优雅的解决方案。
代理模式就像现实生活中的经纪人:你想买房,不直接找房主,而是通过中介;明星接商演,不直接对接,而是通过经纪人。代理在客户端和目标对象之间充当中间人,控制对目标对象的访问。本文将深入探讨代理模式的原理、三种实现方式,并结合Spring AOP、MyBatis等框架应用,帮助你全面掌握这一重要的设计模式。
二、什么是代理模式
2.1 定义
代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用。
2.2 核心思想
- 控制访问:代理控制对真实对象的访问
- 增强功能:在不修改真实对象的前提下添加功能
- 延迟加载:推迟对象的创建和初始化
- 透明性:代理对象和真实对象实现相同接口
2.3 模式结构
┌──────────────────────┐
│ <<interface>> │
│ Subject │ 抽象主题
├──────────────────────┤
│ + request() │
└──────────┬───────────┘
△
│ 实现
┌─────┴──────┐
│ │
┌────┴────────┐ ┌┴─────────────┐
│ RealSubject │ │ Proxy │ 代理类
├─────────────┤ ├──────────────┤
│ request() │◄─┤- realSubject │ 持有真实对象
└─────────────┘ │+ request() │
└──────────────┘
│
└→ 调用前后添加额外功能
调用流程:
Client → Proxy.request() → [前置处理] → RealSubject.request() → [后置处理]
2.4 代理模式的分类
代理模式的三种实现方式:
1. 静态代理
┌────────────┐
│ Proxy │ 编译时确定
│ (手写) │ 代码冗余
└────────────┘
2. JDK动态代理
┌────────────┐
│ Proxy │ 运行时生成
│ (反射实现) │ 只能代理接口
└────────────┘
3. CGLib动态代理
┌────────────┐
│ Proxy │ 运行时生成
│ (字节码) │ 可代理类
└────────────┘
三、静态代理
3.1 基础示例
抽象主题:
java
/**
* 抽象主题:用户服务接口
*/
public interface UserService {
/**
* 保存用户
*/
void saveUser(String username);
/**
* 删除用户
*/
void deleteUser(String username);
/**
* 查询用户
*/
String getUser(String username);
}
真实主题:
java
/**
* 真实主题:用户服务实现
*/
public class UserServiceImpl implements UserService {
@Override
public void saveUser(String username) {
System.out.println("保存用户: " + username);
// 实际业务逻辑
}
@Override
public void deleteUser(String username) {
System.out.println("删除用户: " + username);
}
@Override
public String getUser(String username) {
System.out.println("查询用户: " + username);
return "User{name=" + username + "}";
}
}
静态代理类:
java
/**
* 静态代理:添加日志和权限控制
*/
public class UserServiceProxy implements UserService {
private UserService userService;
private String currentUser;
public UserServiceProxy(UserService userService, String currentUser) {
this.userService = userService;
this.currentUser = currentUser;
}
@Override
public void saveUser(String username) {
// 前置处理:权限检查
if (!checkPermission("SAVE")) {
System.out.println("[PROXY] 权限不足,无法保存用户");
return;
}
// 前置处理:记录日志
System.out.println("[PROXY] 操作前 - 用户: " + currentUser + ", 方法: saveUser");
long startTime = System.currentTimeMillis();
// 调用真实对象
userService.saveUser(username);
// 后置处理:记录耗时
long endTime = System.currentTimeMillis();
System.out.println("[PROXY] 操作后 - 耗时: " + (endTime - startTime) + "ms");
}
@Override
public void deleteUser(String username) {
if (!checkPermission("DELETE")) {
System.out.println("[PROXY] 权限不足,无法删除用户");
return;
}
System.out.println("[PROXY] 操作前 - 用户: " + currentUser + ", 方法: deleteUser");
userService.deleteUser(username);
System.out.println("[PROXY] 操作后 - 删除完成");
}
@Override
public String getUser(String username) {
System.out.println("[PROXY] 操作前 - 用户: " + currentUser + ", 方法: getUser");
String result = userService.getUser(username);
System.out.println("[PROXY] 操作后 - 查询成功");
return result;
}
/**
* 权限检查
*/
private boolean checkPermission(String operation) {
// 简化:假设admin用户有所有权限
return "admin".equals(currentUser);
}
}
客户端使用:
java
public class StaticProxyDemo {
public static void main(String[] args) {
// 创建真实对象
UserService realService = new UserServiceImpl();
// 场景1:admin用户(有权限)
System.out.println("=== 场景1:admin用户 ===");
UserService adminProxy = new UserServiceProxy(realService, "admin");
adminProxy.saveUser("张三");
adminProxy.deleteUser("李四");
// 场景2:普通用户(无权限)
System.out.println("\n=== 场景2:普通用户 ===");
UserService userProxy = new UserServiceProxy(realService, "guest");
userProxy.saveUser("王五");
userProxy.deleteUser("赵六");
}
}
输出:
=== 场景1:admin用户 ===
[PROXY] 操作前 - 用户: admin, 方法: saveUser
保存用户: 张三
[PROXY] 操作后 - 耗时: 0ms
[PROXY] 操作前 - 用户: admin, 方法: deleteUser
删除用户: 李四
[PROXY] 操作后 - 删除完成
=== 场景2:普通用户 ===
[PROXY] 权限不足,无法保存用户
[PROXY] 权限不足,无法删除用户
3.2 静态代理的缺点
java
/**
* 静态代理的问题:
* 1. 一个代理类只能代理一个接口
* 2. 接口方法增加,代理类也要修改
* 3. 代码冗余,重复的横切逻辑
*/
// 如果有10个Service接口,需要10个代理类
class OrderServiceProxy implements OrderService { /* 重复代码 */ }
class ProductServiceProxy implements ProductService { /* 重复代码 */ }
class PaymentServiceProxy implements PaymentService { /* 重复代码 */ }
// ... 更多代理类
// 维护成本高!
四、JDK动态代理
4.1 基本原理
JDK动态代理使用Java反射机制,在运行时动态生成代理类。
JDK动态代理的工作流程:
1. Client请求
↓
2. Proxy.$Proxy0 (运行时生成)
↓
3. InvocationHandler.invoke()
↓
4. 前置处理
↓
5. method.invoke(target, args) (反射调用)
↓
6. 后置处理
↓
7. 返回结果
4.2 实现示例
InvocationHandler实现:
java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK动态代理:通用的日志和性能监控代理
*/
public class LoggingInvocationHandler implements InvocationHandler {
private Object target; // 被代理的真实对象
public LoggingInvocationHandler(Object target) {
this.target = target;
}
/**
* 代理方法调用
* @param proxy 代理对象
* @param method 被调用的方法
* @param args 方法参数
* @return 方法返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置处理
System.out.println("\n[JDK PROXY] ========== 方法调用开始 ==========");
System.out.println("[JDK PROXY] 类名: " + target.getClass().getName());
System.out.println("[JDK PROXY] 方法: " + method.getName());
System.out.println("[JDK PROXY] 参数: " + java.util.Arrays.toString(args));
long startTime = System.currentTimeMillis();
// 调用真实对象的方法
Object result = null;
try {
result = method.invoke(target, args);
// 后置处理:记录成功
long endTime = System.currentTimeMillis();
System.out.println("[JDK PROXY] 返回值: " + result);
System.out.println("[JDK PROXY] 耗时: " + (endTime - startTime) + "ms");
System.out.println("[JDK PROXY] 状态: SUCCESS");
} catch (Exception e) {
// 异常处理
System.out.println("[JDK PROXY] 异常: " + e.getCause().getMessage());
System.out.println("[JDK PROXY] 状态: FAILED");
throw e.getCause();
} finally {
System.out.println("[JDK PROXY] ========== 方法调用结束 ==========\n");
}
return result;
}
/**
* 创建代理对象
*/
@SuppressWarnings("unchecked")
public static <T> T createProxy(T target) {
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 类加载器
target.getClass().getInterfaces(), // 代理的接口
new LoggingInvocationHandler(target) // InvocationHandler
);
}
}
使用示例:
java
public class JdkProxyDemo {
public static void main(String[] args) {
// 创建真实对象
UserService userService = new UserServiceImpl();
// 创建代理对象(一行代码搞定!)
UserService proxy = LoggingInvocationHandler.createProxy(userService);
// 使用代理对象
proxy.saveUser("张三");
String user = proxy.getUser("李四");
proxy.deleteUser("王五");
System.out.println("\n=== 测试其他接口 ===");
// 同一个Handler可以代理任何接口
OrderService orderService = new OrderServiceImpl();
OrderService orderProxy = LoggingInvocationHandler.createProxy(orderService);
orderProxy.createOrder("ORDER001", 299.99);
}
}
/**
* 订单服务接口
*/
interface OrderService {
void createOrder(String orderId, double amount);
}
class OrderServiceImpl implements OrderService {
@Override
public void createOrder(String orderId, double amount) {
System.out.println("创建订单: " + orderId + ", 金额: " + amount);
}
}
4.3 多功能动态代理
java
/**
* 增强版动态代理:支持多种功能
*/
public class EnhancedInvocationHandler implements InvocationHandler {
private Object target;
private boolean enableLogging = true;
private boolean enablePerformance = true;
private boolean enableCache = false;
private java.util.Map<String, Object> cache = new java.util.HashMap<>();
public EnhancedInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodKey = method.getName() + java.util.Arrays.toString(args);
// 功能1:缓存
if (enableCache && cache.containsKey(methodKey)) {
System.out.println("[CACHE] 缓存命中: " + method.getName());
return cache.get(methodKey);
}
// 功能2:日志
if (enableLogging) {
System.out.println("[LOG] 调用方法: " + method.getName());
}
// 功能3:性能监控
long startTime = 0;
if (enablePerformance) {
startTime = System.nanoTime();
}
// 调用真实方法
Object result = method.invoke(target, args);
// 性能统计
if (enablePerformance) {
long endTime = System.nanoTime();
double ms = (endTime - startTime) / 1_000_000.0;
System.out.println("[PERFORMANCE] 耗时: " + String.format("%.3f", ms) + "ms");
}
// 存入缓存
if (enableCache && result != null) {
cache.put(methodKey, result);
}
return result;
}
// 配置方法
public EnhancedInvocationHandler enableLogging(boolean enable) {
this.enableLogging = enable;
return this;
}
public EnhancedInvocationHandler enablePerformance(boolean enable) {
this.enablePerformance = enable;
return this;
}
public EnhancedInvocationHandler enableCache(boolean enable) {
this.enableCache = enable;
return this;
}
/**
* 创建代理对象(支持链式配置)
*/
@SuppressWarnings("unchecked")
public static <T> T createProxy(T target, java.util.function.Consumer<EnhancedInvocationHandler> configurator) {
EnhancedInvocationHandler handler = new EnhancedInvocationHandler(target);
if (configurator != null) {
configurator.accept(handler);
}
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler
);
}
}
/**
* 使用示例
*/
class EnhancedProxyDemo {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
// 只启用日志和性能监控
UserService proxy = EnhancedInvocationHandler.createProxy(userService, handler -> {
handler.enableLogging(true)
.enablePerformance(true)
.enableCache(false);
});
proxy.saveUser("张三");
proxy.getUser("李四");
}
}
五、CGLib动态代理
5.1 CGLib vs JDK动态代理
JDK动态代理:
┌──────────────┐
│ Interface │
└──────△───────┘
│实现
┌───┴────┐
│ Target │
└────────┘
△
│代理
┌───┴────┐
│ $Proxy │ 运行时生成的代理类
└────────┘
限制:目标必须实现接口
CGLib动态代理:
┌──────────────┐
│ Target │ 普通类,无需接口
└──────△───────┘
│继承
┌───┴────┐
│ Target │ 运行时生成的子类
│$$EnhancerByCGLIB$$
└────────┘
优势:可以代理没有接口的类
5.2 CGLib实现示例
java
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* CGLib动态代理示例
* 注意:需要添加cglib依赖
*/
public class CglibProxyExample implements MethodInterceptor {
private Object target;
public CglibProxyExample(Object target) {
this.target = target;
}
/**
* 拦截方法调用
* @param obj 代理对象
* @param method 被拦截的方法
* @param args 方法参数
* @param proxy 方法代理对象
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("\n[CGLIB PROXY] ========== 方法调用开始 ==========");
System.out.println("[CGLIB PROXY] 方法: " + method.getName());
long startTime = System.currentTimeMillis();
// 调用父类方法(目标对象的方法)
Object result = proxy.invokeSuper(obj, args);
long endTime = System.currentTimeMillis();
System.out.println("[CGLIB PROXY] 耗时: " + (endTime - startTime) + "ms");
System.out.println("[CGLIB PROXY] ========== 方法调用结束 ==========\n");
return result;
}
/**
* 创建代理对象
*/
@SuppressWarnings("unchecked")
public static <T> T createProxy(Class<T> targetClass) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setCallback(new CglibProxyExample(null));
return (T) enhancer.create();
}
}
/**
* 没有接口的普通类
*/
class ProductService {
public void addProduct(String productName) {
System.out.println("添加商品: " + productName);
}
public void deleteProduct(String productId) {
System.out.println("删除商品: " + productId);
}
}
/**
* 测试CGLib代理
*/
class CglibProxyDemo {
public static void main(String[] args) {
// 代理没有接口的类
ProductService proxy = CglibProxyExample.createProxy(ProductService.class);
proxy.addProduct("iPhone 15");
proxy.deleteProduct("P001");
}
}
六、实际生产场景应用
6.1 场景:数据库事务代理
java
/**
* 事务管理器
*/
class TransactionManager {
private static ThreadLocal<Boolean> transactionStatus = new ThreadLocal<>();
public static void begin() {
System.out.println("[Transaction] 开启事务");
transactionStatus.set(true);
}
public static void commit() {
System.out.println("[Transaction] 提交事务");
transactionStatus.remove();
}
public static void rollback() {
System.out.println("[Transaction] 回滚事务");
transactionStatus.remove();
}
}
/**
* 事务代理处理器
*/
class TransactionInvocationHandler implements InvocationHandler {
private Object target;
public TransactionInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 检查是否需要事务(简化:方法名包含save、update、delete)
boolean needTransaction = method.getName().startsWith("save") ||
method.getName().startsWith("update") ||
method.getName().startsWith("delete");
Object result = null;
if (needTransaction) {
try {
// 开启事务
TransactionManager.begin();
// 执行业务方法
result = method.invoke(target, args);
// 提交事务
TransactionManager.commit();
} catch (Exception e) {
// 回滚事务
TransactionManager.rollback();
throw e.getCause();
}
} else {
// 不需要事务,直接执行
result = method.invoke(target, args);
}
return result;
}
@SuppressWarnings("unchecked")
public static <T> T createProxy(T target) {
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new TransactionInvocationHandler(target)
);
}
}
/**
* 订单服务
*/
interface OrderService2 {
void saveOrder(String orderId);
void updateOrder(String orderId);
void deleteOrder(String orderId);
String getOrder(String orderId);
}
class OrderServiceImpl2 implements OrderService2 {
@Override
public void saveOrder(String orderId) {
System.out.println(" [业务] 保存订单: " + orderId);
}
@Override
public void updateOrder(String orderId) {
System.out.println(" [业务] 更新订单: " + orderId);
}
@Override
public void deleteOrder(String orderId) {
System.out.println(" [业务] 删除订单: " + orderId);
}
@Override
public String getOrder(String orderId) {
System.out.println(" [业务] 查询订单: " + orderId);
return "Order{id=" + orderId + "}";
}
}
/**
* 测试事务代理
*/
class TransactionProxyDemo {
public static void main(String[] args) {
OrderService2 orderService = new OrderServiceImpl2();
OrderService2 proxy = TransactionInvocationHandler.createProxy(orderService);
System.out.println("=== 测试写操作(需要事务) ===");
proxy.saveOrder("ORDER001");
System.out.println("\n=== 测试读操作(不需要事务) ===");
proxy.getOrder("ORDER001");
System.out.println("\n=== 测试更新操作(需要事务) ===");
proxy.updateOrder("ORDER001");
}
}
6.2 场景:RPC远程调用代理
java
/**
* RPC代理:将本地方法调用转换为远程调用
*/
class RpcInvocationHandler implements InvocationHandler {
private String serverAddress;
private int port;
public RpcInvocationHandler(String serverAddress, int port) {
this.serverAddress = serverAddress;
this.port = port;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 1. 构建RPC请求
RpcRequest request = new RpcRequest();
request.setClassName(method.getDeclaringClass().getName());
request.setMethodName(method.getName());
request.setParameterTypes(method.getParameterTypes());
request.setParameters(args);
System.out.println("\n[RPC CLIENT] ========== 远程调用 ==========");
System.out.println("[RPC CLIENT] 目标服务器: " + serverAddress + ":" + port);
System.out.println("[RPC CLIENT] 调用类: " + request.getClassName());
System.out.println("[RPC CLIENT] 调用方法: " + request.getMethodName());
System.out.println("[RPC CLIENT] 参数: " + java.util.Arrays.toString(args));
// 2. 发送请求到远程服务器(这里模拟)
Object result = sendRpcRequest(request);
System.out.println("[RPC CLIENT] 返回结果: " + result);
System.out.println("[RPC CLIENT] =========================================\n");
return result;
}
/**
* 模拟发送RPC请求
*/
private Object sendRpcRequest(RpcRequest request) {
// 实际实现:
// 1. 序列化请求对象
// 2. 通过Socket发送到服务器
// 3. 接收服务器响应
// 4. 反序列化响应对象
// 这里简化为直接返回模拟结果
return "RPC_RESULT_" + System.currentTimeMillis();
}
/**
* 创建RPC代理
*/
@SuppressWarnings("unchecked")
public static <T> T createProxy(Class<T> interfaceClass, String serverAddress, int port) {
return (T) Proxy.newProxyInstance(
interfaceClass.getClassLoader(),
new Class<?>[]{interfaceClass},
new RpcInvocationHandler(serverAddress, port)
);
}
}
/**
* RPC请求对象
*/
class RpcRequest {
private String className;
private String methodName;
private Class<?>[] parameterTypes;
private Object[] parameters;
// Getters and Setters
public void setClassName(String className) { this.className = className; }
public void setMethodName(String methodName) { this.methodName = methodName; }
public void setParameterTypes(Class<?>[] parameterTypes) { this.parameterTypes = parameterTypes; }
public void setParameters(Object[] parameters) { this.parameters = parameters; }
public String getClassName() { return className; }
public String getMethodName() { return methodName; }
}
/**
* 远程服务接口
*/
interface RemoteUserService {
String getUserInfo(String userId);
void updateUserInfo(String userId, String info);
}
/**
* 测试RPC代理
*/
class RpcProxyDemo {
public static void main(String[] args) {
// 创建远程服务代理(无需实现类!)
RemoteUserService userService = RpcInvocationHandler.createProxy(
RemoteUserService.class,
"192.168.1.100",
8080
);
// 像调用本地方法一样调用远程服务
String userInfo = userService.getUserInfo("USER001");
userService.updateUserInfo("USER001", "新信息");
}
}
6.3 场景:延迟加载代理
java
/**
* 延迟加载代理:只在真正使用时才创建对象
*/
class LazyLoadingInvocationHandler implements InvocationHandler {
private Object target;
private java.util.function.Supplier<?> targetSupplier;
public LazyLoadingInvocationHandler(java.util.function.Supplier<?> targetSupplier) {
this.targetSupplier = targetSupplier;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 延迟初始化:第一次调用时才创建对象
if (target == null) {
System.out.println("[LAZY LOADING] 首次访问,创建真实对象...");
target = targetSupplier.get();
}
return method.invoke(target, args);
}
@SuppressWarnings("unchecked")
public static <T> T createProxy(Class<T> interfaceClass, java.util.function.Supplier<T> supplier) {
return (T) Proxy.newProxyInstance(
interfaceClass.getClassLoader(),
new Class<?>[]{interfaceClass},
new LazyLoadingInvocationHandler(supplier)
);
}
}
/**
* 大对象(创建成本高)
*/
interface HeavyObject {
void doSomething();
}
class HeavyObjectImpl implements HeavyObject {
public HeavyObjectImpl() {
System.out.println("[HEAVY OBJECT] 创建对象(耗时操作)...");
// 模拟耗时操作
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("[HEAVY OBJECT] 对象创建完成");
}
@Override
public void doSomething() {
System.out.println("[HEAVY OBJECT] 执行业务逻辑");
}
}
/**
* 测试延迟加载
*/
class LazyLoadingProxyDemo {
public static void main(String[] args) {
System.out.println("创建代理对象(立即返回)...");
// 创建代理,但不创建真实对象
HeavyObject proxy = LazyLoadingInvocationHandler.createProxy(
HeavyObject.class,
HeavyObjectImpl::new
);
System.out.println("代理对象创建完成\n");
System.out.println("等待2秒...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("\n首次调用方法...");
proxy.doSomething(); // 此时才创建真实对象
System.out.println("\n第二次调用方法...");
proxy.doSomething(); // 直接使用已创建的对象
}
}
七、开源框架中的应用
7.1 Spring AOP
Spring AOP是代理模式最典型的应用。
java
/**
* Spring AOP使用代理模式实现切面编程
*
* 原理:
* 1. 如果目标对象实现了接口 → 使用JDK动态代理
* 2. 如果目标对象没有接口 → 使用CGLib代理
*/
// 示例:Spring AOP注解
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.cache.annotation.Cacheable;
/**
* Service类(被代理的目标对象)
*/
@Service
public class UserServiceWithAop {
/**
* @Transactional注解会创建事务代理
* 代理会在方法执行前后添加事务管理逻辑
*/
@Transactional
public void saveUser(String username) {
System.out.println("保存用户: " + username);
// 实际业务逻辑
}
/**
* @Cacheable注解会创建缓存代理
* 代理会先检查缓存,命中则直接返回,未命中则执行方法并缓存结果
*/
@Cacheable("users")
public String getUser(String userId) {
System.out.println("从数据库查询用户: " + userId);
return "User{id=" + userId + "}";
}
}
/**
* 自定义切面
*/
// @Aspect
// @Component
class LoggingAspect {
/**
* 环绕通知:完全控制方法执行
*/
// @Around("execution(* com.example.service.*.*(..))")
public Object logAround(Object joinPoint) throws Throwable {
// 获取方法信息
// MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// Method method = signature.getMethod();
System.out.println("[AOP] 方法执行前");
long startTime = System.currentTimeMillis();
// 执行目标方法
// Object result = joinPoint.proceed();
long endTime = System.currentTimeMillis();
System.out.println("[AOP] 方法执行后,耗时: " + (endTime - startTime) + "ms");
// return result;
return null;
}
}
/**
* Spring AOP的代理创建流程(简化)
*/
class SpringAopProxyFactory {
public static Object createAopProxy(Object target) {
// 判断是否有接口
Class<?>[] interfaces = target.getClass().getInterfaces();
if (interfaces.length > 0) {
// 有接口,使用JDK动态代理
System.out.println("[Spring AOP] 使用JDK动态代理");
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
interfaces,
(proxy, method, args) -> {
System.out.println("[AOP Before] " + method.getName());
Object result = method.invoke(target, args);
System.out.println("[AOP After] " + method.getName());
return result;
}
);
} else {
// 没有接口,使用CGLib代理
System.out.println("[Spring AOP] 使用CGLib代理");
// 实际会使用CGLib创建代理
return target; // 简化示例
}
}
}
7.2 MyBatis的Mapper代理
MyBatis的Mapper接口没有实现类,通过动态代理执行SQL。
java
/**
* MyBatis Mapper代理原理(简化版)
*/
// Mapper接口(无实现类)
interface UserMapper {
// @Select("SELECT * FROM users WHERE id = #{id}")
User selectById(Long id);
// @Insert("INSERT INTO users(name, email) VALUES(#{name}, #{email})")
int insert(User user);
}
/**
* MyBatis的MapperProxy
*/
class MapperProxyFactory {
public static <T> T createMapperProxy(Class<T> mapperInterface) {
return (T) Proxy.newProxyInstance(
mapperInterface.getClassLoader(),
new Class<?>[]{mapperInterface},
new MapperInvocationHandler()
);
}
}
/**
* Mapper代理处理器
*/
class MapperInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("\n[MyBatis Mapper Proxy]");
System.out.println("接口: " + method.getDeclaringClass().getName());
System.out.println("方法: " + method.getName());
// 1. 根据方法获取SQL语句(从注解或XML)
String sql = getSqlStatement(method);
System.out.println("SQL: " + sql);
// 2. 参数处理
System.out.println("参数: " + java.util.Arrays.toString(args));
// 3. 执行SQL
Object result = executeQuery(sql, args);
System.out.println("结果: " + result);
return result;
}
private String getSqlStatement(Method method) {
// 简化:根据方法名生成SQL
if (method.getName().startsWith("select")) {
return "SELECT * FROM users WHERE id = ?";
} else if (method.getName().startsWith("insert")) {
return "INSERT INTO users VALUES (?, ?)";
}
return "UNKNOWN";
}
private Object executeQuery(String sql, Object[] args) {
// 简化:模拟执行SQL
return new User("张三", "zhangsan@example.com");
}
}
/**
* User实体类
*/
class User {
private String name;
private String email;
public User(String name, String email) {
this.name = name;
this.email = email;
}
@Override
public String toString() {
return "User{name='" + name + "', email='" + email + "'}";
}
}
/**
* 测试MyBatis Mapper代理
*/
class MyBatisProxyDemo {
public static void main(String[] args) {
// 创建Mapper代理(无需实现类)
UserMapper mapper = MapperProxyFactory.createMapperProxy(UserMapper.class);
// 调用方法(自动执行SQL)
User user = mapper.selectById(1L);
System.out.println("\n查询结果: " + user);
}
}
7.3 Dubbo RPC框架
java
/**
* Dubbo的远程服务代理(简化原理)
*
* 服务消费者使用代理对象,调用就像本地方法
* 代理内部会:
* 1. 序列化请求参数
* 2. 发送网络请求到服务提供者
* 3. 接收响应并反序列化
* 4. 返回结果
*/
// 使用Dubbo时的代码
// @Reference // Dubbo注解,会创建远程服务代理
// private UserService userService;
// userService.getUser("123"); // 实际是远程调用
/**
* Dubbo代理工厂(简化版)
*/
class DubboProxyFactory {
public static <T> T getProxy(Class<T> interfaceClass, String remoteUrl) {
return (T) Proxy.newProxyInstance(
interfaceClass.getClassLoader(),
new Class<?>[]{interfaceClass},
(proxy, method, args) -> {
System.out.println("\n[Dubbo Proxy] 远程调用");
System.out.println("接口: " + interfaceClass.getName());
System.out.println("方法: " + method.getName());
System.out.println("远程地址: " + remoteUrl);
// 实际实现:
// 1. 将调用信息封装为Request
// 2. 序列化Request
// 3. 通过Netty发送到远程服务器
// 4. 接收Response并反序列化
// 5. 返回结果
// 模拟远程调用
return "REMOTE_RESULT";
}
);
}
}
八、代理模式的优缺点
8.1 优点
1. 职责清晰
真实对象:只关注业务逻辑
代理对象:负责访问控制、日志、缓存等
符合单一职责原则
2. 扩展性好
添加新功能无需修改真实对象
只需修改代理类或添加新代理
3. 保护真实对象
客户端不直接访问真实对象
通过代理控制访问权限
4. 智能引用
延迟加载:需要时才创建对象
引用计数:记录对象使用次数
8.2 缺点
1. 增加系统复杂度
每个真实对象可能需要一个代理
类的数量增加
2. 性能开销
代理模式会增加方法调用层次
反射调用比直接调用慢
3. 静态代理的维护成本
接口改变,代理也要改
代码重复,不够灵活
九、最佳实践
9.1 选择合适的代理方式
java
/**
* 代理方式选择指南
*/
class ProxySelector {
public static Object createProxy(Object target) {
Class<?>[] interfaces = target.getClass().getInterfaces();
if (interfaces.length > 0) {
// 有接口,优先使用JDK动态代理(性能更好)
System.out.println("使用JDK动态代理");
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
interfaces,
(proxy, method, args) -> method.invoke(target, args)
);
} else {
// 没有接口,使用CGLib代理
System.out.println("使用CGLib代理");
// return createCglibProxy(target);
return target;
}
}
}
9.2 代理链模式
java
/**
* 多个代理组成代理链
*/
class ProxyChain {
public static <T> T createProxyChain(T target) {
// 代理链:日志 → 性能监控 → 缓存 → 事务 → 真实对象
// 最内层:真实对象
T proxy = target;
// 第1层:事务代理
proxy = TransactionInvocationHandler.createProxy(proxy);
// 第2层:缓存代理
// proxy = CacheInvocationHandler.createProxy(proxy);
// 第3层:性能监控代理
// proxy = PerformanceInvocationHandler.createProxy(proxy);
// 第4层:日志代理
proxy = LoggingInvocationHandler.createProxy(proxy);
return proxy;
}
}
9.3 代理工厂统一管理
java
/**
* 代理工厂:统一创建和管理代理对象
*/
class ProxyFactory {
private static java.util.Map<Object, Object> proxyCache = new java.util.WeakHashMap<>();
/**
* 获取代理对象(带缓存)
*/
@SuppressWarnings("unchecked")
public static <T> T getProxy(T target, ProxyType type) {
// 检查缓存
if (proxyCache.containsKey(target)) {
return (T) proxyCache.get(target);
}
// 创建代理
T proxy;
switch (type) {
case LOGGING:
proxy = LoggingInvocationHandler.createProxy(target);
break;
case TRANSACTION:
proxy = TransactionInvocationHandler.createProxy(target);
break;
case LAZY_LOADING:
// proxy = LazyLoadingInvocationHandler.createProxy(...);
proxy = target;
break;
default:
proxy = target;
}
// 缓存代理对象
proxyCache.put(target, proxy);
return proxy;
}
enum ProxyType {
LOGGING,
TRANSACTION,
LAZY_LOADING
}
}
十、总结
10.1 核心要点
- 代理模式的本质:为对象提供代理以控制对它的访问
- 三种实现方式 :
- 静态代理:编译时确定,代码冗余
- JDK动态代理:运行时生成,只能代理接口
- CGLib动态代理:运行时生成,可代理类
- 适用场景 :
- 远程代理:RPC调用
- 虚拟代理:延迟加载
- 保护代理:权限控制
- 智能引用:日志、缓存、性能监控
10.2 使用建议
选择代理模式的检查清单:
✓ 是否需要控制对象的访问?
✓ 是否需要在方法执行前后添加额外逻辑?
✓ 是否需要延迟对象的创建?
✓ 是否需要为多个类添加相同的横切关注点?
如果以上都是"是",那么代理模式是个好选择!
10.3 代理 vs 装饰者 vs 适配器
代理模式:
- 目的:控制访问
- 接口:代理和真实对象相同
- 关系:代理控制真实对象
装饰者模式:
- 目的:增强功能
- 接口:装饰者和被装饰者相同
- 关系:装饰者包装被装饰者
适配器模式:
- 目的:接口转换
- 接口:适配器转换接口
- 关系:适配器转换被适配者
10.4 实践经验
- 优先使用动态代理:避免静态代理的代码冗余
- 合理选择代理技术:有接口用JDK,无接口用CGLib
- 注意性能开销:代理会增加调用层次
- 结合AOP使用:Spring AOP是代理模式的最佳实践