Java设计模式-代理模式

代理模式是一种结构型设计模式:为 "某个对象" 提供一种 "代理对象" 以控制对它的访问。调用方不直接引用原对象,而是引用代理;代理在"把请求转给原对象的前/后"附加额外逻辑(缓存、鉴权、延迟加载、事务、日志、熔断、AOP 等)。

一、三种实现方式

实现方式 原理与场景 优点 缺点
静态代理 为每一个被代理类 手工编写 一个代理类,编译期就确定代理逻辑 简单,易调试 代理类爆炸,难维护
JDK 动态代理 JDK 反射 运行时生成 代理类,要求被代理类 必须实现接口 无侵入,代码量小,官方支持 只能代理接口
CGLIB 动态代理 ASM 字节码库 运行时生成 被代理类的子类,覆盖方法 能代理(无接口也行) 不能代理 final 类/方法

注:Spring AOP 默认用 JDK 动态代理;若目标无接口则自动切换到 CGLIB。

二、静态代理示例

  1. 抽象主题:定义业务方法
java 复制代码
public interface OrderService {
    void createOrder(long userId, String itemNo);
}
  1. 真实主题:真正的业务实现(可能部署在远程 / 访问开销很大)
java 复制代码
public class OrderServiceImpl implements OrderService {
    @Override
    public void createOrder(long userId, String itemNo) {
        // 业务:落库、扣库存、推送消息 ...
        System.out.printf("为用户 %d 创建订单,商品 %s%n", userId, itemNo);
    }
}
  1. 代理:给 createOrder 前后加"鉴权 + 耗时统计"
java 复制代码
public class OrderServiceProxy implements OrderService {
    private final OrderService target;  // 被代理对象

    public OrderServiceProxy(OrderService target) {
        this.target = target;
    }

    @Override
    public void createOrder(long userId, String itemNo) {
        preCheck(userId);        // 前置增强
        long s = System.nanoTime();
        target.createOrder(userId, itemNo);  // 真正的业务
        long cost = System.nanoTime() - s;
        System.out.println("  ==> 耗时(ms) = " + cost / 1_000_000.0);
    }

    private void preCheck(long userId) {
        System.out.println("鉴权... 用户ID = " + userId);
    }
}
  1. 客户端
java 复制代码
OrderService real = new OrderServiceImpl();
OrderService proxy = new OrderServiceProxy(real);
proxy.createOrder(1001L, "A20240522");

输出

java 复制代码
鉴权... 用户ID = 1001
为用户 1001 创建订单,商品 A20240522
  ==> 耗时(ms) = 0.52

缺点:接口一多,就要编写 N 个 XxxServiceProxy,后期难以维护。

三、JDK 动态代理示例

核心类:java.lang.reflect.Proxy + InvocationHandler

  1. 编写 InvocationHandler
java 复制代码
public class MetricInvocationHandler implements InvocationHandler {
    private final Object target;        // 真正业务对象

    public MetricInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long s = System.nanoTime();
        Object ret = method.invoke(target, args);
        System.out.printf("方法 %s 执行耗时(ms): %.2f%n",
                method.getName(), (System.nanoTime() - s) / 1_000_000.0);
        return ret;
    }
}
  1. 生成并调用代理
java 复制代码
OrderService real = new OrderServiceImpl();
OrderService proxy = (OrderService) Proxy.newProxyInstance(
        OrderService.class.getClassLoader(),   // 类加载器
        new Class<?>[]{OrderService.class},    // 需要实现的接口
        new MetricInvocationHandler(real));

proxy.createOrder(1002L, "B20240522");

输出

java 复制代码
为用户 1002 创建订单,商品 B20240522
方法 createOrder 执行耗时(ms): 0.30

注:JDK 动态代理只能在 运行时 生成代理对象,无法代理类本身的方法(如 OrderServiceImpl 中未定义在接口的方法)。

四、CGLIB 动态代理示例

引用库:cglib 或 spring-core(已含 cglib)

java 复制代码
public class CglibMetricInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
            throws Throwable {
        long s = System.nanoTime();
        Object ret = proxy.invokeSuper(obj, args);   // 调用父类(真实类)方法
        System.out.printf("CGLIB: %s 耗时(ms) %.2f%n",
                method.getName(), (System.nanoTime() - s) / 1_000_000.0);
        return ret;
    }
}

使用

java 复制代码
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OrderServiceImpl.class);                 // 被代理类
enhancer.setCallback(new CglibMetricInterceptor());
OrderServiceImpl proxy = (OrderServiceImpl) enhancer.create();
proxy.createOrder(1003L, "C20240522");

五、常见 UML 类图

复制代码
                 +----------------+
        ------>  | <<interface>> |
      uses       |  Subject      |
   RealSubject   +-------+-------+
   / Proxy              |
                        |
         +--------------+-------------+
         |                            |
   +-----+-------+             +------+------+
   | RealSubject | implements  |   Proxy     |
   +-------------+             +-------------+

六、与其他模式的关系

  • 装饰器模式:都通过"组合"包装对象,但装饰器更强调"功能叠加",而不控制访问。
  • 门面模式:门面做"高层封装",代理做"同层"的替代。
  • 桥接模式:两者都解耦抽象与实现,但侧重点不同。
  • Spring AOP:本质就是动态代理(JDK / CGLIB)。

七、最佳实践

  1. 延迟加载 ------ Hibernate / MyBatis:只有在第一次调用时才真正去查库。
  2. 保护代理 ------ 权限框架:代理层统一鉴权。
  3. 远程代理 ------ RPC:Stub 封装网络通信。
  4. 缓存代理 ------ 读取前查缓存,写后更新缓存。
  5. 日志/监控 ------ 微服务 Sidecar、链路追踪。
相关推荐
starzy199024 分钟前
Flink基础之Per-Job-Cluster原理详解:被 Application 取代的模式
java·大数据·flink
魏 无羡7 小时前
webclient
java·webclient
神仙别闹8 小时前
基于 C++ 实现两个有序链表序列的交集
java·c++·链表
swordbob9 小时前
ReentrantLock 与 AQS 完整学习手册
java·开发语言
m0_587383009 小时前
全民健身解决方案软件开发实战:从架构设计到落地指南
java·spring boot·spring·架构·需求分析
白山编程大哥9 小时前
Java OutputStreamWriter 详解:从字符到字节的桥梁
java·开发语言·python
一技安身10 小时前
【信创】Docker‑Compose V2 两种离线部署(独立模式、插件模式)简易教程
java·docker·eureka
七夜zippoe11 小时前
为什么 2026 年每个 Java 团队都该懂 AI Agent
java·开发语言·人工智能
时凌云.11 小时前
【2026最新】JDK 下载安装与环境配置全教程(Windows/Mac/Linux 三平台,零基础友好)
java·linux·macos
Despacito100611 小时前
Java后端性能探查工具速查表
java·开发语言