Spring AOP 中@annotation的两种写法使用
在 Spring AOP 的开发中,我们经常看到这样的切面写法:
@Before("@annotation(com.example.annotation.PayLog)")
public void beforeAnnotation() {
System.out.println("通过 @annotation 拦截带 @PayLog 注解的方法");
}
或者这样:
@Before("@annotation(payLog)")
public void beforeAnnotation(PayLog payLog) {
System.out.println("检测到支付操作:" + payLog.value());
}
看起来很相似,但又不太一样 🤔
到底有什么区别?为什么都能生效?
这篇文章帮你彻底搞清楚!
一、什么是 @annotation
在 AOP(Aspect-Oriented Programming,面向切面编程)中,
我们通过切点表达式定义要拦截的方法。
其中,@annotation(...) 是一种非常常见的表达式,用来匹配:
“所有带有指定注解的方法”。
举个例子
假设我们定义了一个自定义注解 @PayLog:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PayLog {
String value() default "默认支付";
}
二、写法一:只拦截方法,不读取注解内容
@Aspect
@Component
public class PayAspect {
@Before("@annotation(com.example.annotation.PayLog)")
public void beforeAnnotation() {
System.out.println("通过 @annotation 拦截带 @PayLog 注解的方法");
}
}
这段切面表示:
“在执行任何带有 @PayLog 注解的方法之前,先执行我这个方法。”
示例:
@Service
public class OrderService {
@PayLog
public void pay() {
System.out.println("执行支付逻辑...");
}
}
输出:
通过 @annotation 拦截带 @PayLog 注解的方法
执行支付逻辑...
🧩 解释:
@annotation(com.example.annotation.PayLog)表示拦截所有被该注解标记的方法;beforeAnnotation()方法执行时,并不会接收到注解对象;- 这种写法适合只想拦截,不需要读取注解里的内容。
三、写法二:拦截 + 获取注解对象
@Aspect
@Component
public class PayAspect {
@Before("@annotation(payLog)")
public void beforeAnnotation(PayLog payLog) {
System.out.println("检测到支付操作:" + payLog.value());
}
}
这段代码看起来只多了一个参数 payLog,
其实功能更强大——它可以直接获取目标方法上的注解实例。
示例
@Service
public class OrderService {
@PayLog("微信支付")
public void payWx() {
System.out.println("执行微信支付逻辑...");
}
@PayLog("支付宝支付")
public void payAli() {
System.out.println("执行支付宝支付逻辑...");
}
}
输出结果:
检测到支付操作:微信支付
执行微信支付逻辑...
检测到支付操作:支付宝支付
执行支付宝支付逻辑...
🧠 解释:
@annotation(payLog)告诉 AOP:
拦截时把目标方法上的@PayLog实例赋值给payLog参数;- 于是我们可以直接通过
payLog.value()获取注解中的值。
四、两种写法的对比总结
| 对比项 | 写法一 | 写法二 |
|---|---|---|
| 表达式 | @annotation(com.example.annotation.PayLog) | @annotation(payLog) |
| 方法参数 | 无 | 有(注解类型参数) |
| 是否能读取注解内容 | ❌ 否 | ✅ 可以 |
| 主要用途 | 只做拦截、执行前后逻辑 | 需要读取注解参数(如描述、类型等) |
| 示例应用 | 简单记录日志 | 根据注解参数执行不同逻辑 |
五、完整运行示例
1、自定义注解
package com.example.annotation;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PayLog {
String value() default "默认支付类型";
}
2、AOP 切面类
package com.example.aspect;
import com.example.annotation.PayLog;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class PayAspect {
// 写法一:只拦截
@Before("@annotation(com.example.annotation.PayLog)")
public void onlyIntercept() {
System.out.println("拦截到带 @PayLog 注解的方法");
}
// 写法二:拦截 + 获取注解
@Before("@annotation(payLog)")
public void beforeWithAnnotation(PayLog payLog) {
System.out.println("检测到支付操作:" + payLog.value());
}
}
3、被拦截的业务类
package com.example.service;
import com.example.annotation.PayLog;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
@PayLog("微信支付")
public void payWx() {
System.out.println("执行微信支付逻辑...");
}
@PayLog("支付宝支付")
public void payAli() {
System.out.println("执行支付宝支付逻辑...");
}
}
4、输出结果
拦截到带 @PayLog 注解的方法
检测到支付操作:微信支付
执行微信支付逻辑...拦截到带 @PayLog 注解的方法
检测到支付操作:支付宝支付
执行支付宝支付逻辑...
六、总结
@annotation 有两种写法:
- @annotation(注解类路径):只拦截,不读参数;
- @annotation(变量名) + 方法参数:拦截并获取注解对象。
两者都对,只是用途不同。
| 场景 | 推荐写法 |
|---|---|
| 只想拦截注解方法,不关心内容 | @annotation(com.xxx.PayLog) |
| 需要读取注解参数(如 type、desc) | @annotation(payLog) + PayLog payLog |
| 想统一记录操作日志 | 推荐带参数写法,灵活性更强 |
到此这篇关于Spring AOP 中@annotation的两种写法使用的文章就介绍到这了,更多相关Spring AOP @annotation内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
springboot快速搭建ftpserver服务端的详细步骤
基于springboot,使用ftpserver快速搭建一个FTP服务端,搭建过程很简单,我们把过程分成4个步骤,一分钟内快速完成构建,感兴趣的朋友跟随小编一起看看吧2023-11-11
深入解析Spring AI框架如何在Java应用中实现智能化交互的关键
本文详细介绍了SpringAI框架在Java应用中的应用,包括实体类映射、函数回调等核心功能的实现,通过源码分析,帮助开发者更好地理解和使用这些高级特性,提升业务效率,感兴趣的朋友跟随小编一起看看吧2024-11-11
spring源码阅读--@Transactional实现原理讲解
这篇文章主要介绍了spring源码阅读--@Transactional实现原理讲解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2021-09-09


最新评论