Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/microwind/ai-skills --skill proxy-pattern명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SOC 직업 분류 기준
SKILL.md 표시 중
| 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());
// 执行真实方法
System.currentTimeMillis();
method.invoke(target, args);
System.currentTimeMillis() - startTime;
System.out.println( + methodName + + duration + );
result;
}
{
Set<String> allowedRoles = permissions.get(methodName);
(allowedRoles == || !allowedRoles.contains(currentUser.getRole())) {
( + currentUser.getName() +
+ methodName);
}
}
}
();
(, );
(Document) Proxy.newProxyInstance(
Document.class.getClassLoader(),
[]{Document.class},
(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())
));
}
}
{
String {
System.out.println( + path);
;
}
{
System.out.println( + path);
}
}
();
enhancer.setSuperclass(RealFileService.class);
enhancer.setCallback( ());
(RealFileService) enhancer.create();
proxy.readFile();
proxy.writeFile(, );
特点: 声明式代理,无需手工编写代理代码
优点: 与 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.*(..))")
Object Throwable {
System.currentTimeMillis();
joinPoint.proceed();
System.currentTimeMillis() - startTime;
logger.info(, joinPoint.getSignature().getName(), duration);
(duration > ) {
logger.warn(,
joinPoint.getSignature().getName(), duration);
}
result;
}
{
logger.error(,
joinPoint.getSignature().getName(), ex.getMessage());
}
}
UserService userService;
{
userService.getUser();
}
特点: 使用函数式编程,代理是函数的组合
优点: 高度灵活,易于组合和测试
缺点: 学习曲线陡
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( + input);
cache.get(input);
}
service.execute(input);
cache.put(input, result);
result;
});
;
}
FunctionalProxyBuilder {
();
Executors.newScheduledThreadPool();
scheduler.scheduleAtFixedRate(() -> counter.set(), , , TimeUnit.MINUTES);
middlewares.add(service -> input -> {
(counter.incrementAndGet() > maxCallsPerMinute) {
();
}
service.execute(input);
});
;
}
Service {
realService;
(Function<Service, Service> middleware : middlewares) {
proxy = middleware.apply(proxy);
}
proxy;
}
}
input -> + input;
()
.addPermissionCheck(currentUser)
.addLogging()
.addCaching()
.addRateLimiting()
.build(realService);
proxyService.execute();
| 维度 | 代理 | 装饰 | 外观 |
|---|---|---|---|
| 目的 | 控制访问 | 添加功能 | 简化接口 |
| 职责数 | 通常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;
}
}
();
(service, user);
(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:缓存反射结果
{
Map<Method, Object> resultCache = <>();
Object Throwable {
method.getName() + Arrays.toString(args);
resultCache.computeIfAbsent(key, k -> {
{
method.invoke(target, args);
} (Exception e) {
(e);
}
});
}
}
System.nanoTime();
( ; i < ; i++) {
proxy.execute();
}
(System.nanoTime() - start) / ;
症状: 多个代理叠加导致代码混乱、调试困难
// ❌ 反面:代理链过长,难以管理
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 {
target = (target, limit);
;
}
UserService {
target;
}
}
()
.withPermissionChecking(user)
.withCaching()
.withRateLimiting()
.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 (, Duration.ofSeconds());
}
Data ServiceUnavailableException {
(circuitBreaker.isOpen()) {
();
}
{
fetchWithRetry();
circuitBreaker.recordSuccess();
result;
} (IOException | InterruptedException | TimeoutException e) {
circuitBreaker.recordFailure();
( + e.getMessage(), e);
}
}
Data IOException, InterruptedException, TimeoutException {
;
;
(attempt < MAX_RETRIES) {
{
fetchSingleAttempt();
} (IOException | TimeoutException e) {
lastException = e;
attempt++;
(attempt < MAX_RETRIES) {
* () Math.pow(, attempt - );
System.out.println( + attempt + + backoff + );
Thread.sleep(backoff);
}
}
}
( + MAX_RETRIES + , lastException);
}
Data IOException, TimeoutException, InterruptedException {
HttpClient.newBuilder()
.connectTimeout(Duration.ofMillis(TIMEOUT_MS))
.build();
HttpRequest.newBuilder(URI.create(serverUrl + ))
.timeout(Duration.ofMillis(TIMEOUT_MS))
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
(response.statusCode() != ) {
( + response.statusCode());
}
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 | 工厂创建代理 | 需要统一创建各类代理 |
✅ 强烈推荐:
⚠️ 权衡使用:
❌ 不推荐: