Under The Hood
backend springboot Spring Framework 6.x / AspectJ

Spring AOP: Pointcut Expressions & Advice Types

Last updated
Prerequisites:
Spring bean lifecycle and proxies
Understanding of cross-cutting concerns (logging, transactions)
  • spring
  • aop
  • pointcut
  • aspect
  • advice
  • proxy
  • aspectj

Read at your depth

The practical view

Spring AOP lets you add behavior (advice) to methods matching a rule (pointcut) without modifying them. Common uses: logging, transactions, auditing, security. Define an @Aspect class with @Before, @After, @AfterReturning, @AfterThrowing, or @Around advice. Pointcut expressions select methods: execution(* com.example.service.*.*(..)), within, @annotation, @within, bean. Example: @Around("@annotation(LogExecution)") around any method annotated @LogExecution. Spring AOP uses proxies (JDK dynamic for interfaces, CGLIB for classes), so it only intercepts calls through the proxy — self-invocation is not intercepted.

The same idea in other frameworks

react equivalent
N/A — server-side Spring concern.

Legacy vs modern

Manual logging in every method vs @Around aspect

Copy-pasting timing/logging code into every method is repetitive and drifts; an aspect applies it uniformly to every matched method.

before → after
Manual timing in each method
public Order placeOrder(...) {
  long start = System.nanoTime(); // ❌ OLD: repeated in every method
  try { ... } finally {
    log.info("placeOrder took {}ms", (System.nanoTime() - start) / 1_000_000);
  }
}
@Around timing aspect
@Aspect
@Component
public class TimingAspect {
  @Around("execution(* com.example.service.*.*(..))") // ✅ NEW
  public Object time(ProceedingJoinPoint pjp) throws Throwable {
    long start = System.nanoTime();
    try { return pjp.proceed(); }
    finally { log.info("{} took {}ms", pjp.getSignature().getName(), (System.nanoTime() - start) / 1_000_000); }
  }
}

Interview gotchas

Context

This is the defining Spring AOP gotcha — interviewers want the proxy model explanation and the concrete limitations (public methods, self-calls, final classes) that come with proxy-based AOP.

The mechanical answer

Spring AOP works by wrapping the target bean in a proxy; only method calls that go THROUGH the proxy are intercepted. When a method on the same bean calls another advised method directly (this.someMethod()), the call executes on the raw target object — the proxy is bypassed, so the advice (and @Transactional/@Async) does not run. Additional limitations of proxy-based AOP: only PUBLIC method invocations through the proxy are advised (private/protected calls and calls on the raw object are not); CGLIB cannot proxy final classes or final methods; JDK dynamic proxies only work for interface-declared methods. Workarounds: inject the proxy into itself (self-injection), move the advised method to another bean, or use AspectJ compile-time/load-time weaving for full interception.

Trap

The naive answer is 'Spring AOP intercepts every method call'. It intercepts proxy-mediated public calls only. Another trap: thinking @Transactional inside the same bean is exempt — it's exactly the self-invocation case that silently skips the transaction. Candidates who explain the proxy boundary and the self-injection fix show real Spring experience.

Under The Hood — a multi-depth technical interview hub.

Third-party licenses Press ⌘ K to search.