代理模式:控制对象访问的智能代表

摘要

代理模式(Proxy Pattern)是结构型设计模式中的"访问控制器",它通过创建代理对象来控制对原始对象的访问。本文将深入剖析代理模式的核心概念、实现方式、应用场景及高级变体,通过丰富的Java代码示例展示如何构建灵活的对象访问控制机制,并分析其与装饰器模式、适配器模式的区别与适用场景。

一、代理模式核心思想

代理模式的核心是控制访问,具有以下关键特征:

  1. 间接访问:通过代理对象间接访问目标对象
  2. 访问控制:代理对象控制对真实对象的访问权限
  3. 功能增强:可在不修改原对象的情况下添加额外功能
  4. 接口一致性:代理与真实对象实现相同接口

适用场景:

  • 需要控制对对象的访问权限
  • 需要延迟加载或远程访问
  • 需要添加对象访问的额外逻辑(如日志、监控)
  • 需要为消耗资源较大的对象提供轻量级代表

二、代理模式结构解析

UML类图示意

[Subject] <|-- [RealSubject]
[Subject] <|-- [Proxy]
[Proxy] o--> [RealSubject]

核心组件角色

角色 职责 典型实现
Subject 抽象主题 定义真实主题和代理的公共接口
RealSubject 真实主题 定义代理所代表的真实对象
Proxy 代理 维护对真实主题的引用,控制访问

三、基础实现:图片加载案例

// 抽象主题
interface Image {
    void display();
}

// 真实主题
class RealImage implements Image {
    private String filename;
    
    public RealImage(String filename) {
        this.filename = filename;
        loadFromDisk();
    }
    
    private void loadFromDisk() {
        System.out.println("Loading image: " + filename);
        // 模拟耗时加载
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
    
    @Override
    public void display() {
        System.out.println("Displaying image: " + filename);
    }
}

// 代理:虚拟代理(延迟加载)
class ProxyImage implements Image {
    private String filename;
    private RealImage realImage;
    
    public ProxyImage(String filename) {
        this.filename = filename;
    }
    
    @Override
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(filename);
        }
        realImage.display();
    }
}

// 客户端使用
public class ImageViewer {
    public static void main(String[] args) {
        Image image1 = new ProxyImage("photo1.jpg");
        Image image2 = new ProxyImage("photo2.jpg");
        
        // 图片未加载
        System.out.println("Images created, not loaded yet");
        
        // 第一次显示需要加载
        image1.display();
        
        // 第二次显示不需要加载
        image1.display();
        
        // 另一张图片
        image2.display();
    }
}

四、高级应用:动态代理机制

1. JDK动态代理

// 抽象主题
interface UserService {
    void addUser(String username);
    void deleteUser(String username);
}

// 真实主题
class UserServiceImpl implements UserService {
    public void addUser(String username) {
        System.out.println("Adding user: " + username);
    }
    
    public void deleteUser(String username) {
        System.out.println("Deleting user: " + username);
    }
}

// 调用处理器
class LoggingInvocationHandler implements InvocationHandler {
    private Object target;
    
    public LoggingInvocationHandler(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = method.invoke(target, args);
        long duration = System.currentTimeMillis() - start;
        
        System.out.printf("Executed %s in %d ms\n", method.getName(), duration);
        return result;
    }
}

// 使用示例
public class DynamicProxyDemo {
    public static void main(String[] args) {
        UserService realService = new UserServiceImpl();
        
        UserService proxy = (UserService) Proxy.newProxyInstance(
            UserService.class.getClassLoader(),
            new Class[]{UserService.class},
            new LoggingInvocationHandler(realService)
        );
        
        proxy.addUser("Alice");
        proxy.deleteUser("Bob");
    }
}

2. CGLIB动态代理

// 真实主题(无需接口)
class ProductService {
    public void saveProduct(String name) {
        System.out.println("Saving product: " + name);
    }
}

// 方法拦截器
class TransactionInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Starting transaction");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("Committing transaction");
        return result;
    }
}

