文章目录
-
- 前言
- [1. 代理模式是什么?](#1. 代理模式是什么?)
- [2. 代理模式解决什么问题?](#2. 代理模式解决什么问题?)
- [3. 代理模式的实现思路](#3. 代理模式的实现思路)
- [4. 静态代理(Static Proxy)](#4. 静态代理(Static Proxy))
-
- [4.1 场景示例:给真实对象加"日志与权限"](#4.1 场景示例:给真实对象加“日志与权限”)
- [4.2 静态代理特点](#4.2 静态代理特点)
- [5. 动态代理(JDK 动态代理)](#5. 动态代理(JDK 动态代理))
-
- [5.1 定义接口与真实对象](#5.1 定义接口与真实对象)
- [5.2 动态代理的核心:InvocationHandler](#5.2 动态代理的核心:InvocationHandler)
- [5.3 动态代理特点](#5.3 动态代理特点)
- [6. 常见类型与适用场景](#6. 常见类型与适用场景)
- [7. 优缺点](#7. 优缺点)
-
- [7.1 代理模式优点](#7.1 代理模式优点)
- [7.2 代理模式缺点](#7.2 代理模式缺点)
- [7.3 和装饰器模式的简单区分](#7.3 和装饰器模式的简单区分)
- [8. 总结](#8. 总结)
前言
在面向对象设计里,"不直接动这个对象,但要在访问它之前/之后做一些事"是非常常见的需求。代理模式(Proxy Pattern) 就是用来解决这种问题的:
让一个对象充当"中介",把对另一个对象的访问过程包装起来。
可以把它理解成:想上门见客户,但先经过前台/经纪人/中介 ------真正的客户对象不需要直接暴露给你。

1. 代理模式是什么?
代理模式: 为其他对象提供一种代理,以便控制对这个对象的访问。
核心思想:
- 真实对象(Real Subject)负责"实际业务"
- 代理对象(Proxy)负责"控制访问 + 增强行为"
- 客户端(Client)面向代理编程,而不是面向真实对象直接调用
GoF 的经典结构里通常有:
- Subject:抽象主题(接口/抽象类)
- RealSubject:真实主题(核心实现)
- Proxy:代理主题(增强与控制)
2. 代理模式解决什么问题?
代理模式主要用来实现这些能力:
-
权限控制/访问校验
例如:管理员才能调用某些方法。
-
日志/埋点/审计
例如:统计方法耗时、记录调用参数与结果。
-
远程调用封装
例如:RPC 框架里的 Stub/Client Proxy,看起来像本地调用。
-
缓存/延迟加载
例如:首次访问才创建真实对象,后续直接命中缓存。
-
增强与解耦
例如:不改真实对象代码,也能叠加横切逻辑(横切关注点)。
3. 代理模式的实现思路
实现代理模式时,常见套路是:
- 先定义统一接口
Subject - 让
RealSubject实现真实业务 - 让
Proxy内部持有一个RealSubject引用 - 在
Proxy的方法里:- 访问前做增强(权限/日志/计时)
- 再调用真实对象
- 访问后做增强(记录结果/清理资源/统计)
4. 静态代理(Static Proxy)
4.1 场景示例:给真实对象加"日志与权限"
假设有一个接口:Service
java
public interface Service {
void doWork();
}
真实对象:RealService
java
public class RealService implements Service {
@Override
public void doWork() {
System.out.println("RealService: 执行业务逻辑");
}
}
代理对象:ServiceProxy
java
public class ServiceProxy implements Service {
private final Service real;
public ServiceProxy(Service real) {
this.real = real;
}
@Override
public void doWork() {
// 1) 访问前增强:权限校验
System.out.println("Proxy: 权限校验通过(示例)");
// 2) 访问前增强:日志/计时
long start = System.currentTimeMillis();
// 3) 调用真实对象
real.doWork();
// 4) 访问后增强:日志/统计
long cost = System.currentTimeMillis() - start;
System.out.println("Proxy: doWork 耗时 = " + cost + "ms");
}
}
客户端使用代理:
java
public class Client {
public static void main(String[] args) {
Service real = new RealService();
Service proxy = new ServiceProxy(real);
proxy.doWork();
}
}
4.2 静态代理特点
- 代理类由程序员手写(或生成)
- 编译期就确定代理逻辑
- 适合代理逻辑稳定、对象数量不太多的场景
5. 动态代理(JDK 动态代理)
当目标对象实现了接口,可以用 java.lang.reflect.Proxy 做动态代理。
5.1 定义接口与真实对象
接口同上:Service
真实对象:RealService
5.2 动态代理的核心:InvocationHandler
java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxyFactory {
@SuppressWarnings("unchecked")
public static <T> T createProxy(T target) {
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK Proxy: 权限校验(示例)");
long start = System.currentTimeMillis();
Object result = method.invoke(target, args);
long cost = System.currentTimeMillis() - start;
System.out.println("JDK Proxy: " + method.getName() + " 耗时=" + cost + "ms");
return result;
}
}
);
}
}
客户端:
java
public class Client {
public static void main(String[] args) {
Service real = new RealService();
Service proxy = JdkProxyFactory.createProxy(real);
proxy.doWork();
}
}
5.3 动态代理特点
- 代理逻辑在运行时决定(通过反射调用)
- 代理类不需要手写每一种类型
- 但性能上一般比静态代理略逊(反射开销)
6. 常见类型与适用场景
按"代理方式"可以分为:
-
静态代理
- 手写代理类
- 场景:权限、日志、缓存等增强固定且简单
-
JDK 动态代理
- 目标必须实现接口
- 场景:框架通用增强(例如 AOP、RPC 客户端代理)
-
CGLIB 动态代理
- 目标类无需实现接口
- 场景:类代理(Spring 某些配置下)
-
远程代理(Remote Proxy)
- 客户端调用像本地一样,但底层走网络
- 典型:RPC 的 client stub
-
虚拟代理(Virtual Proxy)
- 延迟初始化:首次访问才创建真实对象
- 场景:大对象、图片/资源加载、懒加载
-
保护代理(Protection Proxy)
- 用于访问控制(角色/令牌校验)
- 场景:后台管理接口、敏感操作保护
-
缓存代理(Caching Proxy)
- 先查缓存,命中则直接返回,不命中再调用真实对象
- 场景:热点查询、幂等读
7. 优缺点
7.1 代理模式优点
- 可控访问:能在调用前后加逻辑(权限、日志、审计)
- 增强解耦:真实对象专注核心业务,横切逻辑交给代理
- 可扩展:可以不断叠加新的代理增强
7.2 代理模式缺点
- 增加复杂度:多一层对象、多一段调用链
- 可能影响性能:动态代理依赖反射/拦截
- 不当使用会变"滥用中间层":过度代理导致调试困难
7.3 和装饰器模式的简单区分
- 装饰器:通常强调"功能叠加"(也会包一层对象,但更偏向对象行为扩展)
- 代理:更强调"控制访问/代表/访问管理"(例如权限、远程、延迟)
在很多框架实现里,两者可能"看起来很像",但意图和侧重点不同。
8. 总结
代理模式就是:
不直接调用真实对象,而是先走一层"代表对象",在这里完成访问控制与增强,然后再把请求转发给真实对象。