My App

代理模式

Proxy — 为对象提供一个替身,控制对该对象的访问

一句话理解

不直接访问目标对象,而是通过一个代理人来间接访问,代理人可以在访问前后做额外的事。

解决什么问题

  • 想在访问对象前做权限检查、日志记录、缓存等操作
  • 目标对象创建成本高,想延迟加载(用到时才真正创建)
  • 想对远程对象的调用做本地封装(远程代理)

和装饰器的区别

代理模式装饰器模式
目的控制访问增强功能
关注是否能访问、何时访问给对象叠加新能力
典型权限控制、懒加载、缓存加牛奶、加糖

怎么写

静态代理

public interface UserService {
    void save(String name);
}

// 真实对象
public class UserServiceImpl implements UserService {
    public void save(String name) {
        System.out.println("保存用户: " + name);
    }
}

// 代理对象
public class UserServiceProxy implements UserService {
    private final UserService target;

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

    @Override
    public void save(String name) {
        System.out.println("[日志] 开始保存...");
        target.save(name);  // 委托给真实对象
        System.out.println("[日志] 保存完成");
    }
}
UserService service = new UserServiceProxy(new UserServiceImpl());
service.save("张三");
// [日志] 开始保存...
// 保存用户: 张三
// [日志] 保存完成

动态代理(Java JDK)

不用手写代理类,运行时动态生成:

UserService proxy = (UserService) Proxy.newProxyInstance(
    UserService.class.getClassLoader(),
    new Class[]{UserService.class},
    (proxyObj, method, args) -> {
        System.out.println("[日志] 调用: " + method.getName());
        Object result = method.invoke(new UserServiceImpl(), args);
        System.out.println("[日志] 完成: " + method.getName());
        return result;
    }
);

proxy.save("张三");

前端中的代理

// ES6 Proxy —— 语言原生支持
const user = { name: '张三', age: 25 }

const proxy = new Proxy(user, {
  get(target, prop) {
    console.log(`读取 ${prop}`)
    return target[prop]
  },
  set(target, prop, value) {
    console.log(`设置 ${prop} = ${value}`)
    target[prop] = value
    return true
  }
})

proxy.name      // 读取 name → "张三"
proxy.age = 26  // 设置 age = 26

Vue 3 的响应式系统就是基于 Proxy 实现的。

使用场景

  • Spring AOP —— 通过动态代理实现切面(日志、事务、权限)
  • MyBatis Mapper —— Mapper 接口没有实现类,运行时动态代理生成
  • Vue 3 响应式 —— Proxy 拦截数据读写,触发视图更新
  • 懒加载 —— 图片懒加载、大对象延迟初始化

On this page