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获取当前代理对象:
- 添加AOP配置类:
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration @EnableAspectJAutoProxy(exposeProxy = true) // 暴露代理对象到AopContext public class AopConfig { }
- 修改
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直接修改字节码,支持内部方法调用的切面触发:
- 添加AspectJ依赖:
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> </dependency>
- 修改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
相关产品推荐
相关产品推荐

