23种设计模式23种设计模式
首页
介绍
  • 单例模式
  • 工厂方法模式
  • 抽象工厂模式
  • 建造者模式
  • 原型模式
  • 适配器模式
  • 桥接模式
  • 组合模式
  • 装饰器模式
  • 外观模式
  • 享元模式
  • 代理模式
  • 责任链模式
  • 命令模式
  • 解释器模式
  • 迭代器模式
  • 中介者模式
  • 备忘录模式
  • 观察者模式
  • 状态模式
  • 策略模式
  • 模板方法模式
  • 访问者模式
🚀 编程指南
首页
介绍
  • 单例模式
  • 工厂方法模式
  • 抽象工厂模式
  • 建造者模式
  • 原型模式
  • 适配器模式
  • 桥接模式
  • 组合模式
  • 装饰器模式
  • 外观模式
  • 享元模式
  • 代理模式
  • 责任链模式
  • 命令模式
  • 解释器模式
  • 迭代器模式
  • 中介者模式
  • 备忘录模式
  • 观察者模式
  • 状态模式
  • 策略模式
  • 模板方法模式
  • 访问者模式
🚀 编程指南
  • 结构型模式

    • 适配器模式 (Adapter)
    • 桥接模式 (Bridge)
    • 组合模式 (Composite)
    • 装饰器模式 (Decorator)
    • 外观模式 (Facade)
    • 享元模式 (Flyweight)
    • 代理模式 (Proxy)

代理模式 (Proxy)

📖 通俗理解

你要租房,但不想自己到处找房源、谈价格、签合同。怎么办?

找个房产中介!中介帮你找房、带看、谈价格、办手续,你只需要付钱入住。

代理模式就是:为对象提供一个代理,控制对这个对象的访问。

🎯 解决什么问题?

场景:

  • 访问对象前需要做一些控制(权限、日志、缓存)
  • 对象创建开销很大,希望延迟创建
  • 远程对象需要本地代理

🌰 生活中的例子

  • 房产中介:代理房东出租房子
  • 明星经纪人:代理明星接洽工作
  • VPN 代理:代理访问网络
  • 信用卡:代理你的银行账户消费

💻 Java 代码实现

方式一:静态代理

/**
 * 主题接口
 */
public interface Subject {
    void request();
}

/**
 * 真实主题
 */
public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("真实对象处理请求...");
    }
}

/**
 * 代理类
 */
public class Proxy implements Subject {
    
    private RealSubject realSubject;
    
    @Override
    public void request() {
        // 前置处理
        System.out.println("代理:权限检查...");
        System.out.println("代理:记录日志...");
        
        // 延迟创建真实对象
        if (realSubject == null) {
            realSubject = new RealSubject();
        }
        
        // 调用真实对象
        realSubject.request();
        
        // 后置处理
        System.out.println("代理:清理工作...");
    }
}

使用:

public class Client {
    public static void main(String[] args) {
        Subject subject = new Proxy();
        subject.request();
    }
}

方式二:JDK 动态代理 ⭐

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 服务接口
 */
public interface UserService {
    void addUser(String name);
    void deleteUser(String name);
}

/**
 * 真实服务
 */
public class UserServiceImpl implements UserService {
    @Override
    public void addUser(String name) {
        System.out.println("添加用户: " + name);
    }
    
    @Override
    public void deleteUser(String name) {
        System.out.println("删除用户: " + name);
    }
}

/**
 * 动态代理处理器
 */
public class LogHandler implements InvocationHandler {
    
    private Object target;
    
    public LogHandler(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 前置增强
        System.out.println("[日志] 调用方法: " + method.getName());
        long start = System.currentTimeMillis();
        
        // 调用真实方法
        Object result = method.invoke(target, args);
        
        // 后置增强
        long end = System.currentTimeMillis();
        System.out.println("[日志] 方法执行耗时: " + (end - start) + "ms\n");
        
        return result;
    }
    
    /**
     * 创建代理对象
     */
    @SuppressWarnings("unchecked")
    public static <T> T createProxy(T target) {
        return (T) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            new LogHandler(target)
        );
    }
}

使用:

public class Client {
    public static void main(String[] args) {
        UserService realService = new UserServiceImpl();
        UserService proxyService = LogHandler.createProxy(realService);
        
        proxyService.addUser("张三");
        proxyService.deleteUser("李四");
    }
}

输出:

[日志] 调用方法: addUser
添加用户: 张三
[日志] 方法执行耗时: 1ms

[日志] 调用方法: deleteUser
删除用户: 李四
[日志] 方法执行耗时: 0ms

方式三:CGLIB 动态代理

CGLIB 可以代理没有接口的类:

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * 没有接口的类
 */
public class OrderService {
    public void createOrder(String orderId) {
        System.out.println("创建订单: " + orderId);
    }
}

/**
 * CGLIB 方法拦截器
 */
public class CglibInterceptor implements MethodInterceptor {
    
    @Override
    public Object intercept(Object obj, Method method, Object[] args, 
                           MethodProxy proxy) throws Throwable {
        System.out.println("[CGLIB] 方法调用前...");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("[CGLIB] 方法调用后...");
        return result;
    }
    
    @SuppressWarnings("unchecked")
    public static <T> T createProxy(Class<T> clazz) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(new CglibInterceptor());
        return (T) enhancer.create();
    }
}

// 使用
OrderService proxy = CglibInterceptor.createProxy(OrderService.class);
proxy.createOrder("ORD001");

🔥 常见代理类型

代理类型说明例子
远程代理为远程对象提供本地代理RMI、RPC
虚拟代理延迟创建开销大的对象懒加载图片
保护代理控制对象的访问权限权限校验
缓存代理为结果提供缓存数据缓存

✅ 适用场景

  1. AOP 切面编程:日志、事务、权限
  2. 延迟加载:大对象的延迟初始化
  3. 远程调用:RPC 框架
  4. 访问控制:权限检查

⚠️ JDK 代理 vs CGLIB

对比项JDK 动态代理CGLIB
要求必须有接口可以没有接口
原理实现接口继承类
性能稍慢稍快

小结

代理模式的核心:为对象提供一个替身,控制对这个对象的访问。

Spring AOP 底层就是使用代理模式(JDK 动态代理 + CGLIB)。

👉 下一篇:责任链模式

Prev
享元模式 (Flyweight)