以下是为你精心撰写的 《Java 代理模式深度学习指南》,专为 Java 后端开发者打造,内容涵盖:定义、作用、与装饰器模式的深度对比、真实业务场景、JDK 动态代理、CGLIB 代理、Spring AOP 对应、避坑指南、最佳实践、面试高频题,所有示例均含中文注释,可直接用于项目实战:权限控制、日志记录、事务管理、远程调用、缓存、限流、监控等核心场景。
📘 Java 代理模式深度学习指南
—— 从“直接调用”到“拦截增强”的架构升华
作者:Java 后端架构实战导师
适用对象:Java 后端开发者(Spring Boot / 微服务 / AOP / RPC / 安全 / 性能监控)
目标:彻底掌握“在不修改原对象的前提下,通过代理对象控制访问”的核心模式,理解 Spring AOP 的底层原理
核心原则:“我不是你,但我能代表你;我不是在改你,我是在你前后加了哨兵”
✅ 一、什么是代理模式?
📌 定义:
代理模式(Proxy Pattern) 是一种结构型设计模式,它为其他对象提供一个代理或占位符,以控制对这个对象的访问。代理对象在客户端与真实对象之间起到中介作用。
🔍 核心思想:
- 客户端不直接调用真实对象(Subject)
- 客户端调用的是代理对象(Proxy)
- 代理对象持有真实对象的引用
- 代理对象在调用真实对象前后,可以添加额外逻辑(如权限校验、日志、缓存)
- 代理对象和真实对象实现相同接口(或继承相同父类)
💡 一句话记忆:
“我要找老板谈事,老板太忙,先找秘书——秘书先拦我、记我、查我权限,再决定要不要放我进去见老板。”
🆚 代理模式 vs 装饰器模式(极易混淆)
| 维度 | 代理模式 | 装饰器模式 |
|---|---|---|
| 目的 | 控制访问(是否能调、何时调、如何调) | 增强功能(加日志、缓存、加密) |
| 关注点 | 访问控制、延迟加载、安全拦截 | 功能叠加、职责扩展 |
| 是否必须接口一致 | ✅ 必须(同接口) | ✅ 必须(同接口) |
| 是否改变行为 | 可以阻止调用(如权限不足) | 总是调用原行为 + 增强 |
| 典型场景 | 权限校验、远程调用、懒加载 | 日志、缓存、加密、限流 |
| 是否透明 | 客户端感知不到代理存在 | 客户端也感知不到装饰器 |
| 类比 | 秘书(决定是否放行) | 给咖啡加奶(增强口味) |
✅ 关键区别:
- 代理:“你能不能见老板?”(控制权)
- 装饰器:“你见老板前先喝杯咖啡?”(增强性)
✅ 经典比喻:
- 你去银行取钱:
- 装饰器:取钱时,自动打印小票(增强)
- 代理:取钱前,必须刷身份证、人脸识别(控制)
✅ 二、代理模式有什么作用?(Why Use Proxy Pattern?)
| 作用 | 说明 |
|---|---|
| ✅ 控制访问权限 | 在调用前校验用户身份、角色、权限 |
| ✅ 延迟加载(Lazy Loading) | 对象创建成本高时,先返回代理,真正用时才初始化 |
| ✅ 远程代理(Remote Proxy) | 本地对象代表远程服务(如 RPC、Feign) |
| ✅ 虚拟代理(Virtual Proxy) | 占位符,按需加载大对象(如图片、文件) |
| ✅ 保护代理(Protection Proxy) | 控制对敏感对象的访问(如数据库、配置) |
| ✅ 智能引用(Smart Reference) | 在调用前后自动记录日志、统计次数、缓存 |
| ✅ 事务管理 | 在方法前后自动开启/提交/回滚事务 |
| ✅ 性能监控 | 自动记录方法执行时间、调用次数 |
| ✅ AOP 实现基础 | Spring AOP 底层就是代理模式的实现 |
💡 经典名言:
“A proxy is an object that acts as a stand-in for another object.”
——《Design Patterns: Elements of Reusable Object-Oriented Software》
✅ 三、代理模式的典型使用场景(Java 后端真实案例)
| 场景 | 说明 | 是否推荐使用代理模式 |
|---|---|---|
| ✅ 权限控制 | 用户访问接口前校验角色(如:只有管理员能删除) | ✅ 强烈推荐 |
| ✅ 事务管理 | @Transactional 自动开启/提交/回滚事务 | ✅ 强烈推荐 |
| ✅ 日志记录 | 方法调用前后自动打印参数、耗时、结果 | ✅ 推荐 |
| ✅ 远程调用 | Feign、Dubbo、gRPC 的客户端代理 | ✅ 推荐 |
| ✅ 缓存代理 | 方法调用前查缓存,命中则返回,未命中才调用真实方法 | ✅ 推荐 |
| ✅ 限流/熔断 | 调用前判断是否超限,超限直接拒绝 | ✅ 推荐 |
| ✅ 懒加载 | 加载大型对象(如图片、文件、复杂查询)时,先返回代理 | ✅ 推荐 |
| ✅ 监控/埋点 | 统计接口调用量、成功率、响应时间 | ✅ 推荐 |
| ✅ AOP 实现 | Spring AOP 底层使用代理实现切面 | ✅ 核心基础 |
| ❌ 简单工具封装 | StringUtils.isEmpty() | ❌ 用静态方法 |
| ❌ 对象创建 | new Order() | ❌ 用工厂模式 |
| ❌ 接口转换 | 微信 SDK → 标准接口 | ❌ 用适配器模式 |
| ❌ 功能叠加 | 日志 + 缓存 + 加密 | ❌ 用装饰器模式 |
✅ 判断标准:
“我需要在调用真实对象之前/之后,插入控制逻辑(如权限、事务、缓存),甚至阻止调用?”
→ 是 → 用代理模式!
✅ 四、代理模式的三种实现方式详解(含中文注释)
我们从静态代理到JDK 动态代理,再到CGLIB 代理,最后到Spring AOP。
🔹 1. 静态代理(Manual Proxy)—— 手写代理类
适用于固定接口、少量对象,代码量大,不推荐用于生产。
/**
* 【1】真实对象接口
*/
interface UserService {
void createUser(String name);
void deleteUser(Long id);
String getUserInfo(Long id);
}
/**
* 【2】真实对象实现
*/
class UserServiceImpl implements UserService {
@Override
public void createUser(String name) {
System.out.println("👤 创建用户:" + name);
}
@Override
public void deleteUser(Long id) {
System.out.println("🗑️ 删除用户:id=" + id);
}
@Override
public String getUserInfo(Long id) {
return "用户信息:id=" + id + ", name=张三";
}
}
/**
* 【3】静态代理类:实现相同接口,持有真实对象
*/
class UserServiceProxy implements UserService {
private UserService realService; // 持有真实对象
public UserServiceProxy(UserService realService) {
this.realService = realService;
}
@Override
public void createUser(String name) {
// ✅ 代理增强:权限校验
if (!hasPermission("CREATE_USER")) {
System.out.println("🚫 权限不足,禁止创建用户");
return;
}
System.out.println("📝 记录日志:即将创建用户:" + name);
realService.createUser(name); // 调用真实对象
System.out.println("✅ 记录日志:用户创建完成");
}
@Override
public void deleteUser(Long id) {
// ✅ 代理增强:权限校验
if (!hasPermission("DELETE_USER")) {
System.out.println("🚫 权限不足,禁止删除用户");
return;
}
System.out.println("📝 记录日志:即将删除用户:id=" + id);
realService.deleteUser(id);
System.out.println("✅ 记录日志:用户删除成功");
}
@Override
public String getUserInfo(Long id) {
// ✅ 代理增强:缓存模拟
String cacheKey = "user:" + id;
String cached = getFromCache(cacheKey);
if (cached != null) {
System.out.println("⚡ 缓存命中:" + cacheKey);
return cached;
}
System.out.println("🔍 查询数据库:id=" + id);
String result = realService.getUserInfo(id);
putToCache(cacheKey, result);
return result;
}
// 模拟权限检查
private boolean hasPermission(String action) {
return "admin".equals(System.getProperty("user.role", "guest"));
}
// 模拟缓存
private Map<String, String> cache = new HashMap<>();
private String getFromCache(String key) {
return cache.get(key);
}
private void putToCache(String key, String value) {
cache.put(key, value);
}
}
/**
* 【4】客户端:调用代理而非真实对象
*/
public class StaticProxyDemo {
public static void main(String[] args) {
// 创建真实对象
UserService realService = new UserServiceImpl();
// 创建代理对象,包装真实对象
UserService proxy = new UserServiceProxy(realService);
// 设置用户角色为 admin(模拟权限)
System.setProperty("user.role", "admin");
// ✅ 客户端完全不知道用了代理
proxy.createUser("李四"); // ✅ 权限通过,创建成功
proxy.deleteUser(1L); // ✅ 权限通过,删除成功
System.out.println(proxy.getUserInfo(1L)); // ✅ 缓存命中,不查库
// 模拟普通用户
System.setProperty("user.role", "guest");
proxy.createUser("王五"); // ❌ 权限不足,被拦截
}
}
✅ 优点:
- 逻辑清晰,容易理解
- 可完全控制代理行为
❌ 缺点:
- 每个类都要写一个代理类 → 代码冗余
- 不支持动态扩展(新增方法必须改代理类)
- 不适合生产环境
🔹 2. JDK 动态代理(JDK Dynamic Proxy)—— 基于接口的代理(推荐)
利用 Java 反射机制,在运行时动态生成代理类,要求目标对象必须实现接口。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 【1】接口(同上)
*/
interface UserService {
void createUser(String name);
void deleteUser(Long id);
String getUserInfo(Long id);
}
/**
* 【2】真实对象(同上)
*/
class UserServiceImpl implements UserService {
@Override
public void createUser(String name) {
System.out.println("👤 创建用户:" + name);
}
@Override
public void deleteUser(Long id) {
System.out.println("🗑️ 删除用户:id=" + id);
}
@Override
public String getUserInfo(Long id) {
return "用户信息:id=" + id + ", name=张三";
}
}
/**
* 【3】动态代理处理器:实现 InvocationHandler
* 它是代理的核心:所有方法调用都会被转发到这里
*/
class UserServiceInvocationHandler implements InvocationHandler {
private Object target; // 真实对象
public UserServiceInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// ✅ 在调用真实方法前:权限校验
String methodName = method.getName();
if (!hasPermission(methodName)) {
System.out.println("🚫 权限不足,禁止调用方法:" + methodName);
return null;
}
// ✅ 在调用前:日志记录
System.out.println("📝 [代理] 方法开始:" + methodName + ",参数:" + java.util.Arrays.toString(args));
// ✅ 调用真实对象的方法
Object result = method.invoke(target, args);
// ✅ 在调用后:日志记录
System.out.println("✅ [代理] 方法结束:" + methodName + ",返回:" + result);
return result;
}
// 模拟权限检查
private boolean hasPermission(String methodName) {
String role = System.getProperty("user.role", "guest");
return switch (methodName) {
case "createUser" -> "admin".equals(role);
case "deleteUser" -> "admin".equals(role);
case "getUserInfo" -> true; // 所有人可查
default -> false;
};
}
}
/**
* 【4】客户端:动态生成代理对象
*/
public class JdkDynamicProxyDemo {
public static void main(String[] args) {
// 创建真实对象
UserService realService = new UserServiceImpl();
// ✅ 动态生成代理对象
// Proxy.newProxyInstance():
// 第一个参数:类加载器
// 第二个参数:要代理的接口数组
// 第三个参数:InvocationHandler 实例
UserService proxy = (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class<?>[]{UserService.class},
new UserServiceInvocationHandler(realService)
);
// 设置用户角色
System.setProperty("user.role", "admin");
// ✅ 客户端像调用真实对象一样调用代理
proxy.createUser("李四"); // ✅ 权限通过,执行
proxy.deleteUser(1L); // ✅ 权限通过,执行
System.out.println(proxy.getUserInfo(1L)); // ✅ 缓存逻辑?不,这里只是日志
// 模拟普通用户
System.setProperty("user.role", "guest");
proxy.createUser("王五"); // ❌ 权限不足,被拦截
System.out.println(proxy.getUserInfo(1L)); // ✅ 仍可查,因为方法允许
}
}
✅ 优点:
- 无需手写代理类,运行时动态生成
- 支持任意接口,只要实现接口即可
- 符合开闭原则,新增方法无需改代理逻辑
- Spring AOP 默认使用 JDK 动态代理
⚠️ 缺点:
- 必须有接口!不能代理没有接口的类
- 性能略低于 CGLIB(反射调用)
🔹 3. CGLIB 代理(Code Generation Library)—— 基于继承的代理(推荐)
适用于没有接口的类,通过继承目标类 + 重写方法实现代理。
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 【1】真实类(无接口)
*/
class OrderService {
public void createOrder(String productId) {
System.out.println("🛒 创建订单:商品ID=" + productId);
}
public void updateOrder(Long orderId) {
System.out.println("✏️ 更新订单:id=" + orderId);
}
public String getOrderStatus(Long orderId) {
return "已支付";
}
}
/**
* 【2】CGLIB 代理拦截器:实现 MethodInterceptor
* 它会拦截所有被代理类的方法调用
*/
class OrderServiceInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// ✅ 方法调用前:日志 + 权限
String methodName = method.getName();
if (!hasPermission(methodName)) {
System.out.println("🚫 权限不足,禁止调用:" + methodName);
return null;
}
System.out.println("📝 [CGLIB代理] 方法开始:" + methodName + ",参数:" + java.util.Arrays.toString(args));
// ✅ 调用原方法(使用 MethodProxy 更高效)
Object result = proxy.invokeSuper(obj, args);
// ✅ 方法调用后:日志
System.out.println("✅ [CGLIB代理] 方法结束:" + methodName + ",返回:" + result);
return result;
}
private boolean hasPermission(String methodName) {
String role = System.getProperty("user.role", "guest");
return switch (methodName) {
case "createOrder", "updateOrder" -> "admin".equals(role);
case "getOrderStatus" -> true;
default -> false;
};
}
}
/**
* 【3】客户端:使用 CGLIB 创建代理
*/
public class CglibProxyDemo {
public static void main(String[] args) {
// 创建真实对象
OrderService realService = new OrderService();
// ✅ 创建 CGLIB 代理
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OrderService.class); // 设置父类
enhancer.setCallback(new OrderServiceInterceptor()); // 设置拦截器
OrderService proxy = (OrderService) enhancer.create(); // 生成代理对象
// 设置权限
System.setProperty("user.role", "admin");
// ✅ 客户端像调用真实对象一样调用代理
proxy.createOrder("P001"); // ✅ 执行
proxy.updateOrder(1L); // ✅ 执行
System.out.println(proxy.getOrderStatus(1L)); // ✅ 执行
// 普通用户
System.setProperty("user.role", "guest");
proxy.createOrder("P002"); // ❌ 被拦截
}
}
✅ 优点:
- 不需要接口,可代理任意类
- 性能优于 JDK 动态代理(CGLIB 使用字节码生成,直接调用,无反射)
- Spring AOP 在无接口时自动使用 CGLIB
⚠️ 缺点:
- 不能代理
final类或final方法 - 依赖第三方库(CGLIB)
- 生成子类,可能影响序列化、反射
💡 CGLIB 原理:
在运行时动态生成目标类的子类,并重写所有非 final 方法,在子类方法中插入拦截逻辑。
🔹 4. 代理模式 + Spring AOP(企业级终极实现)
Spring AOP 是代理模式的框架级封装,通过注解声明切面,底层自动使用 JDK 或 CGLIB 代理。
/**
* 【1】无接口的真实服务
*/
@Service
public class OrderService {
public void createOrder(String productId) {
System.out.println("🛒 创建订单:商品ID=" + productId);
}
public void updateOrder(Long orderId) {
System.out.println("✏️ 更新订单:id=" + orderId);
}
public String getOrderStatus(Long orderId) {
return "已支付";
}
}
/**
* 【2】切面:定义增强逻辑
*/
@Aspect
@Component
@Slf4j
public class OrderServiceAspect {
// 切入点:匹配 OrderService 所有方法
@Pointcut("execution(* com.example.service.OrderService.*(..))")
public void orderServiceMethods() {}
// 前置增强:权限校验 + 日志
@Before("orderServiceMethods()")
public void logBefore(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
log.info("📝 [AOP] 方法开始:{},参数:{}", methodName, args);
// 模拟权限校验
String role = System.getProperty("user.role", "guest");
if (("createOrder".equals(methodName) || "updateOrder".equals(methodName)) && !"admin".equals(role)) {
throw new SecurityException("🚫 权限不足,禁止操作:" + methodName);
}
}
// 后置增强:记录返回值
@AfterReturning(pointcut = "orderServiceMethods()", returning = "result")
public void logAfter(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
log.info("✅ [AOP] 方法结束:{},返回:{}", methodName, result);
}
// 异常增强
@AfterThrowing(pointcut = "orderServiceMethods()", throwing = "ex")
public void logError(JoinPoint joinPoint, Throwable ex) {
String methodName = joinPoint.getSignature().getName();
log.error("❌ [AOP] 方法 {} 执行失败:{}", methodName, ex.getMessage());
}
}
/**
* 【3】配置:启用 AOP
*/
@SpringBootApplication
@EnableAspectJAutoProxy // ✅ 开启 AOP,底层自动选择 JDK 或 CGLIB 代理
public class SpringProxyDemo {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(SpringProxyDemo.class, args);
OrderService orderService = context.getBean(OrderService.class);
// 设置用户角色
System.setProperty("user.role", "admin");
// ✅ 客户端调用,完全不知道用了代理!
orderService.createOrder("P001");
orderService.updateOrder(1L);
System.out.println(orderService.getOrderStatus(1L));
// 普通用户
System.setProperty("user.role", "guest");
try {
orderService.createOrder("P002"); // ❌ 抛出 SecurityException
} catch (SecurityException e) {
System.out.println(e.getMessage());
}
}
}
✅ 优点:
- 零侵入:业务代码完全不改
- 声明式:用
@Before、@After等注解声明增强逻辑 - 自动选择代理:有接口 → JDK 代理;无接口 → CGLIB 代理
- 集成 Spring:支持事务、缓存、安全等内置切面
- 企业级标准:Spring Boot 默认使用 AOP 实现所有增强功能
✅ Spring AOP 的本质就是代理模式:
| 代理模式 | Spring AOP |
|---|---|
Proxy 对象 | @Aspect 切面 |
InvocationHandler | @Before、@After 等通知方法 |
target.invoke() | joinPoint.proceed() |
| 手动创建代理 | @EnableAspectJAutoProxy 自动创建 |
✅ 结论:
你每天在用的@Transactional、@Cacheable、@Secured、@Log,都是代理模式的注解化实现!
✅ 五、代理模式 vs 装饰器模式 vs 适配器模式 对比
| 模式 | 目的 | 关键词 | 举例 |
|---|---|---|---|
| 代理模式 | 控制访问(是否能调) | “你有权限吗?” | 权限校验、事务、缓存、Feign |
| 装饰器模式 | 增强功能(加点料) | “你喝杯咖啡吗?” | 日志、加密、限流 |
| 适配器模式 | 转换接口(改接口) | “你插头不匹配,我给你转接头” | 微信 SDK → 标准接口 |
✅ 一句话区分:
- 代理:“你不能直接见老板,得经过我”
- 装饰器:“你见老板前先喝杯咖啡”
- 适配器:“你用的是 USB-A,老板用的是 USB-C,我给你个转接头”
✅ 六、代理模式的避坑指南(Java 后端高频踩坑)
| 问题 | 原因 | 解决方案 |
|---|---|---|
| ❌ 用代理模式实现装饰器功能 | 混淆用途 | ✅ 功能增强用装饰器,访问控制用代理 |
| ❌ 代理类中写业务逻辑 | 违反单一职责 | ✅ 代理只做拦截、控制,业务逻辑放 Service |
| ❌ 代理方法调用自身方法(this) | 代理失效 | ✅ 避免在代理类中 this.method(),应注入 @Autowired 的代理对象 |
❌ 代理 final 方法或类 | CGLIB 无法代理 | ✅ 避免用 final,或改用接口 + JDK 代理 |
| ❌ 没有开启 AOP | @Aspect 无效 | ✅ 添加 @EnableAspectJAutoProxy |
| ❌ 事务失效 | 方法是 private 或 static | ✅ 事务方法必须是 public,且由代理对象调用 |
| ❌ 多个代理嵌套顺序错乱 | 优先级混乱 | ✅ 用 @Order 控制切面执行顺序 |
✅ 重要陷阱:
@Service public class UserService { public void createUser() { updateUser(); // ❌ 这里调用的是 this.updateUser(),不是代理对象! } @Transactional public void updateUser() { ... } }→
updateUser()的事务会失效!因为this跳过了代理。
✅ 正确做法:
@Autowired private UserService self; // 注入自己(代理对象) public void createUser() { self.updateUser(); // ✅ 走代理,事务生效 }
✅ 七、学习建议与进阶路径
| 阶段 | 建议 |
|---|---|
| 📚 第一周 | 用 JDK 动态代理为 UserService 实现权限校验和日志 |
| 📚 第二周 | 用 CGLIB 为无接口的 OrderService 实现限流 |
| 📚 第三周 | 用 Spring AOP 实现 @Log 注解,自动记录所有 Controller 方法调用 |
| 📚 第四周 | 阅读 Spring 源码:ProxyFactory、DefaultAopProxyFactory 如何选择 JDK/CGLIB? |
| 📚 面试准备 | 准备回答: |
“你项目中哪里用了代理模式?”
“JDK 动态代理和 CGLIB 区别?”
“Spring AOP 是代理模式吗?”
“为什么 @Transactional 有时失效?” |
✅ 八、代理模式面试高频题(附答案)
Q1:代理模式解决了什么问题?
A:解决“在不修改原对象的前提下,控制对它的访问”,如权限、事务、缓存、远程调用。
Q2:JDK 动态代理和 CGLIB 代理有什么区别?
A:
- JDK:基于接口,使用反射,性能稍低,必须有接口
- CGLIB:基于继承,使用字节码生成,性能高,可代理无接口类,不能代理 final 类
- Spring 优先用 JDK,无接口时自动用 CGLIB
Q3:Spring AOP 是代理模式吗?
A:是的!Spring AOP 底层就是通过 JDK 动态代理或 CGLIB 代理实现的,
@Before、@Around就是代理逻辑。
Q4:为什么 @Transactional 有时不生效?
A:
- 方法不是
public- 方法是
private、static- 在类内部
this.method()调用,绕过了代理- 没有启用 AOP:缺少
@EnableAspectJAutoProxy
Q5:代理模式和装饰器模式的区别?
A:
- 代理:控制访问(是否能调)
- 装饰器:增强功能(怎么调)
→ 一个管“能不能”,一个管“加不加料”
✅ 九、总结:代理模式选型决策树
graph TD
A[需要控制对对象的访问吗?] --> B{目标对象有接口?}
B -->|是| C[使用 JDK 动态代理]
B -->|否| D[使用 CGLIB 代理]
C --> E[是否在 Spring 项目中?]
D --> E
E -->|是| F[用 @Aspect + @Before/@Around 实现 AOP]
E -->|否| G[手动使用 Proxy.newProxyInstance 或 Enhancer]
✅ 最终推荐:
- Spring 项目 → ✅ AOP + @Aspect(最优雅、最标准)
- 非 Spring、有接口 → ✅ JDK 动态代理
- 非 Spring、无接口 → ✅ CGLIB 代理
- 绝对不要:手写静态代理(除非教学)、在代理中写业务逻辑、忽略
@EnableAspectJAutoProxy
✅ 十、结语:真正的高手,不改代码,只设门卫
你不是在学“代理模式”,你是在学“如何在不破坏系统稳定性的前提下,实现安全、监控、事务等横切关注点”。
✅ 当你看到
@Transactional自动帮你开启事务、提交、回滚,而业务代码一行没改时,你已经掌握了 Spring 的灵魂。
✅ 当你用@Aspect统一记录所有接口的访问日志、性能监控、异常追踪时,你已经是架构师了。
不要为了“用模式”而用模式,
要为了“系统可安全、可监控、可维护”而选择它。
Java 代理模式深度学习指南&spm=1001.2101.3001.5002&articleId=152561631&d=1&t=3&u=e9974afb61f04e9fab17de9fa47750d4)

被折叠的 条评论
为什么被折叠?



