Skip to content

代理模式 (Proxy Pattern)

概述

代理模式(Proxy Pattern)是一种结构型设计模式,为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介的作用,并且可以通过代理对象来间接地操作目标对象。

简单来说,代理模式就是"找人代办",当我们不能或不想直接访问某个对象时,可以通过一个代理对象来间接访问。代理对象具有与被代理对象相同的接口,客户端通过代理对象来访问被代理对象,代理对象在转发请求的同时可以添加额外的处理逻辑。

代理模式的核心思想是控制访问,通过代理对象来:

  • 控制访问权限:检查客户端是否有权限访问目标对象
  • 延迟加载:只有在真正需要时才创建目标对象
  • 缓存结果:缓存目标对象的操作结果,提高性能
  • 记录日志:记录对目标对象的访问日志
  • 事务管理:在访问前后添加事务处理逻辑

使用场景

  • 远程代理:为位于远程服务器上的对象提供本地代理
  • 虚拟代理:延迟创建开销很大的对象,直到真正需要时才创建
  • 保护代理:控制对原始对象的访问权限
  • 智能引用代理:在访问对象时执行额外的操作,如引用计数、加载持久化对象等
  • 缓存代理:为开销大的运算结果提供暂时存储
  • 同步代理:在多线程环境中为目标对象提供安全的访问控制

类图结构

plaintext
┌─────────────────┐
│     Client      │
└─────────┬───────┘


┌─────────────────┐
│     Subject     │
│   (interface)   │
│ + request()     │
└─────────┬───────┘


    ┌─────┴─────┐
    │           │
    ▼           ▼
┌─────────────────┐  ┌─────────────────┐
│   RealSubject   │  │      Proxy      │
│                 │  │                 │
│ + request()     │  │ - realSubject   │
└─────────────────┘  │ + request()     │
                     │ + checkAccess() │
                     │ + logAccess()   │
                     └─────────────────┘
  • Subject:抽象主题,定义代理和真实主题的公共接口
  • RealSubject:真实主题,定义代理所代表的真实对象
  • Proxy:代理,保存一个引用使得代理可以访问实体,控制对实体的访问
  • Client:客户端,通过代理访问真实主题

示例

示例1:图片加载的虚拟代理

场景描述:在图片浏览器中,加载大图片需要较长时间。使用虚拟代理可以先显示占位符,在后台异步加载真实图片。

java
// 图片接口
public interface Image {
    void display();
    String getInfo();
}

// 真实图片类
public class RealImage implements Image {
    private String filename;
    private byte[] imageData;
    private boolean loaded = false;
    
    public RealImage(String filename) {
        this.filename = filename;
        System.out.println("创建 RealImage 对象:" + filename);
    }
    
    private void loadFromDisk() {
        if (!loaded) {
            System.out.println("从磁盘加载图片:" + filename);
            try {
                // 模拟加载时间
                Thread.sleep(2000);
                imageData = ("图片数据:" + filename).getBytes();
                loaded = true;
                System.out.println("图片加载完成:" + filename);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
    
    @Override
    public void display() {
        loadFromDisk();
        System.out.println("显示图片:" + filename + ", 大小:" + imageData.length + " bytes");
    }
    
    @Override
    public String getInfo() {
        return "真实图片:" + filename + (loaded ? " (已加载)" : " (未加载)");
    }
}

// 图片代理类
public class ImageProxy implements Image {
    private String filename;
    private RealImage realImage;
    private boolean accessGranted;
    
    public ImageProxy(String filename) {
        this.filename = filename;
        this.accessGranted = checkAccess();
        System.out.println("创建 ImageProxy 对象:" + filename);
    }
    
    private boolean checkAccess() {
        // 模拟权限检查
        boolean hasPermission = !filename.contains("private");
        System.out.println("权限检查:" + filename + " -> " + 
                         (hasPermission ? "允许访问" : "拒绝访问"));
        return hasPermission;
    }
    
    private void logAccess() {
        System.out.println("[访问日志] " + new java.util.Date() + 
                         " - 访问图片:" + filename);
    }
    
    @Override
    public void display() {
        logAccess();
        
        if (!accessGranted) {
            System.out.println("访问被拒绝:" + filename);
            return;
        }
        
        // 延迟创建真实对象
        if (realImage == null) {
            realImage = new RealImage(filename);
        }
        
        realImage.display();
    }
    
    @Override
    public String getInfo() {
        if (!accessGranted) {
            return "代理图片:" + filename + " (访问被拒绝)";
        }
        
        if (realImage == null) {
            return "代理图片:" + filename + " (未加载)";
        }
        
        return "代理图片:" + filename + " -> " + realImage.getInfo();
    }
}

// 图片浏览器
public class ImageViewer {
    private List<Image> images = new ArrayList<>();
    
    public void addImage(String filename) {
        // 使用代理,延迟加载
        images.add(new ImageProxy(filename));
    }
    
    public void showImage(int index) {
        if (index >= 0 && index < images.size()) {
            System.out.println("\n=== 显示第 " + (index + 1) + " 张图片 ===");
            images.get(index).display();
        }
    }
    
    public void showAllInfo() {
        System.out.println("\n=== 图片列表 ===");
        for (int i = 0; i < images.size(); i++) {
            System.out.println((i + 1) + ". " + images.get(i).getInfo());
        }
    }
}

// 客户端
public class ImageViewerClient {
    public static void main(String[] args) {
        ImageViewer viewer = new ImageViewer();
        
        // 添加图片(只创建代理,不加载真实图片)
        viewer.addImage("photo1.jpg");
        viewer.addImage("photo2.png");
        viewer.addImage("private_photo.jpg");
        viewer.addImage("landscape.jpg");
        
        System.out.println("\n=== 图片代理创建完成 ===");
        viewer.showAllInfo();
        
        // 只有在真正需要显示时才加载图片
        viewer.showImage(0);  // 加载并显示第一张图片
        viewer.showImage(2);  // 尝试显示私有图片(被拒绝)
        viewer.showImage(1);  // 加载并显示第二张图片
        
        System.out.println("\n=== 最终状态 ===");
        viewer.showAllInfo();
        
        // 再次显示已加载的图片(不会重新加载)
        System.out.println("\n=== 再次显示第一张图片 ===");
        viewer.showImage(0);
    }
}

示例2:数据库连接的保护代理

场景描述:数据库访问需要权限控制,使用保护代理可以在访问数据库前进行身份验证和权限检查。

java
// 数据库访问接口
public interface DatabaseAccess {
    List<String> query(String sql);
    boolean execute(String sql);
    void connect();
    void disconnect();
}

// 真实数据库访问类
public class RealDatabaseAccess implements DatabaseAccess {
    private String connectionString;
    private boolean connected = false;
    private Map<String, List<String>> mockData;
    
    public RealDatabaseAccess(String connectionString) {
        this.connectionString = connectionString;
        initMockData();
        System.out.println("创建真实数据库连接:" + connectionString);
    }
    
    private void initMockData() {
        mockData = new HashMap<>();
        mockData.put("users", Arrays.asList("Alice", "Bob", "Charlie"));
        mockData.put("products", Arrays.asList("Laptop", "Phone", "Tablet"));
        mockData.put("orders", Arrays.asList("Order1", "Order2", "Order3"));
    }
    
    @Override
    public void connect() {
        if (!connected) {
            System.out.println("连接到数据库:" + connectionString);
            try {
                Thread.sleep(1000); // 模拟连接时间
                connected = true;
                System.out.println("数据库连接成功");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
    
    @Override
    public void disconnect() {
        if (connected) {
            System.out.println("断开数据库连接");
            connected = false;
        }
    }
    
    @Override
    public List<String> query(String sql) {
        if (!connected) {
            throw new RuntimeException("数据库未连接");
        }
        
        System.out.println("执行查询:" + sql);
        
        // 简单的SQL解析
        String tableName = extractTableName(sql);
        List<String> result = mockData.getOrDefault(tableName, Arrays.asList("No data"));
        
        System.out.println("查询结果:" + result);
        return new ArrayList<>(result);
    }
    
    @Override
    public boolean execute(String sql) {
        if (!connected) {
            throw new RuntimeException("数据库未连接");
        }
        
        System.out.println("执行更新:" + sql);
        // 模拟执行时间
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        System.out.println("更新执行成功");
        return true;
    }
    
    private String extractTableName(String sql) {
        // 简单的表名提取
        String[] parts = sql.toLowerCase().split("\\s+");
        for (int i = 0; i < parts.length - 1; i++) {
            if ("from".equals(parts[i])) {
                return parts[i + 1];
            }
        }
        return "unknown";
    }
}

// 用户信息
public class User {
    private String username;
    private String role;
    private Set<String> permissions;
    
    public User(String username, String role, Set<String> permissions) {
        this.username = username;
        this.role = role;
        this.permissions = permissions;
    }
    
    public String getUsername() { return username; }
    public String getRole() { return role; }
    public Set<String> getPermissions() { return permissions; }
    
    public boolean hasPermission(String permission) {
        return permissions.contains(permission) || permissions.contains("ALL");
    }
}

// 数据库代理类
public class DatabaseProxy implements DatabaseAccess {
    private RealDatabaseAccess realDatabase;
    private String connectionString;
    private User currentUser;
    private List<String> accessLog;
    private Map<String, List<String>> queryCache;
    
    public DatabaseProxy(String connectionString) {
        this.connectionString = connectionString;
        this.accessLog = new ArrayList<>();
        this.queryCache = new HashMap<>();
        System.out.println("创建数据库代理");
    }
    
    public void setUser(User user) {
        this.currentUser = user;
        System.out.println("设置当前用户:" + user.getUsername() + " (" + user.getRole() + ")");
    }
    
    private boolean checkPermission(String operation) {
        if (currentUser == null) {
            System.out.println("权限检查失败:用户未登录");
            return false;
        }
        
        boolean hasPermission = currentUser.hasPermission(operation);
        System.out.println("权限检查:" + currentUser.getUsername() + 
                         " 执行 " + operation + " -> " + 
                         (hasPermission ? "允许" : "拒绝"));
        return hasPermission;
    }
    
    private void logAccess(String operation, String details) {
        String logEntry = String.format("[%s] 用户:%s 操作:%s 详情:%s",
                new java.util.Date(),
                currentUser != null ? currentUser.getUsername() : "未知",
                operation, details);
        accessLog.add(logEntry);
        System.out.println("[访问日志] " + logEntry);
    }
    
    @Override
    public void connect() {
        if (!checkPermission("CONNECT")) {
            throw new SecurityException("没有连接权限");
        }
        
        logAccess("CONNECT", connectionString);
        
        if (realDatabase == null) {
            realDatabase = new RealDatabaseAccess(connectionString);
        }
        realDatabase.connect();
    }
    
    @Override
    public void disconnect() {
        if (realDatabase != null) {
            logAccess("DISCONNECT", "");
            realDatabase.disconnect();
        }
    }
    
    @Override
    public List<String> query(String sql) {
        if (!checkPermission("READ")) {
            throw new SecurityException("没有查询权限");
        }
        
        logAccess("QUERY", sql);
        
        // 检查缓存
        List<String> cachedResult = queryCache.get(sql);
        if (cachedResult != null) {
            System.out.println("从缓存返回查询结果:" + cachedResult);
            return new ArrayList<>(cachedResult);
        }
        
        if (realDatabase == null) {
            connect();
        }
        
        List<String> result = realDatabase.query(sql);
        
        // 缓存结果
        queryCache.put(sql, new ArrayList<>(result));
        
        return result;
    }
    
    @Override
    public boolean execute(String sql) {
        if (!checkPermission("WRITE")) {
            throw new SecurityException("没有执行权限");
        }
        
        logAccess("EXECUTE", sql);
        
        if (realDatabase == null) {
            connect();
        }
        
        // 清除相关缓存
        queryCache.clear();
        System.out.println("清除查询缓存");
        
        return realDatabase.execute(sql);
    }
    
    public void printAccessLog() {
        System.out.println("\n=== 访问日志 ===");
        accessLog.forEach(System.out::println);
    }
    
    public void printCacheInfo() {
        System.out.println("\n=== 缓存信息 ===");
        System.out.println("缓存条目数:" + queryCache.size());
        queryCache.forEach((sql, result) -> 
            System.out.println("  " + sql + " -> " + result));
    }
}

// 客户端
public class DatabaseClient {
    public static void main(String[] args) {
        DatabaseProxy dbProxy = new DatabaseProxy("jdbc:mysql://localhost:3306/testdb");
        
        // 创建不同权限的用户
        User admin = new User("admin", "管理员", 
                            Set.of("CONNECT", "READ", "WRITE", "ALL"));
        User reader = new User("reader", "只读用户", 
                             Set.of("CONNECT", "READ"));
        User guest = new User("guest", "访客", 
                            Set.of());
        
        try {
            // 测试未登录访问
            System.out.println("=== 测试未登录访问 ===");
            try {
                dbProxy.query("SELECT * FROM users");
            } catch (SecurityException e) {
                System.out.println("捕获异常:" + e.getMessage());
            }
            
            // 测试管理员访问
            System.out.println("\n=== 测试管理员访问 ===");
            dbProxy.setUser(admin);
            dbProxy.query("SELECT * FROM users");
            dbProxy.query("SELECT * FROM products"); // 测试缓存
            dbProxy.query("SELECT * FROM users");    // 从缓存返回
            dbProxy.execute("UPDATE users SET name='Alice2' WHERE id=1");
            
            // 测试只读用户访问
            System.out.println("\n=== 测试只读用户访问 ===");
            dbProxy.setUser(reader);
            dbProxy.query("SELECT * FROM orders");
            try {
                dbProxy.execute("DELETE FROM orders WHERE id=1");
            } catch (SecurityException e) {
                System.out.println("捕获异常:" + e.getMessage());
            }
            
            // 测试访客访问
            System.out.println("\n=== 测试访客访问 ===");
            dbProxy.setUser(guest);
            try {
                dbProxy.query("SELECT * FROM users");
            } catch (SecurityException e) {
                System.out.println("捕获异常:" + e.getMessage());
            }
            
        } finally {
            dbProxy.disconnect();
            dbProxy.printAccessLog();
            dbProxy.printCacheInfo();
        }
    }
}

示例3:远程服务代理

场景描述:访问远程服务时,使用代理可以处理网络通信、序列化、重试等复杂逻辑。

java
// 远程服务接口
public interface RemoteService {
    String processData(String data);
    List<String> batchProcess(List<String> dataList);
    boolean isHealthy();
}

// 远程服务实现(模拟远程服务器上的实现)
public class RemoteServiceImpl implements RemoteService {
    private String serverName;
    private boolean healthy;
    
    public RemoteServiceImpl(String serverName) {
        this.serverName = serverName;
        this.healthy = Math.random() > 0.1; // 90% 概率健康
        System.out.println("远程服务启动:" + serverName + 
                         " (状态:" + (healthy ? "健康" : "故障") + ")");
    }
    
    @Override
    public String processData(String data) {
        if (!healthy) {
            throw new RuntimeException("服务不可用:" + serverName);
        }
        
        // 模拟处理时间
        try {
            Thread.sleep(100 + (int)(Math.random() * 200));
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        String result = "[" + serverName + "] 处理结果:" + data.toUpperCase();
        System.out.println("远程处理:" + data + " -> " + result);
        return result;
    }
    
    @Override
    public List<String> batchProcess(List<String> dataList) {
        return dataList.stream()
                .map(this::processData)
                .collect(Collectors.toList());
    }
    
    @Override
    public boolean isHealthy() {
        return healthy;
    }
    
    public void setHealthy(boolean healthy) {
        this.healthy = healthy;
    }
}

// 远程服务代理
public class RemoteServiceProxy implements RemoteService {
    private List<RemoteServiceImpl> servers;
    private int currentServerIndex = 0;
    private Map<String, String> cache;
    private int maxRetries = 3;
    private long cacheExpireTime = 5000; // 5秒缓存
    private Map<String, Long> cacheTimestamps;
    
    public RemoteServiceProxy(List<String> serverNames) {
        this.servers = serverNames.stream()
                .map(RemoteServiceImpl::new)
                .collect(Collectors.toList());
        this.cache = new ConcurrentHashMap<>();
        this.cacheTimestamps = new ConcurrentHashMap<>();
        System.out.println("创建远程服务代理,服务器数量:" + servers.size());
    }
    
    private RemoteServiceImpl getHealthyServer() {
        for (int i = 0; i < servers.size(); i++) {
            RemoteServiceImpl server = servers.get(currentServerIndex);
            currentServerIndex = (currentServerIndex + 1) % servers.size();
            
            if (server.isHealthy()) {
                return server;
            }
        }
        throw new RuntimeException("没有可用的服务器");
    }
    
    private boolean isCacheValid(String key) {
        Long timestamp = cacheTimestamps.get(key);
        return timestamp != null && 
               (System.currentTimeMillis() - timestamp) < cacheExpireTime;
    }
    
    private void putCache(String key, String value) {
        cache.put(key, value);
        cacheTimestamps.put(key, System.currentTimeMillis());
    }
    
    @Override
    public String processData(String data) {
        // 检查缓存
        if (isCacheValid(data)) {
            String cachedResult = cache.get(data);
            System.out.println("从缓存返回:" + data + " -> " + cachedResult);
            return cachedResult;
        }
        
        // 重试机制
        for (int retry = 0; retry < maxRetries; retry++) {
            try {
                RemoteServiceImpl server = getHealthyServer();
                String result = server.processData(data);
                
                // 缓存结果
                putCache(data, result);
                
                return result;
            } catch (Exception e) {
                System.out.println("第 " + (retry + 1) + " 次尝试失败:" + e.getMessage());
                
                if (retry == maxRetries - 1) {
                    throw new RuntimeException("所有重试都失败了", e);
                }
                
                // 等待后重试
                try {
                    Thread.sleep(1000 * (retry + 1));
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException("重试被中断", ie);
                }
            }
        }
        
        throw new RuntimeException("处理失败");
    }
    
    @Override
    public List<String> batchProcess(List<String> dataList) {
        System.out.println("批量处理 " + dataList.size() + " 个项目");
        
        return dataList.parallelStream()
                .map(this::processData)
                .collect(Collectors.toList());
    }
    
    @Override
    public boolean isHealthy() {
        return servers.stream().anyMatch(RemoteServiceImpl::isHealthy);
    }
    
    public void printStatus() {
        System.out.println("\n=== 服务状态 ===");
        for (int i = 0; i < servers.size(); i++) {
            RemoteServiceImpl server = servers.get(i);
            System.out.println("服务器 " + (i + 1) + ": " + 
                             (server.isHealthy() ? "健康" : "故障"));
        }
        
        System.out.println("\n=== 缓存状态 ===");
        System.out.println("缓存条目数:" + cache.size());
        cache.forEach((key, value) -> {
            boolean valid = isCacheValid(key);
            System.out.println("  " + key + " -> " + value + 
                             " (" + (valid ? "有效" : "过期") + ")");
        });
    }
    
    // 模拟服务器故障
    public void simulateServerFailure(int serverIndex) {
        if (serverIndex >= 0 && serverIndex < servers.size()) {
            servers.get(serverIndex).setHealthy(false);
            System.out.println("模拟服务器 " + (serverIndex + 1) + " 故障");
        }
    }
    
    // 模拟服务器恢复
    public void simulateServerRecovery(int serverIndex) {
        if (serverIndex >= 0 && serverIndex < servers.size()) {
            servers.get(serverIndex).setHealthy(true);
            System.out.println("模拟服务器 " + (serverIndex + 1) + " 恢复");
        }
    }
}

// 客户端
public class RemoteServiceClient {
    public static void main(String[] args) {
        // 创建远程服务代理
        RemoteServiceProxy proxy = new RemoteServiceProxy(
            Arrays.asList("Server-1", "Server-2", "Server-3"));
        
        try {
            System.out.println("=== 测试正常处理 ===");
            String result1 = proxy.processData("hello");
            String result2 = proxy.processData("world");
            String result3 = proxy.processData("hello"); // 应该从缓存返回
            
            System.out.println("\n=== 测试批量处理 ===");
            List<String> batchData = Arrays.asList("item1", "item2", "item3", "hello");
            List<String> batchResults = proxy.batchProcess(batchData);
            System.out.println("批量处理结果:" + batchResults);
            
            proxy.printStatus();
            
            System.out.println("\n=== 测试故障转移 ===");
            proxy.simulateServerFailure(0);
            proxy.simulateServerFailure(1);
            
            String result4 = proxy.processData("failover-test");
            System.out.println("故障转移结果:" + result4);
            
            System.out.println("\n=== 测试所有服务器故障 ===");
            proxy.simulateServerFailure(2);
            
            try {
                proxy.processData("all-failed");
            } catch (Exception e) {
                System.out.println("捕获异常:" + e.getMessage());
            }
            
            System.out.println("\n=== 测试服务器恢复 ===");
            proxy.simulateServerRecovery(1);
            String result5 = proxy.processData("recovery-test");
            System.out.println("恢复后结果:" + result5);
            
        } finally {
            proxy.printStatus();
        }
    }
}

优缺点分析

✅ 优点

优点说明
1. 控制访问可以在不修改目标对象的情况下控制对它的访问
2. 延迟加载可以延迟创建开销很大的对象,提高系统启动速度
3. 权限控制可以在代理中实现权限检查和访问控制
4. 缓存优化可以缓存目标对象的结果,提高性能
5. 日志记录可以记录对目标对象的访问日志
6. 远程访问可以隐藏远程调用的复杂性
7. 事务管理可以在访问前后添加事务处理逻辑

❌ 缺点

缺点说明
1. 增加复杂度增加了系统的复杂度,需要额外的代理类
2. 性能开销代理调用会增加一定的性能开销
3. 间接访问客户端不能直接访问目标对象,增加了间接性
4. 代理维护需要维护代理类与目标类的一致性
5. 调试困难增加了调试的复杂度,问题可能出现在代理层

和其他模式对比

模式本质思想与代理模式的区别
代理模式控制对象访问关注访问控制,代理与目标对象接口相同
装饰器模式动态添加功能关注功能扩展,可以层层装饰
适配器模式接口转换关注接口适配,连接不兼容的接口
外观模式简化复杂接口关注接口简化,提供统一的高层接口
桥接模式分离抽象和实现关注结构解耦,抽象和实现可以独立变化

在实际框架中的应用

1. Spring AOP 代理

Spring AOP 使用代理模式实现面向切面编程:

java
// 目标接口
public interface UserService {
    void createUser(String username);
    User findUser(String username);
}

// 目标实现
@Service
public class UserServiceImpl implements UserService {
    @Override
    public void createUser(String username) {
        System.out.println("创建用户:" + username);
    }
    
    @Override
    public User findUser(String username) {
        System.out.println("查找用户:" + username);
        return new User(username);
    }
}

// 切面
@Aspect
@Component
public class LoggingAspect {
    @Before("execution(* com.example.UserService.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("[AOP] 方法调用前:" + joinPoint.getSignature().getName());
    }
    
    @After("execution(* com.example.UserService.*(..))")
    public void logAfter(JoinPoint joinPoint) {
        System.out.println("[AOP] 方法调用后:" + joinPoint.getSignature().getName());
    }
}

// Spring 会自动创建代理对象
@RestController
public class UserController {
    @Autowired
    private UserService userService; // 这里注入的是代理对象
    
    @PostMapping("/users")
    public void createUser(@RequestParam String username) {
        userService.createUser(username); // 通过代理调用
    }
}

2. JPA/Hibernate 懒加载代理

JPA 使用代理模式实现懒加载:

java
@Entity
public class User {
    @Id
    private Long id;
    
    private String name;
    
    // 懒加载关联
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
    private List<Order> orders;
    
    // getters and setters
}

@Entity
public class Order {
    @Id
    private Long id;
    
    @ManyToOne(fetch = FetchType.LAZY)
    private User user; // 这里会创建代理对象
    
    // getters and setters
}

// 使用示例
@Service
public class OrderService {
    @Autowired
    private OrderRepository orderRepository;
    
    public void processOrder(Long orderId) {
        Order order = orderRepository.findById(orderId).get();
        
        // 此时 order.getUser() 返回的是代理对象
        User user = order.getUser();
        
        // 只有在真正访问用户属性时才会触发数据库查询
        String userName = user.getName(); // 触发懒加载
    }
}

3. Java 动态代理

Java 提供了内置的动态代理机制:

java
// 接口
public interface Calculator {
    int add(int a, int b);
    int subtract(int a, int b);
}

// 实现类
public class CalculatorImpl implements Calculator {
    @Override
    public int add(int a, int b) {
        return a + b;
    }
    
    @Override
    public int subtract(int a, int b) {
        return a - b;
    }
}

// 动态代理处理器
public class CalculatorInvocationHandler implements InvocationHandler {
    private Object target;
    
    public CalculatorInvocationHandler(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法调用前:" + method.getName());
        long startTime = System.currentTimeMillis();
        
        Object result = method.invoke(target, args);
        
        long endTime = System.currentTimeMillis();
        System.out.println("方法调用后:" + method.getName() + 
                         ", 耗时:" + (endTime - startTime) + "ms");
        
        return result;
    }
}

// 使用动态代理
public class DynamicProxyExample {
    public static void main(String[] args) {
        Calculator calculator = new CalculatorImpl();
        
        // 创建动态代理
        Calculator proxy = (Calculator) Proxy.newProxyInstance(
            calculator.getClass().getClassLoader(),
            calculator.getClass().getInterfaces(),
            new CalculatorInvocationHandler(calculator)
        );
        
        // 通过代理调用方法
        int result1 = proxy.add(10, 5);
        int result2 = proxy.subtract(10, 3);
        
        System.out.println("结果1:" + result1);
        System.out.println("结果2:" + result2);
    }
}

4. MyBatis Mapper 代理

MyBatis 使用代理模式为 Mapper 接口创建实现:

java
// Mapper 接口
public interface UserMapper {
    @Select("SELECT * FROM users WHERE id = #{id}")
    User findById(Long id);
    
    @Insert("INSERT INTO users(name, email) VALUES(#{name}, #{email})")
    void insert(User user);
}

// MyBatis 会为 Mapper 接口创建代理实现
@Service
public class UserService {
    @Autowired
    private UserMapper userMapper; // 这是代理对象
    
    public User getUser(Long id) {
        return userMapper.findById(id); // 代理会执行 SQL
    }
}

// 简化的 MyBatis 代理实现原理
public class MapperProxyFactory<T> {
    private final Class<T> mapperInterface;
    
    public MapperProxyFactory(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }
    
    @SuppressWarnings("unchecked")
    public T newInstance(SqlSession sqlSession) {
        MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface);
        return (T) Proxy.newProxyInstance(
            mapperInterface.getClassLoader(),
            new Class[]{mapperInterface},
            mapperProxy
        );
    }
}

public class MapperProxy<T> implements InvocationHandler {
    private final SqlSession sqlSession;
    private final Class<T> mapperInterface;
    
    public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface) {
        this.sqlSession = sqlSession;
        this.mapperInterface = mapperInterface;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 根据方法和注解执行相应的 SQL 操作
        if (method.isAnnotationPresent(Select.class)) {
            Select select = method.getAnnotation(Select.class);
            return sqlSession.selectOne(select.value()[0], args[0]);
        } else if (method.isAnnotationPresent(Insert.class)) {
            Insert insert = method.getAnnotation(Insert.class);
            return sqlSession.insert(insert.value()[0], args[0]);
        }
        
        return null;
    }
}

代理模式的变种和扩展

1. 智能代理

智能代理可以根据情况自动选择最优的处理策略:

java
public class SmartCacheProxy implements RemoteService {
    private RemoteService primaryService;
    private RemoteService backupService;
    private Map<String, CacheEntry> cache;
    private CircuitBreaker circuitBreaker;
    
    private static class CacheEntry {
        String value;
        long timestamp;
        long accessCount;
        
        CacheEntry(String value) {
            this.value = value;
            this.timestamp = System.currentTimeMillis();
            this.accessCount = 1;
        }
        
        void access() {
            accessCount++;
        }
        
        boolean isExpired(long ttl) {
            return System.currentTimeMillis() - timestamp > ttl;
        }
    }
    
    public SmartCacheProxy(RemoteService primary, RemoteService backup) {
        this.primaryService = primary;
        this.backupService = backup;
        this.cache = new ConcurrentHashMap<>();
        this.circuitBreaker = new CircuitBreaker();
    }
    
    @Override
    public String processData(String data) {
        // 1. 检查缓存
        CacheEntry entry = cache.get(data);
        if (entry != null && !entry.isExpired(5000)) {
            entry.access();
            System.out.println("智能缓存命中:" + data);
            return entry.value;
        }
        
        // 2. 选择服务
        RemoteService service = circuitBreaker.isOpen() ? backupService : primaryService;
        
        try {
            String result = service.processData(data);
            
            // 3. 智能缓存策略
            if (entry == null || entry.accessCount > 3) {
                cache.put(data, new CacheEntry(result));
            }
            
            circuitBreaker.recordSuccess();
            return result;
            
        } catch (Exception e) {
            circuitBreaker.recordFailure();
            
            // 降级处理
            if (entry != null) {
                System.out.println("使用过期缓存:" + data);
                return entry.value;
            }
            
            throw e;
        }
    }
    
    // 其他方法实现...
}

// 简单的断路器实现
class CircuitBreaker {
    private int failureCount = 0;
    private long lastFailureTime = 0;
    private final int threshold = 3;
    private final long timeout = 10000; // 10秒
    
    public boolean isOpen() {
        if (failureCount >= threshold) {
            return System.currentTimeMillis() - lastFailureTime < timeout;
        }
        return false;
    }
    
    public void recordSuccess() {
        failureCount = 0;
    }
    
    public void recordFailure() {
        failureCount++;
        lastFailureTime = System.currentTimeMillis();
    }
}

2. 组合代理

多个代理可以组合使用,形成代理链:

java
// 基础代理接口
public abstract class BaseProxy implements RemoteService {
    protected RemoteService target;
    
    public BaseProxy(RemoteService target) {
        this.target = target;
    }
}

// 日志代理
public class LoggingProxy extends BaseProxy {
    public LoggingProxy(RemoteService target) {
        super(target);
    }
    
    @Override
    public String processData(String data) {
        System.out.println("[LOG] 开始处理:" + data);
        try {
            String result = target.processData(data);
            System.out.println("[LOG] 处理成功:" + result);
            return result;
        } catch (Exception e) {
            System.out.println("[LOG] 处理失败:" + e.getMessage());
            throw e;
        }
    }
    
    // 其他方法实现...
}

// 性能监控代理
public class PerformanceProxy extends BaseProxy {
    public PerformanceProxy(RemoteService target) {
        super(target);
    }
    
    @Override
    public String processData(String data) {
        long startTime = System.currentTimeMillis();
        try {
            String result = target.processData(data);
            long duration = System.currentTimeMillis() - startTime;
            System.out.println("[PERF] 处理耗时:" + duration + "ms");
            return result;
        } catch (Exception e) {
            long duration = System.currentTimeMillis() - startTime;
            System.out.println("[PERF] 失败耗时:" + duration + "ms");
            throw e;
        }
    }
    
    // 其他方法实现...
}

// 缓存代理
public class CachingProxy extends BaseProxy {
    private Map<String, String> cache = new ConcurrentHashMap<>();
    
    public CachingProxy(RemoteService target) {
        super(target);
    }
    
    @Override
    public String processData(String data) {
        String cached = cache.get(data);
        if (cached != null) {
            System.out.println("[CACHE] 缓存命中:" + data);
            return cached;
        }
        
        String result = target.processData(data);
        cache.put(data, result);
        System.out.println("[CACHE] 缓存存储:" + data);
        return result;
    }
    
    // 其他方法实现...
}

// 代理链构建器
public class ProxyChainBuilder {
    public static RemoteService buildChain(RemoteService target) {
        // 构建代理链:日志 -> 性能监控 -> 缓存 -> 目标对象
        return new LoggingProxy(
            new PerformanceProxy(
                new CachingProxy(target)
            )
        );
    }
}

// 使用示例
public class ProxyChainExample {
    public static void main(String[] args) {
        RemoteService realService = new RemoteServiceImpl("RealServer");
        RemoteService proxyChain = ProxyChainBuilder.buildChain(realService);
        
        // 第一次调用
        proxyChain.processData("test1");
        
        // 第二次调用(应该命中缓存)
        proxyChain.processData("test1");
        
        // 第三次调用(新数据)
        proxyChain.processData("test2");
    }
}

实际项目中的最佳实践

1. 代理模式的选择策略

java
// 代理类型枚举
public enum ProxyType {
    VIRTUAL,    // 虚拟代理
    PROTECTION, // 保护代理
    REMOTE,     // 远程代理
    CACHE,      // 缓存代理
    SMART       // 智能代理
}

// 代理工厂
public class ProxyFactory {
    public static <T> T createProxy(Class<T> interfaceType, T target, ProxyType... types) {
        Object proxy = target;
        
        // 根据类型创建代理链
        for (ProxyType type : types) {
            switch (type) {
                case VIRTUAL:
                    proxy = createVirtualProxy(interfaceType, proxy);
                    break;
                case PROTECTION:
                    proxy = createProtectionProxy(interfaceType, proxy);
                    break;
                case CACHE:
                    proxy = createCacheProxy(interfaceType, proxy);
                    break;
                // 其他类型...
            }
        }
        
        return interfaceType.cast(proxy);
    }
    
    @SuppressWarnings("unchecked")
    private static <T> T createVirtualProxy(Class<T> interfaceType, Object target) {
        return (T) Proxy.newProxyInstance(
            interfaceType.getClassLoader(),
            new Class[]{interfaceType},
            new VirtualProxyHandler(target)
        );
    }
    
    // 其他代理创建方法...
}

// 虚拟代理处理器
class VirtualProxyHandler implements InvocationHandler {
    private Object target;
    private volatile boolean initialized = false;
    
    public VirtualProxyHandler(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (!initialized) {
            synchronized (this) {
                if (!initialized) {
                    System.out.println("延迟初始化目标对象");
                    // 这里可以进行复杂的初始化逻辑
                    initialized = true;
                }
            }
        }
        
        return method.invoke(target, args);
    }
}

2. 代理性能优化

java
// 高性能代理实现
public class HighPerformanceProxy implements InvocationHandler {
    private final Object target;
    private final Map<Method, MethodHandler> methodHandlers;
    
    public HighPerformanceProxy(Object target) {
        this.target = target;
        this.methodHandlers = new ConcurrentHashMap<>();
        precomputeMethodHandlers();
    }
    
    private void precomputeMethodHandlers() {
        Class<?> targetClass = target.getClass();
        for (Method method : targetClass.getMethods()) {
            methodHandlers.put(method, createMethodHandler(method));
        }
    }
    
    private MethodHandler createMethodHandler(Method method) {
        // 根据方法特征创建优化的处理器
        if (method.getName().startsWith("get")) {
            return new CachedMethodHandler(method);
        } else if (method.getName().startsWith("set")) {
            return new DirectMethodHandler(method);
        } else {
            return new LoggedMethodHandler(method);
        }
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodHandler handler = methodHandlers.get(method);
        return handler.handle(target, args);
    }
    
    // 方法处理器接口
    interface MethodHandler {
        Object handle(Object target, Object[] args) throws Throwable;
    }
    
    // 缓存方法处理器
    static class CachedMethodHandler implements MethodHandler {
        private final Method method;
        private final Map<Object, Object> cache = new ConcurrentHashMap<>();
        
        CachedMethodHandler(Method method) {
            this.method = method;
        }
        
        @Override
        public Object handle(Object target, Object[] args) throws Throwable {
            Object key = Arrays.toString(args);
            return cache.computeIfAbsent(key, k -> {
                try {
                    return method.invoke(target, args);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
        }
    }
    
    // 直接方法处理器
    static class DirectMethodHandler implements MethodHandler {
        private final Method method;
        
        DirectMethodHandler(Method method) {
            this.method = method;
        }
        
        @Override
        public Object handle(Object target, Object[] args) throws Throwable {
            return method.invoke(target, args);
        }
    }
    
    // 日志方法处理器
    static class LoggedMethodHandler implements MethodHandler {
        private final Method method;
        
        LoggedMethodHandler(Method method) {
            this.method = method;
        }
        
        @Override
        public Object handle(Object target, Object[] args) throws Throwable {
            System.out.println("调用方法:" + method.getName());
            Object result = method.invoke(target, args);
            System.out.println("方法返回:" + result);
            return result;
        }
    }
}

3. 代理模式的监控和调试

java
// 代理监控器
public class ProxyMonitor {
    private static final Map<String, ProxyMetrics> metricsMap = new ConcurrentHashMap<>();
    
    public static void recordMethodCall(String proxyName, String methodName, long duration, boolean success) {
        ProxyMetrics metrics = metricsMap.computeIfAbsent(proxyName, ProxyMetrics::new);
        metrics.recordCall(methodName, duration, success);
    }
    
    public static void printMetrics() {
        System.out.println("\n=== 代理性能指标 ===");
        metricsMap.forEach((name, metrics) -> {
            System.out.println("代理:" + name);
            metrics.print();
            System.out.println();
        });
    }
    
    static class ProxyMetrics {
        private final String proxyName;
        private final Map<String, MethodMetrics> methodMetrics = new ConcurrentHashMap<>();
        
        ProxyMetrics(String proxyName) {
            this.proxyName = proxyName;
        }
        
        void recordCall(String methodName, long duration, boolean success) {
            methodMetrics.computeIfAbsent(methodName, MethodMetrics::new)
                         .record(duration, success);
        }
        
        void print() {
            methodMetrics.forEach((method, metrics) -> {
                System.out.printf("  %s: 调用%d次, 成功率%.1f%%, 平均耗时%.1fms%n",
                    method, metrics.totalCalls, metrics.getSuccessRate(), metrics.getAverageDuration());
            });
        }
    }
    
    static class MethodMetrics {
        private final String methodName;
        private final AtomicLong totalCalls = new AtomicLong();
        private final AtomicLong successCalls = new AtomicLong();
        private final AtomicLong totalDuration = new AtomicLong();
        
        MethodMetrics(String methodName) {
            this.methodName = methodName;
        }
        
        void record(long duration, boolean success) {
            totalCalls.incrementAndGet();
            totalDuration.addAndGet(duration);
            if (success) {
                successCalls.incrementAndGet();
            }
        }
        
        double getSuccessRate() {
            long total = totalCalls.get();
            return total > 0 ? (double) successCalls.get() / total * 100 : 0;
        }
        
        double getAverageDuration() {
            long total = totalCalls.get();
            return total > 0 ? (double) totalDuration.get() / total : 0;
        }
    }
}

// 监控代理处理器
public class MonitoringProxyHandler implements InvocationHandler {
    private final Object target;
    private final String proxyName;
    
    public MonitoringProxyHandler(Object target, String proxyName) {
        this.target = target;
        this.proxyName = proxyName;
    }
    
    @Override
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
         long startTime = System.currentTimeMillis();
         boolean success = false;
         
         try {
             Object result = method.invoke(target, args);
             success = true;
             return result;
         } catch (Exception e) {
             success = false;
             throw e;
         } finally {
             long duration = System.currentTimeMillis() - startTime;
             ProxyMonitor.recordMethodCall(proxyName, method.getName(), duration, success);
         }
     }
}

总结

代理模式是一种非常实用的设计模式,它通过引入代理对象来控制对目标对象的访问。代理模式的核心价值在于:

🎯 核心价值

  1. 访问控制:可以在不修改原有代码的情况下添加访问控制逻辑
  2. 性能优化:通过缓存、延迟加载等技术提高系统性能
  3. 功能增强:可以在原有功能基础上添加日志、监控、事务等横切关注点
  4. 解耦合:客户端与真实对象解耦,便于系统扩展和维护

📋 使用建议

  1. 选择合适的代理类型:根据具体需求选择虚拟代理、保护代理、远程代理等
  2. 注意性能开销:代理会增加一定的性能开销,需要权衡利弊
  3. 保持接口一致性:代理对象应该与目标对象实现相同的接口
  4. 合理使用代理链:多个代理可以组合使用,但要注意复杂度控制
  5. 考虑线程安全:在多线程环境中要确保代理的线程安全性

🚀 实际应用

代理模式在现代软件开发中应用广泛:

  • Spring AOP:面向切面编程的核心实现机制
  • ORM 框架:如 Hibernate 的懒加载机制
  • RPC 框架:如 Dubbo、gRPC 的客户端代理
  • 缓存系统:Redis、Memcached 的客户端代理
  • 安全框架:如 Spring Security 的权限控制

代理模式体现了"控制访问"的设计思想,是构建灵活、可扩展系统的重要工具。通过合理运用代理模式,我们可以在不修改原有代码的基础上,为系统添加各种增强功能,提高代码的可维护性和可扩展性。