初识aop进阶

28 阅读3分钟

以“保镖(AOP)”和“大明星(目标方法)”的故事为例。现在这一课,就是要教保镖们“什么时候动手” 、 “好几个保镖怎么排队”以及“怎么精准地拦住该拦的人”。


1. 通知类型 (Advice Types)

这就是在规定保镖在什么时间点干活。

Spring AOP 提供了 5 种时间点,你只需要记住最厉害的那个(@Around),但其他的也要知道意思:

注解名字演唱会类比(时间点)
@Before前置通知入场前。安检、收手机。
@After后置通知散场后。不管演唱会是圆满成功还是出了事故,最后都要打扫卫生。
@AfterReturning返回后通知圆满结束后。只有演出顺利(没报错),才开香槟庆祝。
@AfterThrowing异常后通知出事故后。只有演出搞砸了(抛异常了),才启动公关预案。
@Around环绕通知全能大管家。它能决定大明星能不能上台,能改大明星的出场费(返回值),能捕获大明星的失误。 (这个最常用!)

2. 通知顺序 (Advice Order)

场景:如果大明星请了两个保镖团队(定义了两个 AOP 切面类),一个负责“记日志”,一个负责“检查权限”。

问题:谁先上?

这就好比剥洋葱,或者穿衣服:

  • 进去的时候(Before)数字越小,越先执行
  • 出来的时候(After)数字越小,越后执行(因为它在最外层)。

怎么控制?

在切面类上加一个注解:@Order(1)。

  • @Order(1) 的保镖站在最外层(先拦截请求,最后放行响应)。
  • @Order(2) 的保镖站在里层。

3. 切入点表达式 (Pointcut Expressions)

这就是在教保镖“如何精准识别目标”。

主要有两种写法,一种是“按地址找人”,一种是“按标签找人”。

A. execution(...) —— 按地址找(比较繁琐)

你得把包名、类名、方法名写得清清楚楚。

  • 写法:execution(* com.itheima.service.impl.EmpServiceImpl.*(..))
  • 缺点:万一你改了类名,这行代码就废了。而且不够灵活。

B. @annotation(...) —— 按标签找(推荐!好用!

这是进阶玩法的核心。

  1. 你自己做一个注解(比如叫 @MyLog)。
  2. 你想管哪个方法,就在哪个方法头上贴一个 @MyLog
  3. AOP 配置里写:@annotation(com.itheima.anno.MyLog)
  4. 效果:保镖只拦截贴了标签的方法。

4. 连接点 (JoinPoint)

这是保镖手里的“情报单”。

当 AOP 拦截到方法时,你肯定想知道:“我是拦住了谁?他带了什么参数?”

JoinPoint 就是干这个的。

在你的通知方法里,加上这个参数,Spring 会自动传给你:

Java

// 在 Advice 方法里
public void recordLog(JoinPoint joinPoint) {
    // 1. 获取目标方法的方法名
    String methodName = joinPoint.getSignature().getName();
    
    // 2. 获取目标方法收到的参数(比如 id=1)
    Object[] args = joinPoint.getArgs();
    
    // 3. 获取目标对象本身
    Object target = joinPoint.getTarget();
    
    System.out.println("我拦住了方法:" + methodName + ",参数是:" + Arrays.toString(args));
}

注意:如果是 @Around 环绕通知,参数类型要用功能更强的子接口 ProceedingJoinPoint,因为它多了一个 .proceed() 方法(让目标方法继续执行)。


总结

这四个概念其实就是回答了 AOP 编程的四个问题:

  1. 类型:保镖在入场前还是散场后动手?
  2. 顺序:好几个保镖谁说了算?(@Order
  3. 表达式:怎么告诉保镖去拦谁?(推荐用 @annotation 贴标签法)
  4. 连接点:保镖怎么知道拦下来的人叫什么名字、带了什么东西?(JoinPoint