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、链路追踪。
相关推荐
小咕聊编程22 分钟前
【含文档+PPT+源码】基于spring boot的固定资产管理系统
java·spring boot·后端
roykingw23 分钟前
【终极面试集锦】如何设计微服务熔断体系?
java·微服务·面试
我命由我1234523 分钟前
Spring Cloud - Spring Cloud 微服务概述 (微服务的产生与特点、微服务的优缺点、微服务设计原则、微服务架构的核心组件)
java·运维·spring·spring cloud·微服务·架构·java-ee
それども26 分钟前
忽略Lombok构建警告
java·开发语言·jvm
用户685453759776933 分钟前
🎮 Java设计模式:从青铜到王者的代码修炼手册
java·后端
马尚道1 小时前
Java高手速成--吃透源码+手写组件+定制开发教程
java
我命由我123451 小时前
Spring Cloud - Spring Cloud 注册中心与服务提供者(Spring Cloud Eureka 概述、微服务快速入门、微服务应用实例)
java·spring boot·spring·spring cloud·微服务·eureka·java-ee
MetaverseMan1 小时前
Java Spring 框架的`@Autowired` 注解 以及依赖注入分析
java·开发语言·spring
一吃就胖的1 小时前
【给服务器安装服务器安装nacos】
java·运维·服务器
码住懒羊羊1 小时前
【C++】stack|queue|deque
java·开发语言·c++