设计模式之代理模式详解

深入理解设计模式之代理模式(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是代理模式的最佳实践

相关推荐
杨充19 小时前
10.可测试性实战设计
设计模式·开源·代码规范
杨充19 小时前
9.重构十二式的实战
设计模式·开源·代码规范
杨充19 小时前
6.设计原则的全景图
设计模式·开源·全栈
杨充19 小时前
2.面向对象的特性
设计模式
杨充19 小时前
7.SOLID原则案例汇
设计模式·开源·全栈
杨充19 小时前
8.反模式与坏味道
设计模式·开源·代码规范
杨充19 小时前
3.接口vs抽象类比较
设计模式
咖啡八杯1 天前
文法、BNF与AST
java·设计模式·解释器模式·ast·文法
咖啡八杯1 天前
GoF设计模式——解释器模式
java·后端·spring·设计模式