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

AspectJ环绕通知调用目标方法:避免无限循环且不遗漏方法捕获

AspectJ环绕通知调用目标方法避免无限循环的解决方案

我们需要用AspectJ捕获com.ABC.MyClass中所有方法的执行,目标类和初始切面代码如下:

目标类代码:

package com.ABC;

public class MyClass{
    public void methodA(){
    }

    public void methodB(){
        methodA();
    }
}

初始切面代码:

@Aspect
public class MyAspect{
    @Pointcut("execution(* com.ABC.MyClass.*(..))")
    public void captureMyClassMethods(){
    }
    
    @Around("captureMyClassMethods()")
    public Object aroundMyClassMethods(ProceedingJoinPoint jp) throws Throwable{
        MyClass object = (MyClass)jp.getTarget();

        object.methodA();      // 此处引发无限循环

        Object o = jp.proceed();
        System.out.println("Some data from o");
        return o;
    }
}

问题说明:

  • 环绕通知中调用object.methodA()会触发切点匹配,导致无限循环。
  • 若改用execution(* com.ABC.MyClass.*(..)) && !cflow(within(MyAspect))作为切点,会遗漏methodB()内部调用的methodA(),因为该调用处于切面的控制流中。

方案一:使用@Privileged注解(AspectJ原生支持)

通过@Privileged标记环绕通知,让通知内部发起的目标方法调用不触发当前切面的切点,同时不影响目标类内部方法调用的捕获。

修改后的切面代码:

@Aspect
public class MyAspect{
    @Pointcut("execution(* com.ABC.MyClass.*(..))")
    public void captureMyClassMethods(){
    }
    
    @Privileged
    @Around("captureMyClassMethods()")
    public Object aroundMyClassMethods(ProceedingJoinPoint jp) throws Throwable{
        MyClass object = (MyClass)jp.getTarget();

        object.methodA();      // 不会引发无限循环

        Object o = jp.proceed();
        System.out.println("Some data from o");
        return o;
    }
}

原理:
@Privileged是AspectJ的原生注解,它会让通知内部的方法调用跳过当前切面的切点匹配。这样:

  1. 通知内直接调用object.methodA()时,不会触发当前切面的环绕通知,避免无限循环。
  2. methodB()内部调用的methodA()属于目标类自身的执行流程,不在@Privileged的作用范围内,仍会被正常捕获。

方案二:通过反射直接调用目标方法

利用Java反射绕开AspectJ织入的切面代码,直接调用目标方法的原始实现。

修改后的切面代码:

import java.lang.reflect.Method;

@Aspect
public class MyAspect{
    @Pointcut("execution(* com.ABC.MyClass.*(..))")
    public void captureMyClassMethods(){
    }
    
    @Around("captureMyClassMethods()")
    public Object aroundMyClassMethods(ProceedingJoinPoint jp) throws Throwable{
        MyClass object = (MyClass)jp.getTarget();

        // 通过反射调用methodA,绕开切面
        Method methodA = MyClass.class.getDeclaredMethod("methodA");
        methodA.setAccessible(true);
        methodA.invoke(object);

        Object o = jp.proceed();
        System.out.println("Some data from o");
        return o;
    }
}

原理:
反射调用直接操作目标方法的字节码实现,不会触发AspectJ织入的切面逻辑,因此不会产生无限循环。同时,methodB()内部的methodA()调用仍会被切面正常捕获。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 09:59:53