ソース情報
- リポジトリ
- 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で見る