Spring AOP 中@annotation的两种写法使用

 更新时间:2026年02月11日 10:07:25   作者:Knight_AL  
本文介绍了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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 基于@RequestMapping 用法详解之地址映射

    基于@RequestMapping 用法详解之地址映射

    这篇文章主要介绍了@RequestMapping 用法详解之地址映射,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • 布隆过滤器(Bloom Filter)的Java实现方法

    布隆过滤器(Bloom Filter)的Java实现方法

    下面小编就为大家带来一篇布隆过滤器(Bloom Filter)的Java实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • spring boot环境抽象的实现方法

    spring boot环境抽象的实现方法

    在实际开发中,开发人员在编写springboot的时候通常要在本地环境测试然后再部署到Production环境,这两种环境一般来讲是不同的,最主要的区别就是数据源的不同。本文主要介绍了这两种,感兴趣的可以了解一下
    2019-04-04
  • 使用通过ARP类似P2P终结者实现数据封包

    使用通过ARP类似P2P终结者实现数据封包

    目前网络上类似P2P终结者这类软件,主要都是基于ARP欺骗实现的,网络上到处都有关于ARP的介绍,不过为了本文读者不需要再去查找,我就在这里大概讲解一下
    2012-12-12
  • Spring全家桶中@CacheEvict无效情况的问题解决

    Spring全家桶中@CacheEvict无效情况的问题解决

    本文主要介绍了SpringBoot中@CacheEvict注解删除缓存无效的情况,主要包括Controller直接调用、key值不匹配、方法组织、返回值类型和代理机制,具有一定的参考价值,感兴趣的可以了解一下
    2025-10-10
  • SpringBoot整合JPA详细代码实例

    SpringBoot整合JPA详细代码实例

    这篇文章主要给大家介绍了关于SpringBoot整合JPA的相关资料,JPA(Java Persistence API)是Sun官方提出的Java持久化规范,它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据,需要的朋友可以参考下
    2024-05-05
  • springboot集成redisson的三种方式

    springboot集成redisson的三种方式

    本文主要介绍了springboot集成redisson的三种方式,包含自定义配置+手动注入,使用Yaml方式批量读取配置和spring boot自动配置类这三种,具有一定的参考价值,感兴趣的可以了解一下
    2024-03-03
  • java.math包下计算浮点数和整数的类的实例

    java.math包下计算浮点数和整数的类的实例

    这篇文章主要介绍了java.math包下计算浮点数和整数的类的实例代码,本文通过使用BigDecimal进行浮点数比较给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-02-02
  • 关于Java中的实体类要 implements Serializable的原因分析

    关于Java中的实体类要 implements Serializable的原因分析

    这篇文章主要介绍了Java中的实体类为什么要 implements Serializable,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-06-06
  • Java如何调用C++ DLL库

    Java如何调用C++ DLL库

    本文重点给大家介绍java中调用c++ dll库的方法,本文分步骤介绍的非常详细,感兴趣的朋友可以参考下
    2016-06-06

最新评论