Skip to main content

proxy-pattern

为其他对象提供代理以控制其访问和行为。支持延迟加载、权限控制、远程访问和监控。

ソース情報

リポジトリ
microwind/ai-skills
ソースの最終更新活動
2026年3月29日 22:57
検出された SKILL.md の言語
中国語
スター
83
フォーク
24

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

ファイルエクスプローラー
4 ファイル

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
Proxy Pattern
description
为其他对象提供代理以控制其访问和行为。支持延迟加载、权限控制、远程访问和监控。
license
MIT
# Proxy 模式 (代理模式) ## 核心原理 **Proxy 模式**通过为真实对象创建代理,在客户端与真实对象之间建立一层控制层。代理与真实对象实现相同接口,但在转发请求前可以执行额外的逻辑。 **关键思想**: ``` 客户端 → 代理对象 → (验证/检查/监控) → 真实对象 ↓ 缓存/日志/计数 ``` **四大应用场景**: 1. 🐢 **虚代理** (Lazy Proxy) - 延迟加载 2. 🔐 **保护代理** (Protection Proxy) - 访问控制 3. 🌐 **远程代理** (Remote Proxy) - 分布式访问 4. 📊 **日志代理** (Logging Proxy) - 监控审计 --- ## 5个实现方法对比 ### 方法1: 基础代理(静态代理) **特点**: 为每个服务类编写一个代理类 **优点**: 代码清晰,易于理解 **缺点**: 代码量大,维护很乱(每个类都需要一个代理) ```java // 产品接口 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); } } ``` ### 方法2: Java 动态代理 (Reflection-based) **特点**: 运行时生成代理类,一个通用代理处理所有接口 **优点**: 无需为每个类写代理 **缺点**: 反射性能开销,调试困难 ```java 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(); // 自动检查权限、记录日志、计时 ``` ### 方法3: CGLib 代理(字节码生成)- 无需接口 **特点**: 通过继承生成代理,支持没有接口的类 **优点**: 性能好(不用反射),无需实现接口 **缺点**: 无法代理 final 类,GC 开销 ```java 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"); ``` ### 方法4: Spring AOP 代理(最实用) **特点**: 声明式代理,无需手工编写代理代码 **优点**: 与 Spring 集成,支持注解,代码简洁 **缺点**: 依赖 Spring 框架 ```java // 目标服务 @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 切面 } ``` ### 方法5: 纯函数式代理(FP 风格) **特点**: 使用函数式编程,代理是函数的组合 **优点**: 高度灵活,易于组合和测试 **缺点**: 学习曲线陡 ```java 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"); // 会依次执行所有中间件 ``` --- ## 代理 vs 装饰 vs 外观 - 全面对比 | 维度 | 代理 | 装饰 | 外观 | |------|------|------|------| | **目的** | 控制访问 | 添加功能 | 简化接口 | | **职责数** | 通常1-2个 | 可多个 | 多个 | | **创建时机** | 代替原对象 | 自由叠加 | 统一管理 | | **大小关系** | 相同接口 | 可扩展接口 | 可更简单 | | **何时使用** | 权限/性能 | 功能加强 | 接口封装 | | **示例** | 文件访问代理 | Logger 装饰器 | Facade 简化 | --- ## 4个常见问题 + 完整解决方案 ### 问题1: 代理与装饰器的实际区别 **症状**: 容易混淆代理和装饰器,不知道何时用哪个 ```java // ❌ 错误混淆 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");
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る