设计模式之代理模式详解

深入理解设计模式之代理模式(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 核心要点

  1. 代理模式的本质:为对象提供代理以控制对它的访问
  2. 三种实现方式
    • 静态代理:编译时确定,代码冗余
    • JDK动态代理:运行时生成,只能代理接口
    • CGLib动态代理:运行时生成,可代理类
  3. 适用场景
    • 远程代理:RPC调用
    • 虚拟代理:延迟加载
    • 保护代理:权限控制
    • 智能引用:日志、缓存、性能监控

10.2 使用建议

复制代码
选择代理模式的检查清单:

✓ 是否需要控制对象的访问?
✓ 是否需要在方法执行前后添加额外逻辑?
✓ 是否需要延迟对象的创建?
✓ 是否需要为多个类添加相同的横切关注点?

如果以上都是"是",那么代理模式是个好选择!

10.3 代理 vs 装饰者 vs 适配器

复制代码
代理模式:
- 目的:控制访问
- 接口:代理和真实对象相同
- 关系:代理控制真实对象

装饰者模式:
- 目的:增强功能
- 接口:装饰者和被装饰者相同
- 关系:装饰者包装被装饰者

适配器模式:
- 目的:接口转换
- 接口:适配器转换接口
- 关系:适配器转换被适配者

10.4 实践经验

  1. 优先使用动态代理:避免静态代理的代码冗余
  2. 合理选择代理技术:有接口用JDK,无接口用CGLib
  3. 注意性能开销:代理会增加调用层次
  4. 结合AOP使用:Spring AOP是代理模式的最佳实践

相关推荐
小二·33 分钟前
Spring框架入门:代理模式详解
java·spring·代理模式
繁华似锦respect3 小时前
C++ 设计模式之观察者模式详细介绍
linux·开发语言·c++·windows·观察者模式·设计模式·visual studio
雨中飘荡的记忆3 小时前
设计模式之适配器模式详解
java·设计模式·适配器模式
phdsky3 小时前
【设计模式】工厂方法模式
c++·设计模式·工厂方法模式
cui17875684 小时前
重构消费模式:消费增值如何让 “花出去的钱” 回头找你?
大数据·人工智能·设计模式·重构·运维开发
雨中飘荡的记忆4 小时前
设计模式之建造者模式详解
java·设计模式·建造者模式
雨中飘荡的记忆4 小时前
设计模式之组合模式详解
设计模式·组合模式
繁华似锦respect5 小时前
C++ 设计模式之代理模式详细介绍
linux·开发语言·c++·windows·设计模式·代理模式·visual studio
__万波__17 小时前
二十三种设计模式(二)--工厂方法模式
java·设计模式·工厂方法模式