news 2026/4/22 2:27:40

【硬核实战】Spring AOP 从原理到落地:3 个可运行案例带你吃透切面编程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【硬核实战】Spring AOP 从原理到落地:3 个可运行案例带你吃透切面编程

作者风格:MY_TEUCK 硬核实战风 + AI 应用落地风
读者对象:Java 学习者 / Spring Boot 初中级开发者
阅读目标:不仅知道 AOP 是什么,更知道什么时候用、怎么写、怎么避坑


前言

很多同学第一次学 AOP(面向切面编程)会有两个误区:

  1. 只会背概念:Aspect、Pointcut、Advice,但写不出可用代码。
  2. 只会抄例子:日志打印能跑,但一到业务场景(权限、幂等、审计)就不会落地。

这篇文章直接走实战路线:
先把思想讲透,再给你可运行代码,最后落到真实业务场景和面试答法,确保你学完就能用。


一、概念解析:AOP 到底是什么?

1.1 一句话定义

AOP 是把“横切关注点”从业务代码中抽离出来,统一管理的一种编程思想。

什么叫横切关注点?

  • 不是核心业务本身(比如下单、支付、查询订单)
  • 但很多地方都要做(比如日志、权限、事务、审计、幂等)

1.2 为什么需要 AOP?

如果不用 AOP,代码常变成这样:

  • 每个方法都写一遍日志
  • 每个接口都写一遍权限判断
  • 每次更新都手动补审计字段

结果是:重复、易漏、难维护。

1.3 AOP 与 OOP 的关系

  • OOP:负责纵向建模(订单服务、商品服务、用户服务)
  • AOP:负责横向增强(日志、权限、监控、审计)

它们不是替代关系,而是互补关系。


二、原理:Spring AOP 是怎么工作的?

Spring AOP 的核心不是“魔法”,而是代理模式