// 使用示例
public class CglibProxyDemo {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(ProductService.class);
        enhancer.setCallback(new TransactionInterceptor());
        
        ProductService proxy = (ProductService) enhancer.create();
        proxy.saveProduct("Laptop");
    }
}

五、代理模式类型对比

代理类型对比表

代理类型 特点 适用场景 实现复杂度
虚拟代理 延迟加载 资源消耗大的对象 中等
保护代理 访问控制 权限敏感对象 中等
远程代理 网络通信 远程对象调用
缓存代理 结果缓存 重复计算场景 中等
动态代理 运行时生成 AOP编程

代理模式 vs 装饰器模式

维度 代理模式 装饰器模式
目的 控制访问 增强功能
对象创建 通常由代理控制 通常由客户端控制
关注点 访问机制 附加功能
生命周期 代理可管理目标生命周期 装饰器与组件独立
典型应用 延迟加载、访问控制 流处理、UI组件

六、企业级应用案例

1. Spring AOP代理

// 使用Spring AOP实现日志代理
@Aspect
@Component
public class LoggingAspect {
    
    @Before("execution(* com.example.service.*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Before method: " + joinPoint.getSignature().getName());
    }
    
    @Around("execution(* com.example.service.*.*(..))")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long duration = System.currentTimeMillis() - start;
        
        System.out.println(joinPoint.getSignature() + " executed in " + duration + "ms");
        return result;
    }
}

// 配置类
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.example")
public class AppConfig {
}

2. RPC框架远程代理

// RPC客户端代理
public class RpcProxy implements InvocationHandler {
    private Class<?> interfaceClass;
    private String host;
    private int port;
    
    public RpcProxy(Class<?> interfaceClass, String host, int port) {
        this.interfaceClass = interfaceClass;
        this.host = host;
        this.port = port;
    }
    
    public Object newInstance() {
        return Proxy.newProxyInstance(
            interfaceClass.getClassLoader(),
            new Class[]{interfaceClass},
            this
        );
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 构造请求
        RpcRequest request = new RpcRequest();
        request.setClassName(interfaceClass.getName());
        request.setMethodName(method.getName());
        request.setParams(args);
        request.setParamTypes(method.getParameterTypes());
        
        // 发送网络请求
        return sendRequest(request);
    }
    
    private Object sendRequest(RpcRequest request) {
        try (Socket socket = new Socket(host, port);
             ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
             ObjectInputStream ois = new ObjectInputStream(socket.getInputStream())) {
            
            oos.writeObject(request);
            return ois.readObject();
        } catch (Exception e) {
            throw new RuntimeException("RPC call failed", e);
        }
    }
}

// 使用示例
public class RpcClient {
    public static void main(String[] args) {
        UserService userService = (UserService) new RpcProxy(
            UserService.class, "localhost", 8080).newInstance();
        
        userService.addUser("Alice");
    }
}

七、代理模式最佳实践

1. 延迟初始化代理

// 线程安全的延迟初始化代理
class LazyInitializationProxy<T> implements InvocationHandler {
    private volatile T target;
    private Supplier<T> supplier;
    private final Object lock = new Object();
    
    public LazyInitializationProxy(Supplier<T> supplier) {
        this.supplier = supplier;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (target == null) {
            synchronized (lock) {
                if (target == null) {
                    target = supplier.get();
                }
            }
        }
        return method.invoke(target, args);
    }
    
    public static <T> T create(Class<T> interfaceClass, Supplier<T> supplier) {
        return (T) Proxy.newProxyInstance(
            interfaceClass.getClassLoader(),
            new Class[]{interfaceClass},
            new LazyInitializationProxy<>(supplier)
        );
    }
}

// 使用示例
DatabaseService heavyDBService = LazyInitializationProxy.create(
    DatabaseService.class, 
    () -> new HeavyDatabaseService()
);

2. 访问控制代理

// 保护代理实现
class AccessControlProxy implements InvocationHandler {
    private Object target;
    private User user;
    
    public AccessControlProxy(Object target, User user) {
        this.target = target;
        this.user = user;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.isAnnotationPresent(RequiresPermission.class)) {
            RequiresPermission annotation = method.getAnnotation(RequiresPermission.class);
            if (!user.hasPermission(annotation.value())) {
                throw new SecurityException("Access denied for " + method.getName());
            }
        }
        return method.invoke(target, args);
    }
}

// 权限注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface RequiresPermission {
    String value();
}

// 使用示例
public class SecureSystem {
    public static void main(String[] args) {
        User admin = new User("admin", Set.of("READ", "WRITE", "DELETE"));
        User guest = new User("guest", Set.of("READ"));
        
        DocumentService docService = new DocumentServiceImpl();
        
        DocumentService adminProxy = createProxy(docService, admin);
        DocumentService guestProxy = createProxy(docService, guest);
        
        adminProxy.readDocument(); // OK
        adminProxy.deleteDocument(); // OK
        
        guestProxy.readDocument(); // OK
        guestProxy.deleteDocument(); // 抛出SecurityException
    }
    
    private static DocumentService createProxy(DocumentService target, User user) {
        return (DocumentService) Proxy.newProxyInstance(
            DocumentService.class.getClassLoader(),
            new Class[]{DocumentService.class},
            new AccessControlProxy(target, user)
        );
    }
}

八、代理模式在开源框架中的应用

MyBatis的Mapper代理

// MyBatis通过动态代理实现Mapper接口
SqlSession session = sqlSessionFactory.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);

// 底层实现原理
public class MapperProxy<T> implements InvocationHandler {
    private final SqlSession sqlSession;
    private final Class<T> mapperInterface;
    
    public Object invoke(Object proxy, Method method, Object[] args) {
        // 将方法调用转换为SQL执行
        String statement = mapperInterface.getName() + "." + method.getName();
        return sqlSession.selectOne(statement, args[0]);
    }
}

Hibernate延迟加载

// Hibernate实体延迟加载代理
Session session = sessionFactory.openSession();
Product product = session.load(Product.class, 1L); // 返回代理对象

// 实际访问时加载数据
System.out.println(product.getName()); // 触发数据库查询

九、代理模式未来发展趋势

新兴应用方向:

  1. 微服务网关:API网关作为服务的代理
  2. 服务网格:Sidecar代理服务间通信
  3. 云函数:函数计算的事件代理
  4. 区块链智能合约:合约调用代理
  5. AI模型服务:模型推理代理

响应式代理模式

// Reactor中的代理模式应用
class ReactiveProxy<T> {
    private final Mono<T> target;
    
    public ReactiveProxy(Mono<T> target) {
        this.target = target.cache();
    }
    
    public Mono<Object> invoke(String methodName, Object... args) {
        return target.flatMap(instance -> {
            try {
                Method method = instance.getClass().getMethod(methodName);
                return Mono.fromCallable(() -> method.invoke(instance, args));
            } catch (Exception e) {
                return Mono.error(e);
            }
        });
    }
}

// 使用示例
ReactiveProxy<HeavyService> proxy = new ReactiveProxy<>(
    Mono.fromCallable(HeavyService::new).subscribeOn(Schedulers.boundedElastic())
);

proxy.invoke("expensiveOperation")
    .subscribe(result -> System.out.println("Result: " + result));

总结

代理模式是控制对象访问的强大工具,特别适合需要间接管理对象访问的场景。其核心价值体现在:

  1. 访问控制:精细控制对敏感对象的访问
  2. 功能增强:透明添加额外逻辑
  3. 资源优化:延迟加载和缓存优化资源使用
  4. 分布式支持:简化远程对象访问

现代应用关键点:

  • 合理选择代理类型:根据场景选择静态/动态代理
  • 性能考量:避免过度代理导致性能下降
  • 安全边界:保护代理需严格验证权限
  • 与AOP结合:利用AOP简化代理创建
  • 响应式支持:适应异步非阻塞编程模型

代理模式正在与云原生、服务网格等现代架构结合,演进出更强大的访问控制能力。掌握代理模式的精髓,将帮助开发者构建出更加安全、高效的系统架构。