con un clic
proxy-pattern
为其他对象提供代理以控制其访问和行为。支持延迟加载、权限控制、远程访问和监控。
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Menú
为其他对象提供代理以控制其访问和行为。支持延迟加载、权限控制、远程访问和监控。
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Basado en la clasificación ocupacional SOC
以聚合根为边界,包含多个相关Entity和ValueObject的集合。保证数据一致性和事务边界。
在DDD中具有唯一身份标识和生命周期的对象,通过身份而非属性值相等判断。
封装复杂对象和聚合的创建过程,将创建职责从领域对象中剥离,保证聚合创建时的不变量满足。
没有身份标识,通过属性值判断相等的对象。不可变,通常代表领域中的度量或描述。
命令查询责任分离,将数据的写入操作和读取操作分别用不同的模型处理,优化各自的性能。
将DDD战略设计应用于微服务架构,限界上下文指导服务拆分,领域事件实现服务间通信。
| name | Proxy Pattern |
| description | 为其他对象提供代理以控制其访问和行为。支持延迟加载、权限控制、远程访问和监控。 |
| license | MIT |
Proxy 模式通过为真实对象创建代理,在客户端与真实对象之间建立一层控制层。代理与真实对象实现相同接口,但在转发请求前可以执行额外的逻辑。
关键思想:
客户端 → 代理对象 → (验证/检查/监控) → 真实对象
↓
缓存/日志/计数
四大应用场景:
特点: 为每个服务类编写一个代理类
优点: 代码清晰,易于理解
缺点: 代码量大,维护很乱(每个类都需要一个代理)
// 产品接口
public interface Document {
void read();
void write(String content);
}
// 真实对象
public class RealDocument implements Document {
private String filename;
public RealDocument(String filename) {
this.filename = filename;
System.out.println("[Real] Document created: " + filename);
}
@Override public void read() {
System.out.println("[Real] Reading: " + filename);
}
@Override public void write(String content) {
System.out.println("[Real] Writing to: " + filename + " -> " + content);
}
}
// 代理(静态 - 需要为每个接口编写一个)
public class DocumentProxy implements Document {
private RealDocument realDocument;
private String filename;
private User currentUser;
public DocumentProxy(String filename, User user) {
this.filename = filename;
this.currentUser = user;
}
@Override
public void read() {
// 代理逻辑:验证权限
if (!currentUser.hasPermission("READ")) {
throw new AccessDeniedException("No read permission");
}
// 代理逻辑:延迟加载
if (realDocument == null) {
this.realDocument = new RealDocument(filename);
}
realDocument.read();
}
@Override
public void write(String content) {
if (!currentUser.hasPermission("WRITE")) {
throw new AccessDeniedException("No write permission");
}
if (realDocument == null) {
this.realDocument = new RealDocument(filename);
}
realDocument.write(content);
}
}
特点: 运行时生成代理类,一个通用代理处理所有接口
优点: 无需为每个类写代理
缺点: 反射性能开销,调试困难
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
// 通用代理处理器(处理所有被代理对象)
public class PermissionCheckingHandler implements InvocationHandler {
private Object target;
private User currentUser;
private Map<String, Set<String>> permissions = new HashMap<>();
public PermissionCheckingHandler(Object target, User user) {
this.target = target;
this.currentUser = user;
initPermissions();
}
private void initPermissions() {
permissions.put("read", Set.of("admin", "user", "guest"));
permissions.put("write", Set.of("admin", "user"));
permissions.put("delete", Set.of("admin"));
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
// 权限检查逻辑
checkPermission(methodName);
// 记录调用日志
System.out.println("[Proxy] Calling: " + methodName + " for user: " + currentUser.getName());
// 执行真实方法
long startTime = System.currentTimeMillis();
Object result = method.invoke(target, args);
long duration = System.currentTimeMillis() - startTime;
// 性能监控
System.out.println("[Proxy] Method " + methodName + " took " + duration + "ms");
return result;
}
private void checkPermission(String methodName) {
Set<String> allowedRoles = permissions.get(methodName);
if (allowedRoles == null || !allowedRoles.contains(currentUser.getRole())) {
throw new AccessDeniedException("User " + currentUser.getName() +
" has no permission to call " + methodName);
}
}
}
// 使用 JDK 动态代理
Document realDoc = new RealDocument("report.docx");
User user = new User("Alice", "admin");
Document proxyDoc = (Document) Proxy.newProxyInstance(
Document.class.getClassLoader(),
new Class[]{Document.class},
new PermissionCheckingHandler(realDoc, user)
);
proxyDoc.read(); // 自动检查权限、记录日志、计时
特点: 通过继承生成代理,支持没有接口的类
优点: 性能好(不用反射),无需实现接口
缺点: 无法代理 final 类,GC 开销
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class PerformanceMonitorInterceptor implements MethodInterceptor {
private Map<String, Long> callDurations = new ConcurrentHashMap<>();
private Map<String, Integer> callCounts = new ConcurrentHashMap<>();
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
throws Throwable {
String key = method.getName();
long startTime = System.nanoTime();
Object result = proxy.invokeSuper(obj, args);
long duration = System.nanoTime() - startTime;
callCounts.merge(key, 1, Integer::sum);
callDurations.merge(key, duration, Long::sum);
System.out.printf("[CGLib Proxy] %s called (total: %d times, avg: %.2fms)%n",
key, callCounts.get(key), callDurations.get(key) / 1_000_000.0 / callCounts.get(key));
return result;
}
public Map<String, Double> getAverageCallTimes() {
return callDurations.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
e -> e.getValue() / 1_000_000.0 / callCounts.get(e.getKey())
));
}
}
// 使用 CGLib
public class RealFileService { // 注意:没有接口
public String readFile(String path) {
System.out.println("[Real] Reading file: " + path);
return "file content";
}
public void writeFile(String path, String content) {
System.out.println("[Real] Writing to " + path);
}
}
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealFileService.class);
enhancer.setCallback(new PerformanceMonitorInterceptor());
RealFileService proxy = (RealFileService) enhancer.create();
proxy.readFile("/tmp/test.txt");
proxy.writeFile("/tmp/test.txt", "new content");
特点: 声明式代理,无需手工编写代理代码
优点: 与 Spring 集成,支持注解,代码简洁
缺点: 依赖 Spring 框架
// 目标服务
@Service
public class UserService {
public User getUser(String id) {
System.out.println("[Service] Getting user: " + id);
Thread.sleep(100); // 模拟耗时操作
return new User(id, "John");
}
public void deleteUser(String id) {
System.out.println("[Service] Deleting user: " + id);
}
}
// 自定义切面
@Aspect
@Component
public class PermissionAndPerformanceAspect {
private static final Logger logger = LoggerFactory.getLogger(PermissionAndPerformanceAspect.class);
@Before("execution(* com.example.UserService.*(..))")
public void checkPermission(JoinPoint joinPoint) {
User currentUser = SecurityContextHolder.getContext().getAuthentication();
if (!currentUser.hasPermission(joinPoint.getSignature().getName())) {
throw new AccessDeniedException("Permission denied");
}
}
@Around("execution(* com.example.UserService.*(..))")
public Object measurePerformance(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = joinPoint.proceed(); // 执行实际方法
long duration = System.currentTimeMillis() - startTime;
logger.info("Method {} took {}ms", joinPoint.getSignature().getName(), duration);
if (duration > 500) {
logger.warn("Slow method detected: {} took {}ms",
joinPoint.getSignature().getName(), duration);
}
return result;
}
@AfterThrowing(pointcut = "execution(* com.example.UserService.*(..))", throwing = "ex")
public void logException(JoinPoint joinPoint, Exception ex) {
logger.error("Method {} threw exception: {}",
joinPoint.getSignature().getName(), ex.getMessage());
}
}
// 使用(自动被 Spring 代理)
@Autowired
private UserService userService;
public void example() {
User user = userService.getUser("123"); // 自动执行 AOP 切面
}
特点: 使用函数式编程,代理是函数的组合
优点: 高度灵活,易于组合和测试
缺点: 学习曲线陡
import java.util.function.Function;
// 定义服务接口为纯函数
public interface Service {
String execute(String input);
}
// 创建代理是中间件的组合
public class FunctionalProxyBuilder {
private List<Function<Service, Service>> middlewares = new ArrayList<>();
public FunctionalProxyBuilder addPermissionCheck(User user) {
middlewares.add(service -> input -> {
if (!user.hasPermission("execute")) {
throw new AccessDeniedException();
}
return service.execute(input);
});
return this;
}
public FunctionalProxyBuilder addLogging() {
middlewares.add(service -> input -> {
System.out.println("[Proxy] Executing with input: " + input);
String result = service.execute(input);
System.out.println("[Proxy] Result: " + result);
return result;
});
return this;
}
public FunctionalProxyBuilder addCaching() {
Map<String, String> cache = new ConcurrentHashMap<>();
middlewares.add(service -> input -> {
if (cache.containsKey(input)) {
System.out.println("[Proxy] Cache hit for: " + input);
return cache.get(input);
}
String result = service.execute(input);
cache.put(input, result);
return result;
});
return this;
}
public FunctionalProxyBuilder addRateLimiting(int maxCallsPerMinute) {
AtomicInteger counter = new AtomicInteger(0);
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(() -> counter.set(0), 1, 1, TimeUnit.MINUTES);
middlewares.add(service -> input -> {
if (counter.incrementAndGet() > maxCallsPerMinute) {
throw new RateLimitExceededException();
}
return service.execute(input);
});
return this;
}
public Service build(Service realService) {
Service proxy = realService;
for (Function<Service, Service> middleware : middlewares) {
proxy = middleware.apply(proxy);
}
return proxy;
}
}
// 使用示例
Service realService = input -> "Processed: " + input;
Service proxyService = new FunctionalProxyBuilder()
.addPermissionCheck(currentUser)
.addLogging()
.addCaching()
.addRateLimiting(100)
.build(realService);
String result = proxyService.execute("query"); // 会依次执行所有中间件
| 维度 | 代理 | 装饰 | 外观 |
|---|---|---|---|
| 目的 | 控制访问 | 添加功能 | 简化接口 |
| 职责数 | 通常1-2个 | 可多个 | 多个 |
| 创建时机 | 代替原对象 | 自由叠加 | 统一管理 |
| 大小关系 | 相同接口 | 可扩展接口 | 可更简单 |
| 何时使用 | 权限/性能 | 功能加强 | 接口封装 |
| 示例 | 文件访问代理 | Logger 装饰器 | Facade 简化 |
症状: 容易混淆代理和装饰器,不知道何时用哪个
// ❌ 错误混淆
class LoggingProxy implements DataService { // 这其实是装饰器
private DataService target;
@Override
public Data fetch() {
log("Fetching data");
return target.fetch(); // 同时做了权限+日志,职责混乱
}
}
// ✅ 清晰的代理 - 专注于控制访问
class PermissionCheckingProxy implements DataService {
private DataService target;
private User user;
@Override
public Data fetch() {
if (!user.hasPermission("READ")) {
throw new AccessDeniedException();
}
return target.fetch(); // 只负责权限检查
}
}
// ✅ 清晰的装饰器 - 专注于功能增强
class LoggingDecorator implements DataService {
private DataService wrapped;
@Override
public Data fetch() {
System.out.println("Before fetch");
Data result = wrapped.fetch();
System.out.println("After fetch");
return result; // 只负责添加日志
}
}
// 使用组合:代理控制访问,装饰器添加日志
DataService service = new DataService();
DataService withPermission = new PermissionCheckingProxy(service, user);
DataService withLog = new LoggingDecorator(withPermission);
症状: 使用 JDK 动态代理导致性能下降 50%+
// ❌ 反面:反射导致性能问题
public class SlowReflectionProxy implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(target, args); // 每次调用都通过反射
}
}
// ✅ 解决方案1:使用字节码生成 (CGLib)
public class FastCGLibProxy {
public static <T> T createProxy(T target, MethodInterceptor interceptor) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(interceptor);
return (T) enhancer.create();
}
}
// ✅ 解决方案2:静态代理(最快,但需手写)
public class FastStaticProxy implements UserService {
private UserService target;
@Override
public void deleteUser(String id) {
// 直接调用,无反射
checkPermission();
target.deleteUser(id);
}
private void checkPermission() { /* ... */ }
}
// ✅ 解决方案3:缓存反射结果
public class CachedReflectionProxy implements InvocationHandler {
private Map<Method, Object> resultCache = new ConcurrentHashMap<>();
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String key = method.getName() + Arrays.toString(args);
return resultCache.computeIfAbsent(key, k -> {
try {
return method.invoke(target, args);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
}
// 性能测试对比
long start = System.nanoTime();
for (int i = 0; i < 1_000_000; i++) {
proxy.execute();
}
long duration = (System.nanoTime() - start) / 1_000_000;
// JDK 动态代理: ~500ms
// CGLib: ~200ms
// 静态代理: ~50ms
症状: 多个代理叠加导致代码混乱、调试困难
// ❌ 反面:代理链过长,难以管理
UserService service = new RealUserService();
service = new PermissionCheckingProxy(service, user);
service = new LoggingProxy(service);
service = new CachingProxy(service);
service = new RateLimitingProxy(service, 100);
service = new TimeoutProxy(service, 5000);
// 调试时不知道哪一层出错了
// ✅ 解决方案:使用代理构建器
public class ProxyChainBuilder {
private UserService target;
public ProxyChainBuilder withPermissionChecking(User user) {
target = new PermissionCheckingProxy(target, user);
return this;
}
public ProxyChainBuilder withLogging() {
target = new LoggingProxy(target);
return this;
}
public ProxyChainBuilder withCaching() {
target = new CachingProxy(target);
return this;
}
public ProxyChainBuilder withRateLimiting(int limit) {
target = new RateLimitingProxy(target, limit);
return this;
}
public UserService build() {
return target;
}
}
// 使用更清晰
UserService service = new ProxyChainBuilder()
.withPermissionChecking(user)
.withCaching()
.withRateLimiting(100)
.build();
症状: 网络延迟、超时、连接错误时没有处理
// ❌ 反面:没有考虑网络问题
public class RemoteServiceProxy implements RemoteService {
private String serverUrl;
@Override
public Data fetch() {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create(serverUrl + "/fetch"))
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
return parseResponse(response.body()); // 如果网络故障直接崩溃
}
}
// ✅ 解决方案:添加重试、超时、熔断
public class RobustRemoteServiceProxy implements RemoteService {
private String serverUrl;
private final int MAX_RETRIES = 3;
private final int TIMEOUT_MS = 5000;
private final CircuitBreaker circuitBreaker;
public RobustRemoteServiceProxy(String serverUrl) {
this.serverUrl = serverUrl;
this.circuitBreaker = new CircuitBreaker(3, Duration.ofSeconds(30));
}
@Override
public Data fetch() throws ServiceUnavailableException {
// 熔断检查
if (circuitBreaker.isOpen()) {
throw new ServiceUnavailableException("Service temporarily unavailable");
}
try {
Data result = fetchWithRetry();
circuitBreaker.recordSuccess();
return result;
} catch (IOException | InterruptedException | TimeoutException e) {
circuitBreaker.recordFailure();
throw new ServiceUnavailableException("Remote service failed: " + e.getMessage(), e);
}
}
private Data fetchWithRetry() throws IOException, InterruptedException, TimeoutException {
int attempt = 0;
Exception lastException = null;
while (attempt < MAX_RETRIES) {
try {
return fetchSingleAttempt();
} catch (IOException | TimeoutException e) {
lastException = e;
attempt++;
if (attempt < MAX_RETRIES) {
long backoff = 100 * (long) Math.pow(2, attempt - 1); // 指数退避
System.out.println("[Proxy] Retry attempt " + attempt + " after " + backoff + "ms");
Thread.sleep(backoff);
}
}
}
throw new TimeoutException("Failed after " + MAX_RETRIES + " retries", lastException);
}
private Data fetchSingleAttempt() throws IOException, TimeoutException, InterruptedException {
HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofMillis(TIMEOUT_MS))
.build();
HttpRequest request = HttpRequest.newBuilder(URI.create(serverUrl + "/fetch"))
.timeout(Duration.ofMillis(TIMEOUT_MS))
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
throw new IOException("Server returned status: " + response.statusCode());
}
return parseResponse(response.body());
}
}
// ❌ 混乱
class MixedProxy implements Service {
public void execute() {
checkPermission(); // 权限
logCall(); // 日志
cache(); // 缓存
monitor(); // 监控
target.execute();
}
}
// ✅ 清晰 - 每个代理一个职责
class PermissionProxy implements Service {
public void execute() {
checkPermission();
target.execute();
}
}
// ❌ 错误 - 代理不应该改变返回值
class TransformingProxy implements Service {
public String execute() {
String result = target.execute();
return result.toUpperCase(); // 不应该修改
}
}
// ✅ 正确 - 只处理服务方面
class LoggingProxy implements Service {
public String execute() {
System.out.println("Before");
String result = target.execute();
System.out.println("After");
return result; // 返回原始结果
}
}
// ✅ 代理应该处理自己的异常
public class RobustProxy implements Service {
@Override
public void execute() {
try {
checkPermission();
} catch (PermissionException e) {
logger.error("Permission denied", e);
throw e; // 或根据策略降级
}
try {
target.execute();
} catch (ServiceException e) {
logger.error("Service failed", e);
throw e;
}
}
}
/**
* 权限检查代理 - 代理 UserService
*
* 代理的行为:
* - 每次调用前检查用户权限
* - 如果权限不足抛出 AccessDeniedException
* - 如果真实对象抛异常,直接转发
*
* 性能影响:
* - 每次调用增加 <1ms 的权限检查时间
*
* @param user 当前用户
*/
public class PermissionCheckingProxy implements UserService {
private UserService target;
private User user;
// ...
}
| 模式 | 关系 | 何时结合 |
|---|---|---|
| Decorator | 都是包装对象,但目的不同 | 需要同时控制访问并添加功能 |
| Facade | 都简化接口,但 Facade 处理系统 | 对多个对象的统一简化 |
| Adapter | 都是中介,但 Adapter 改变接口 | 需要改变接口并控制访问 |
| Strategy | 都在运行时切换实现 | 代理负责访问,Strategy 负责算法 |
| Factory | 工厂创建代理 | 需要统一创建各类代理 |
✅ 强烈推荐:
⚠️ 权衡使用:
❌ 不推荐: