Spring注解式AOP除首个切入点外Advice执行两次问题求助
解决Spring注解AOP通知执行两次的问题
看起来你遇到的核心问题是切面通知被重复执行,这在纯注解AOP配置里最常见的原因是切面类被Spring容器重复注册了,我来帮你一步步排查和解决:
一、排查核心原因:切面实例重复创建
你现在的配置是:
- 在
LoggingConfig里用@Bean手动创建了PreProcessLogs实例 PreProcessLogs本身标注了@Aspect
如果你的项目开启了组件扫描(比如用了@SpringBootApplication或者@ComponentScan),且PreProcessLogs所在的包被扫描到,那么Spring会做两件事:
- 因为
@Aspect+组件扫描,自动把PreProcessLogs注册为Bean - 因为
LoggingConfig里的@Bean,又手动创建了一个PreProcessLogs实例
这就导致容器里存在两个切面实例,每个实例都会触发对应的通知,自然就执行两次了。
你可以快速验证:在PreProcessLogs的构造函数里加一行日志,启动应用时如果日志打印两次,就确认是这个问题。
二、两种解决方案
方案1:用组件扫描管理切面(推荐)
去掉LoggingConfig里的@Bean声明,给切面类加上@Component注解,让Spring通过组件扫描自动注册:
修改切面类:
@Aspect @Component // 加上这个注解 public class PreProcessLogs { // 你的@Before、@After等通知方法 @Before("your-pointcut-expression") public void beforeAdvice(JoinPoint joinPoint) { // 你的逻辑 } }
简化配置类:
@Configuration @EnableAspectJAutoProxy // 如果切面不在当前配置类的包及其子包下,需要加上@ComponentScan指定切面所在包 // @ComponentScan(basePackages = "com.yourpackage.aspect") public class LoggingConfig { // 移除@Bean PreProcessLogs的代码 }
方案2:仅通过@Bean注册切面
如果不想用@Component,那要确保切面类不会被组件扫描到:
- 把
PreProcessLogs放到组件扫描范围外的包 - 或者在
@ComponentScan里排除这个类 - 保留
LoggingConfig里的@Bean声明,确保只有这一个切面实例
三、其他可能的排查方向
如果上面的方法没解决,再检查这两个点:
- 切入点表达式是否重叠:比如多个切入点表达式匹配了同一个方法,导致多次触发。可以把每个切入点的表达式缩小范围,比如指定具体的包、类或方法名
- @EnableAspectJAutoProxy是否重复配置:如果多个
@Configuration类都加了@EnableAspectJAutoProxy,虽然不会重复注册代理创建器,但如果结合其他配置可能有影响,建议只在一个配置类里加这个注解
内容的提问来源于stack exchange,提问作者Naz Haque




