Why Does My Overridden Spring Aspect Log Twice? Debugging and Fixes
This article explains why a Spring AOP aspect that overrides a parent method logs twice, walks through the debugging process that reveals duplicate advisor creation, and presents two solutions—including a pointcut tweak and upgrading to Spring 6.1.8—to eliminate the redundant logs.
1. Problem Reproduction
To improve code reuse and maintainability, a generic abstract aspect class CommonAspect was created to encapsulate common logic such as logging, performance monitoring, and exception handling. Business-specific aspects inherit from this class.
<code>public abstract class CommonAspect {
@Pointcut("execution(public * com.pack..*.*(..))")
private void commonPointcut() {}
@Before("bean(*Service)")
protected void beforeLog(JoinPoint jp) {
System.out.println("通用日志记录...");
}
@Around("@annotation(monitor)")
protected Object monitorRun(ProceedingJoinPoint pjp, Monitor monitor) throws Throwable {
Object ret = null;
// TODO
ret = pjp.proceed();
// TODO
return ret;
}
// other
}</code>A concrete aspect overrides the logging method:
<code>@Component
@Aspect
public class LogAspect extends CommonAspect {
@Override
public void beforeLog(JoinPoint jp) {
System.out.println("重写日志记录功能");
}
}</code>Running the application prints the overridden log message twice:
<code>重写日志记录功能
重写日志记录功能
查询Person对象</code>2. Analysis
During container startup, Spring parses the @Aspect and retrieves all methods from the aspect class. It finds two methods: the one defined in the parent class and the overridden one in the subclass.
The getAdvisorMethods method returns three methods, two from the parent and one overridden method. Spring then creates an Advisor for each, which explains the duplicate execution because Spring does not check whether the advice method overrides a parent method.
These advisors are later turned into Advice (MethodInterceptor) objects that the proxy invokes.
2. Solution
2.1 Solution 1 – Adjust Pointcut
Add a pointcut to the overridden method that does not match any join point, preventing Spring from creating an advisor for it.
<code>@Before("execution(public * xxxooo())")
@Override
public void beforeLog(JoinPoint jp) {
System.out.println("重写日志记录功能");
}</code>After this change the output is:
<code>重写日志记录功能
查询Person对象</code>Only a single log entry appears.
2.2 Solution 2 – Upgrade Spring
Upgrading to Spring 6.1.8 resolves the issue. The core change is in ReflectiveAspectJAdvisorFactory#getAdvisors , where a check is added to compare the method with the most specific method in the aspect class, filtering out inherited methods.
<code>public class ReflectiveAspectJAdvisorFactory {
public List<Advisor> getAdvisors(...) {
List<Advisor> advisors = new ArrayList<>();
for (Method method : getAdvisorMethods(aspectClass)) {
// Added check: compare with most specific method
if (method.equals(ClassUtils.getMostSpecificMethod(method, aspectClass))) {
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
}
}
}</code>In versions lower than 6.1.8 this check is absent, so duplicate advisors are created.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.