2.1 执行链路

  1. Spring 启动扫描到切面(@Aspect
  2. 根据切点(Pointcut)匹配目标方法
  3. 为目标 Bean 创建代理对象(JDK 动态代理 / CGLIB)
  4. 你调用的是代理对象
  5. 代理在合适时机执行通知(Advice)再执行目标方法

2.2 关键术语(必须会)

  • Aspect(切面):承载增强逻辑的类
  • Pointcut(切点):定义拦截哪些方法
  • Advice(通知):定义何时增强(前置/后置/环绕/异常)
  • JoinPoint(连接点):可被增强的方法执行点
  • Weaving(织入):把切面应用到目标对象的过程

三、实战代码:3 个可运行 AOP 案例

下面示例基于 Spring Boot,直接可用。

3.1 准备依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>

3.2 案例一:接口耗时统计(最直观)

(1)切面代码
packagecom.example.aop;importlombok.extern.slf4j.Slf4j;importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.Around;importorg.aspectj.lang.annotation.Aspect;importorg.springframework.stereotype.Component;@Aspect@Component@Slf4jpublicclassCostTimeAspect{@Around("execution(* com.example.service..*(..))")publicObjectrecordTime(ProceedingJoinPointpjp)throwsThrowable{longstart=System.currentTimeMillis();try{returnpjp.proceed();}finally{longcost=System.currentTimeMillis()-start;log.info("method={} cost={}ms",pjp.getSignature().toShortString(),cost);}}}
(2)业务代码
packagecom.example.service;importorg.springframework.stereotype.Service;@ServicepublicclassOrderService{publicStringcreateOrder()throwsInterruptedException{Thread.sleep(120);return"ok";}}

3.3 案例二:自定义注解 + 权限校验

(1)定义注解
packagecom.example.aop;importjava.lang.annotation.*;@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public@interfaceRequiresRole{Stringvalue();}
(2)切面校验
packagecom.example.aop;importorg.aspectj.lang.JoinPoint;importorg.aspectj.lang.annotation.Aspect;importorg.aspectj.lang.annotation.Before;importorg.aspectj.lang.reflect.MethodSignature;importorg.springframework.stereotype.Component;@Aspect@ComponentpublicclassRoleCheckAspect{@Before("@annotation(com.example.aop.RequiresRole)")publicvoidcheckRole(JoinPointjoinPoint){MethodSignaturesignature=(MethodSignature)joinPoint.getSignature();RequiresRolerequiresRole=signature.getMethod().getAnnotation(RequiresRole.class);StringneedRole=requiresRole.value();// 示例:真实项目可从 ThreadLocal / JWT 中取当前用户角色StringcurrentRole="USER";if(!needRole.equals(currentRole)){thrownewRuntimeException("无权限访问,needRole="+needRole);}}}
(3)使用注解
packagecom.example.service;importcom.example.aop.RequiresRole;importorg.springframework.stereotype.Service;@ServicepublicclassAdminService{@RequiresRole("ADMIN")publicStringdeleteUser(){return"deleted";}}

3.4 案例三:公共字段自动填充(企业项目高频)

这个场景是很多管理系统都存在的真实需求:

  • 新增时自动填充createTime/createUser/updateTime/updateUser
  • 更新时自动填充updateTime/updateUser
(1)注解 + 操作类型
publicenumOperationType{INSERT,UPDATE}
@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public@interfaceAutoFill{OperationTypevalue();}
(2)切面核心逻辑
@Aspect@ComponentpublicclassAutoFillAspect{@Before("execution(* com.example.mapper..*(..)) && @annotation(com.example.aop.AutoFill)")publicvoidautoFill(JoinPointjoinPoint)throwsException{MethodSignaturesignature=(MethodSignature)joinPoint.getSignature();AutoFillautoFill=signature.getMethod().getAnnotation(AutoFill.class);OperationTypetype=autoFill.value();Objectentity=joinPoint.getArgs()[0];LocalDateTimenow=LocalDateTime.now();LongcurrentUserId=1L;// 示例,真实项目从上下文取if(type==OperationType.INSERT){entity.getClass().getMethod("setCreateTime",LocalDateTime.class).invoke(entity,now);entity.getClass().getMethod("setCreateUser",Long.class).invoke(entity,currentUserId);}entity.getClass().getMethod("setUpdateTime",LocalDateTime.class).invoke(entity,now);entity.getClass().getMethod("setUpdateUser",Long.class).invoke(entity,currentUserId);}}

四、场景案例:AOP 在业务中怎么选?

4.1 订单系统

  • 下单接口:幂等切面,防重复提交
  • 核心服务:耗时切面,定位慢调用
  • 管理接口:权限切面,拦截越权操作

4.2 后台管理系统

  • 数据变更:操作审计切面(谁、何时、改了什么)
  • 增删改接口:统一日志切面
  • 通用字段:自动填充切面

4.3 AI 应用落地场景

在 AI 业务里,AOP 同样有价值:

  • 模型调用耗时统计(推理耗时、token 消耗)
  • Prompt 安全校验(敏感词、越权指令)
  • 统一打点埋点(命中率、错误率、重试次数)

重点:AOP 不是传统业务专属,在 AI 工程化里同样是“横向治理利器”。


五、避坑指南(实战高频)

5.1 自调用失效

同类中this.xxx()调用可能绕过代理,导致切面不生效。
解决:通过代理对象调用,或拆分到其他 Bean。

5.2 切点写错

  • 写太宽:误伤无关方法
  • 写太窄:该拦截的没拦截

建议先在切面里打日志确认命中范围。

5.3 多切面顺序混乱

多个切面叠加时用@Order明确顺序,避免执行链不可控。

5.4 环绕通知漏写proceed()

@Around不调用proceed(),目标方法不会执行。这个坑非常常见。

5.5 反射异常未处理

自动填充常用反射,setter 名称、参数类型要严格一致,异常处理要完整。


六、面试题(高频 + 可直接回答)

题 1:AOP 的核心价值是什么?

把横切关注点(日志、权限、事务等)从业务逻辑中剥离,减少重复代码,提高一致性和可维护性。

题 2:Spring AOP 和动态代理有什么关系?

Spring AOP 基于代理模式实现增强:目标对象被代理后,在方法执行前后插入通知逻辑。

题 3:@Before@Around怎么选?

  • 只做前置校验:@Before
  • 需要统计耗时、控制是否执行原方法:@Around

题 4:为什么事务有时不生效?

常见原因是自调用绕过代理、方法不是public、异常被吞掉或配置不当。

题 5:AOP 适合所有逻辑吗?

不适合。只建议用于跨模块、规则统一、与业务相对解耦的逻辑。


总结

AOP 真正的价值不是“写了个切面”,而是建立一套工程化思维:

  • 把重复横向逻辑统一治理
  • 让业务代码专注核心业务
  • 让系统更稳定、更可维护、更易扩展

你可以从这条落地路径开始:

  1. 先做耗时统计切面(最快看到收益)
  2. 再做权限切面(业务价值高)
  3. 最后做审计/幂等/自动填充(系统化治理)

当你把 AOP 用到“看不到它,但处处受益”的程度,你就真正掌握它了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/22 2:21:36

神经网络与柯尔莫哥洛夫表示定理的数学本质

1. 神经网络与纯数学的深层联系作为一名长期游走于理论物理与机器学习交叉领域的研究者&#xff0c;我始终被一个核心问题所吸引&#xff1a;为什么深度神经网络能在缺乏严格理论支撑的情况下&#xff0c;展现出如此惊人的泛化能力&#xff1f;答案或许藏在数学分析的宝库中——…

作者头像 李华
网站建设 2026/4/22 2:20:35

信号与系统/控制工程必看:用留数定理手算Laplace逆变换,保姆级步骤拆解

信号与系统实战&#xff1a;用留数定理手算Laplace逆变换的工程指南 在电路分析和控制系统设计中&#xff0c;我们经常需要将复杂的S域传递函数转换回时域响应。传统教材中介绍的查表法和部分分式分解法虽然基础&#xff0c;但在处理某些复杂情况时显得力不从心。留数定理作为复…

作者头像 李华
网站建设 2026/4/22 2:19:38

手把手解读:NOTEARS论文里的评估函数(FDR/SHD)到底在算什么?

因果模型评估实战&#xff1a;从NOTEARS源码拆解FDR/SHD计算逻辑 在因果推断领域&#xff0c;评估模型性能是验证算法有效性的关键环节。NOTEARS论文中提出的count_accuracy函数实现了多种评估指标的计算&#xff0c;其中**FDR&#xff08;误发现率&#xff09;和SHD&#xff0…

作者头像 李华