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

Spring Boot AOP嵌套自定义注解未触发问题求助

解决Spring Boot AOP嵌套注解@Traceable不生效问题

问题原因

Spring AOP默认采用动态代理实现,当同一个类内部方法互相调用时(比如get()调用test1()/test2()),是通过原始对象的this直接调用方法,而非通过Spring生成的代理对象,因此切面逻辑不会被触发。只有外部通过代理对象调用方法时,切面才会生效。

解决方案

方案1:自注入代理对象

在当前类中注入自身的代理实例,通过代理对象调用内部方法:

修改ControllerTest代码:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/test")
public class ControllerTest {

    // 注入自身的代理对象
    @Autowired
    private ControllerTest self;

    @GetMapping("/get")
    @Traceable
    public String get(){
        // 通过代理对象调用方法
        self.test1();
        self.test2();
        return "Hi";
    }
    
    @Traceable
    public void test1(){
        String str = "1";
        System.out.println(str);
    }

    @Traceable
    public Object test2(){
        String str = "2";
        System.out.println(str);
        // 同样通过代理对象调用
        self.test1();
        return null;
    }
}

方案2:使用AopContext获取代理对象

开启代理暴露,通过AopContext获取当前代理对象:

  1. 添加AOP配置类:
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy(exposeProxy = true) // 暴露代理对象到AopContext
public class AopConfig {
}
  1. 修改ControllerTest调用逻辑:
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/test")
public class ControllerTest {

    @GetMapping("/get")
    @Traceable
    public String get(){
        // 获取代理对象并调用方法
        ((ControllerTest) AopContext.currentProxy()).test1();
        ((ControllerTest) AopContext.currentProxy()).test2();
        return "Hi";
    }
    
    @Traceable
    public void test1(){
        String str = "1";
        System.out.println(str);
    }

    @Traceable
    public Object test2(){
        String str = "2";
        System.out.println(str);
        // 同样通过代理对象调用
        ((ControllerTest) AopContext.currentProxy()).test1();
        return null;
    }
}

方案3:改用AspectJ织入(编译/加载时)

如果不想修改业务代码,可以改用AspectJ直接修改字节码,支持内部方法调用的切面触发:

  1. 添加AspectJ依赖:
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
</dependency>
  1. 修改AOP配置,启用加载时织入:
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableLoadTimeWeaving;

@Configuration
@EnableLoadTimeWeaving(aspectjWeaving = EnableLoadTimeWeaving.AspectJWeaving.ENABLED)
public class AopConfig {
}

这种方式不需要修改业务代码中的调用方式,内部方法调用也能触发切面,但配置相对复杂,适合不想侵入业务代码的场景。

验证结果

修改后运行测试,控制台输出会符合预期:

Inside Aspect
Inside Aspect
1
Inside Aspect
2
Inside Aspect
1
Hi

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 18:45:59