黑马JavaWeb+AI笔记 Day12 Web后端实战(AOP)
全称:Aspect Oriented Programming(面向切面编程 / 面向方面编程)定义:在不改变原始业务逻辑的前提下,将一些公共行为(如日志、权限校验、事务控制等)从业务代码中抽取出来统一管理。场景:案例中部分业务方法运行较慢,定位执行耗时较长的接口,此时需要统计每一个业务方法的执行耗时。模块核心内容与关键理解点AOP 概念统一处理共性问题的技术(如日志、安全、事务)核心术语通知类型表
·
一、什么是AOP?
全称:Aspect Oriented Programming(面向切面编程 / 面向方面编程)
定义:在不改变原始业务逻辑的前提下,将一些公共行为(如日志、权限校验、事务控制等)从业务代码中抽取出来统一管理。
场景:案例中部分业务方法运行较慢,定位执行耗时较长的接口,此时需要统计每一个业务方法的执行耗时。
✅ AOP 优势
优势 | 说明 |
---|---|
减少重复代码 | 公共逻辑抽出,不需重复写 |
代码无侵入 | 原业务逻辑不需要修改 |
提高开发效率 | 共性功能一次配置,全局生效 |
易于维护 | 修改公共逻辑时,只需改一处即可 |
二、AOP核心概念
✅概念
名称 | 含义说明 |
---|---|
JoinPoint | 连接点:可以被 AOP 拦截的方法或执行点(如所有方法) |
PointCut | 切入点:实际要拦截的方法的定义规则(如 service.*) |
Advice | 通知:定义要执行的横切逻辑(如日志、权限) |
Aspect | 切面:通知 + 切入点的组合体 |
Target | 目标对象:被增强的原始业务类 |
✅引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
✅编写切面类
@Slf4j
@Aspect
@Component
public class TimeAspect {
@Around("execution(* com.xxx.service.impl.*.*(..))")
public Object recordExecutionTime(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
Object result = pjp.proceed(); // 原始方法执行
long end = System.currentTimeMillis();
log.info("执行方法:{},耗时:{}ms", pjp.getSignature(), end - start);
return result;
}
}
三、通知类型详解
✅通知类型
通知注解 | 说明 |
---|---|
@Around | 环绕通知,目标方法前后都能执行 ✅ 最常用 |
@Before | 前置通知,在目标方法执行前调用 |
@After | 后置通知,无论是否异常都会执行 |
@AfterReturning | 返回后通知,方法正常返回后执行(异常不会执行) |
@AfterThrowing | 异常通知,目标方法抛出异常时执行 |
✅ @PointCut 抽取公共切入点表达式
@Pointcut("execution(* com.xxx.service.impl.*.*(..))")
private void serviceMethods() {}
@Around("serviceMethods()")
public Object around(ProceedingJoinPoint jp) { ... }
✅ 通知顺序
不同切面类中,默认按照切面类的类名字母排序:
-
目标方法前的通知方法:字母排名靠前的先执行
- 目标方法后的通知方法:字母排名靠前的后执行
用 @Order(数字)加在切面类上来控制顺序
- 目标方法前的通知方法:数字小的先执行
- 目标方法后的通知方法:数字小的后执行
四、切入点表达式详解
✅ execution 表达式语法
execution([修饰符] 返回值类型 包名.类名.方法名(参数) throws 异常)
✅ 通配符说明
通配符 | 含义 |
---|---|
* | 匹配任意单个项(如返回值、类名等) |
… | 匹配任意层级包名 / 参数列表 |
✅ @annotation 表达式(通过注解匹配)
- 适用于无法通过方法签名表达的切面需求(如指定加了某个注解的方法)
@Around("@annotation(com.itheima.anno.Log)")
五、连接点
对于@Around通知,获取连接点信息只能使用 ProceedingJoinPoint
对于其它四种通知,获取连接点信息只能使用 JoinPoint ,它是 ProceedingJoinPoint 的父类型
方法 | 作用 |
---|---|
getTarget() | 获取目标对象 |
getTarget().getClass().getName(); | 获取目标类 |
getSignature().getName(); | 获取目标方法 |
getArgs(); | 获取目标方法参数 |
六、ThreadLocal 用于传递登录用户信息
✅ 问题:如何从 JWT 中解析出的员工 ID 传给 AOP 程序?
✅ ThreadLocal 原理
- 是“线程内的全局变量”
- 每个线程有自己独立的变量副本,线程安全
✅ 用法示例
// 设置
ThreadLocalUtils.set(currentUserId);
// 获取
Long id = ThreadLocalUtils.get();
// 清除
ThreadLocalUtils.remove();
✅ 应用流程
- 在 TokenFilter 中解析 JWT,得到登录员工 ID
- 将 ID 存入 ThreadLocal
- 在 AOP 或 Controller 中读取 ThreadLocal 获取登录用户信息
- 用完清除,避免内存泄漏
✅ 总结表
模块 | 核心内容与关键理解点 |
---|---|
AOP 概念 | 统一处理共性问题的技术(如日志、安全、事务) |
核心术语 | JoinPoint、PointCut、Advice、Aspect、Target |
通知类型 | @Before、@After、@Around、@AfterReturning、@AfterThrowing |
表达式写法 | execution、@annotation,支持通配符 * 和 … |
实战日志案例 | 使用环绕通知 + ThreadLocal + JWT 实现用户行为记录 |
更多推荐
所有评论(0)