You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中@Around Advice注解会执行两次吗?自定义注解场景咨询

关于@Around注解Advice多次执行问题的分析与解决

首先得说,你当前用的这个切点表达式 @Around(value = "@annotation(MyAnnotation) && args(MyArgs)") 是完全没问题的——它确实能精准匹配到标记了@MyAnnotation、且参数是MyArgs类型的方法,就像你给出的示例方法那样,正常工作+获取参数都不在话下。

不过你提到的"仅用注解会导致Advice执行多次"的情况,我也碰到过,大概率是下面这几个原因搞的鬼:

  • 代理重复叠加:如果你的项目里同时用了多种代理机制(比如Spring AOP加上自定义的代理逻辑),同一个方法调用就会被多个代理拦截,自然触发多次Advice执行。
  • 切点匹配范围太宽:要是@MyAnnotation既标在了父类方法上,又标在了子类重写的方法上,Spring AOP的代理可能会同时匹配到父类和子类的方法,导致重复执行。
  • 内部方法调用的代理冲突:同一个类内部调用被注解标记的方法时,Spring动态代理本来会失效,但如果同时还有AspectJ编译时织入这类机制在运行,就可能出现"一个调用被两种代理处理"的情况,进而多次执行Advice。

针对这些情况,给你几个实用的解决思路:

  1. 统一代理机制:先排查项目里是不是同时用了多种代理方式(比如Spring AOP + AspectJ),要是的话,要么统一成一种,要么试试@EnableAspectJAutoProxy(proxyTargetClass = true)来优化代理逻辑,减少冲突。
  2. 缩小切点匹配范围:如果不需要匹配父类或者其他包的方法,可以给切点表达式加上类限定,比如:
    @Around(value = "@annotation(MyAnnotation) && args(MyArgs) && within(com.your.project.package..*)")
    
    这样就只会匹配指定包下的类,避免不必要的匹配。
  3. 处理内部调用问题:如果是同一个类内部调用导致的重复,可以通过获取自身的代理对象来调用方法(比如把代理对象注入到类里),或者直接改用AspectJ编译时织入的方式。
  4. 临时应急:加执行标记:要是暂时找不到根源,可以给Advice加个线程本地的标记,确保同一个方法调用只执行一次逻辑:
    private ThreadLocal<Boolean> hasExecuted = new ThreadLocal<>();
    
    @Around(value = "@annotation(MyAnnotation) && args(MyArgs)")
    public Object aroundAdvice(ProceedingJoinPoint joinPoint, MyArgs args) throws Throwable {
        if (Boolean.TRUE.equals(hasExecuted.get())) {
            return joinPoint.proceed();
        }
        hasExecuted.set(true);
        try {
            // 这里写你的Advice业务逻辑
            return joinPoint.proceed();
        } finally {
            hasExecuted.remove(); // 记得清理标记,避免内存泄漏
        }
    }
    

内容的提问来源于stack exchange,提问作者Hearen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:54:15