Skip to content
Method约 1 分钟0 个小节更新于 2026/06/19在线编辑

代理模式

代理模式用于给目标对象提供一个代理对象,通过代理控制对目标对象的访问。

一句话理解:调用目标对象之前,先经过代理这一层。

解决什么问题

有些逻辑不属于目标对象本身,但又希望在访问目标对象时统一处理:

  • 权限校验。
  • 日志记录。
  • 性能监控。
  • 事务控制。
  • 缓存。
  • 远程调用。
  • 延迟加载。

如果这些逻辑直接写进业务类,会污染业务代码。代理模式把访问控制和增强逻辑放到代理对象中。

基本结构

text
Client -> Subject
          ^
          |
        Proxy -> RealSubject

角色:

  • Subject:目标接口。
  • RealSubject:真实对象。
  • Proxy:代理对象,持有真实对象。

静态代理

接口:

java
interface UserService {
    void createUser(String username);
}

真实对象:

java
class UserServiceImpl implements UserService {
    public void createUser(String username) {
        System.out.println("create user: " + username);
    }
}

代理对象:

java
class UserServiceProxy implements UserService {
    private final UserService target;

    UserServiceProxy(UserService target) {
        this.target = target;
    }

    public void createUser(String username) {
        System.out.println("check permission");
        long start = System.currentTimeMillis();
        target.createUser(username);
        System.out.println("cost: " + (System.currentTimeMillis() - start));
    }
}

使用:

java
UserService userService = new UserServiceProxy(new UserServiceImpl());
userService.createUser("justin");

静态代理清楚直观,但每个接口都要写代理类。

JDK 动态代理

JDK 动态代理要求目标对象实现接口。

java
import java.lang.reflect.Proxy;

UserService target = new UserServiceImpl();

UserService proxy = (UserService) Proxy.newProxyInstance(
        target.getClass().getClassLoader(),
        new Class[]{UserService.class},
        (object, method, args) -> {
            System.out.println("before method");
            Object result = method.invoke(target, args);
            System.out.println("after method");
            return result;
        }
);

proxy.createUser("justin");

Spring AOP 在很多情况下就会使用代理思想。

常见代理类型

类型说明
静态代理手写代理类
JDK 动态代理基于接口生成代理
CGLIB 代理基于继承生成子类代理
远程代理屏蔽远程调用细节
虚拟代理延迟创建重对象
保护代理做权限控制

使用场景

  • Spring AOP。
  • 事务、权限、日志、监控。
  • RPC 客户端代理。
  • MyBatis Mapper 接口代理。
  • 懒加载对象。

优点

  • 不修改目标类即可增强行为。
  • 增强逻辑可以复用。
  • 调用方可以面向接口编程。
  • 适合处理横切关注点。

缺点

  • 调用链变长,调试时需要理解代理层。
  • 动态代理有一定性能开销。
  • 代理配置不当可能导致方法没有被增强。
  • CGLIB 代理无法代理 final 类或 final 方法。

和装饰器模式的区别

模式重点
代理控制访问目标对象
装饰器动态增加目标对象能力

代理更强调“访问控制”,装饰器更强调“功能叠加”。

实战注意

在 Spring 中,同一个类内部方法互相调用时,可能绕过代理,导致事务或 AOP 不生效。这是使用代理时非常常见的问题。

以工程实践沉淀知识,以文档复盘成长。