skip to content

Advice Types & Join Points

The five advice types — before, after returning, after throwing, after, and around — and what each one can see or change at the join point. Expect a question that forces you to pick the weakest advice that still does the job.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

explore

questions

29

What is @After advice in Spring AOP and when does it run?

level: juniorimportance: must knowfreq 58%

answer

  1. Runs like finally — success or exception
  2. No returning / no throwing binding
  3. JoinPoint yes, return value no
  4. Cleanup / resource release
  5. Exception still propagates after it runs

basics

~20 s

@After is advice that runs after a matched method finishes — whether it returned normally or threw an exception. It behaves like a finally block, so it is used for cleanup. It cannot see the return value or the exception.

solid answer

~40 s

@After (the 'after finally' advice) is one of Spring AOP's five advice types. You put @After on an aspect method with a pointcut, e.g. @After("execution(* com.acme.service..*(..))"). Spring wraps the target bean in a proxy; when a matched method completes, the @After method always runs — on both the normal-return path and the exception path — mirroring a try/finally block. Its typical uses are cleanup and resource release: unlocking, closing handles, clearing a ThreadLocal or MDC context, decrementing a counter. It can declare a JoinPoint parameter to inspect the signature and arguments, but unlike @AfterReturning it has no 'returning' binding and unlike @AfterThrowing it has no 'throwing' binding — so it cannot access the returned value or the thrown exception. If the method threw, @After runs and then the exception keeps propagating.

code

java · 12 lines
java
@Aspect
@Component
public class CleanupAspect {

    @After("execution(* com.acme.service.OrderService.*(..))")
    public void afterAnyServiceCall(JoinPoint joinPoint) {
        // Always runs: normal return OR exception thrown.
        MDC.clear(); // e.g. clear per-request logging context
        System.out.println("Finished: " + joinPoint.getSignature().toShortString());
        // Cannot read the return value or the exception here.
    }
}

go deeper

for a junior

Must know: @After = runs after, no matter what, like finally; used for cleanup.

for a middle

Should also state it cannot bind the return value or exception, and that it does not suppress exceptions.

for a senior

Frame it against the other four advice types and note proxy/self-invocation limits.

for a principal

Discuss when finally-style cleanup belongs in an aspect vs. the method itself, and idempotency of cleanup on the throwing path.

### What AOP and advice are Aspect-Oriented Programming (AOP) lets you factor out cross-cutting concerns (logging, security, cleanup) into an **aspect** instead of scattering them through business code. An aspect contains **advice** — code that runs at chosen points in program execution. The chosen points are selected by a **pointcut** (an expression like `execution(* com.acme..*(..))`). A single point where advice can run (here, a method call) is a **join point**. Spring implements this with **proxies**: when a bean is matched by a pointcut, Spring replaces it with a proxy (a JDK dynamic proxy if the bean implements an interface, otherwise a CGLIB subclass). Calls go through the proxy, which invokes the advice around the real method. ### The five advice types - `@Before` — runs before the method. - `@AfterReturning` — runs only after a **normal** return; can bind the return value via `returning`. - `@AfterThrowing` — runs only if the method **throws**; can bind the exception via `throwing`. - `@After` — runs **after the method regardless of outcome** (normal or exception). This is the topic here. - `@Around` — wraps the method; must call `ProceedingJoinPoint.proceed()` and can do work before and after, including its own try/finally. ### @After semantics (finally) `@After` is called the *after (finally) advice* in the Spring reference. It always executes once the join point completes, in exactly the situations a Java `finally` block would run. So for: ``` try { result = method(); } finally { /* @After runs here */ } ``` it runs whether `method()` returns or throws. **What it can and cannot access:** - It **may** declare a `JoinPoint` as its first parameter to read the method signature (`joinPoint.getSignature()`) and arguments (`joinPoint.getArgs()`). - It **cannot** access the return value — there is no `returning` attribute on `@After`. - It **cannot** access the exception — there is no `throwing` attribute on `@After`. If you need either of those, use `@AfterReturning`/`@AfterThrowing`, or use `@Around` with a `try/finally`. ### Exception behavior `@After` does **not** swallow or suppress the exception. On the throwing path Spring runs `@After` and then re-propagates the original exception to the caller. `@After` running is not a `catch`. ### Enabling it You need `spring-aop` (and normally `aspectjweaver` for the annotation pointcut language), the class annotated with `@Aspect` and registered as a Spring bean (e.g. `@Component`), and AspectJ auto-proxying enabled via `@EnableAspectJAutoProxy` (Spring Boot autoconfigures this when AspectJ is on the classpath). ### Gotchas - **Proxy self-invocation**: if the target calls its own `@After`-matched method internally (`this.foo()`), the call does not go through the proxy, so no advice fires. - **Only proxied beans**: advice applies to Spring-managed beans reached through the proxy, not to `new`-ed objects. - **Ordering vs @AfterReturning/@AfterThrowing** within the same aspect changed in Spring 5.2.7 (covered in the advanced question). ### When to use Reach for `@After` when the cleanup is identical on success and failure and does not need the result/exception — releasing a lock, clearing context, closing something. If the cleanup differs by outcome, or you need the value/exception, prefer the more specific advice or `@Around`.

  • If the advised method throws, does @After stop the exception from reaching the caller?
    No. @After is not a catch block. Spring runs the @After method and then re-propagates the original exception. Only @Around (which can catch inside proceed()) or a real try/catch can suppress it.
  • How would you inspect which method and arguments triggered the @After advice?
    Declare a JoinPoint as the first parameter and call joinPoint.getSignature() and joinPoint.getArgs(). That is the only binding @After supports — there is no returning/throwing attribute.

context

open as a page

What does Spring's @AfterReturning advice do, and when does it run?

level: juniorimportance: must knowfreq 60%

basics

~10 s

@AfterReturning is AOP advice that runs after an advised method finishes successfully (returns normally). It does NOT run if the method throws an exception. It can read the returned value but cannot replace it.

open as a page

What is @AfterThrowing advice in Spring AOP and when does it run?

level: juniorimportance: must knowfreq 65%

basics

~10 s

@AfterThrowing is an aspect advice method that runs only when the matched method (join point) exits by throwing an exception. If the method returns normally, it does not run.

open as a page

What is @Around advice in Spring AOP, and why must it call ProceedingJoinPoint.proceed()?

level: juniorimportance: must knowfreq 78%

basics

~20 s

@Around wraps a method call. It runs code before and after the target method. You must call proceed() to actually run the target method; if you skip it, the target never executes and you return your own value instead.

open as a page

What is @Before advice in Spring AOP and when does it run?

level: juniorimportance: must knowfreq 70%

basics

~10 s

@Before advice is aspect code that runs before a matched method (the join point) executes. It's used for things like logging entry or validating arguments. It runs before, then the real method still runs.

open as a page

What is a JoinPoint in Spring AOP advice, and what information does it expose?

level: juniorimportance: must knowfreq 70%

basics

~10 s

JoinPoint is an object Spring passes to advice methods representing the intercepted method call. It exposes getArgs() (the call's arguments), getSignature() (method name/details), getTarget() (the real bean), and getThis() (the proxy).

open as a page

How does @After differ from @AfterReturning and @AfterThrowing?

level: middleimportance: must knowfreq 52%

basics

~20 s

@AfterReturning runs only on a normal return and can bind the return value. @AfterThrowing runs only when an exception is thrown and can bind that exception. @After runs in both cases (finally) but can bind neither the value nor the exception.

open as a page

How do you bind and use a method's return value inside @AfterReturning, and what are the naming rules?

level: middleimportance: must knowfreq 55%

basics

~10 s

Add returning="paramName" to @AfterReturning and declare a matching parameter of that name in the advice method. The parameter receives the returned value. The name must match the parameter, not the pointcut expression.

open as a page

How does ProceedingJoinPoint differ from JoinPoint, and where can you use it?

level: middleimportance: must knowfreq 75%

basics

~20 s

ProceedingJoinPoint extends JoinPoint and adds proceed(), which actually invokes the advised method (or the next advice in the chain). It is valid only inside @Around advice. Other advice types get the plain JoinPoint, which cannot proceed.

open as a page

Does @AfterThrowing swallow or handle the exception? How would you actually suppress or translate it?

level: seniorimportance: must knowfreq 60%

basics

~20 s

No. @AfterThrowing only observes the exception, then the original exception keeps propagating to the caller. To suppress, replace, or recover, use @Around: catch inside proceed() and either return a fallback or throw a different exception.

open as a page

Why might @Before advice silently not fire, and how do proxy mechanics explain it?

level: seniorimportance: must knowfreq 50%

basics

~20 s

Spring AOP is proxy-based, so @Before only fires when the method is called through the proxy from another bean. Self-invocation (this.method()), private/final methods, non-bean calls, or missing @EnableAspectJAutoProxy all cause it to silently not run.

open as a page

How does the throwing attribute work, and how do you filter @AfterThrowing to a specific exception type?

level: middleimportance: should knowfreq 55%

basics

~20 s

The throwing attribute names the advice method parameter that receives the thrown exception. Declaring that parameter as a specific type (e.g. DataAccessException) makes the advice fire only when the thrown exception is that type or a subtype.

open as a page

How do you modify the arguments passed to the target method from an @Around advice, and what are the rules of proceed(Object[])?

level: middleimportance: should knowfreq 55%

basics

~10 s

Call the overloaded proceed(Object[] args) instead of proceed(). Get the current args with pjp.getArgs(), change them in a new array, and pass that array. The array length and types must match the method's parameters.

open as a page

What is the required method signature of an @Around advice, and how does its return type relate to the target method's return type (including void and primitives)?

level: middleimportance: should knowfreq 44%

basics

~20 s

The first parameter must be ProceedingJoinPoint and the method should declare throws Throwable. Return type is normally Object. proceed() returns the target's result as Object; for void targets it returns null, and you still return it.

open as a page

How do you access the method arguments and signature inside @Before advice, and can you modify them?

level: middleimportance: should knowfreq 55%

basics

~10 s

Declare a JoinPoint parameter first. Use jp.getArgs() for arguments and jp.getSignature() for the method name/type. You can read them, but mutating the array does not change what the target actually receives.

open as a page

Give a real use case for @After advice and explain why @After (not @Around) fits it.

level: seniorimportance: should knowfreq 34%

basics

~20 s

Use @After to release a resource acquired for the call — clear a ThreadLocal/MDC context, unlock a lock, or decrement a gauge — because it must happen on success and failure alike and does not need the result or exception. @After is simpler than @Around for that.

open as a page

Why can't @AfterReturning modify the value returned to the caller, and when should you reach for @Around instead?

level: seniorimportance: should knowfreq 45%

basics

~20 s

@AfterReturning is an observer: Spring gives it the return value but provides no way to substitute a different one — its own return type is ignored by the framework. To transform or replace the result you need @Around, which controls what proceed() returns.

open as a page

In what order do @Before, @After, @AfterReturning, @AfterThrowing, and @Around fire around a single method, and how does @AfterReturning fit on the success vs failure paths?

level: seniorimportance: should knowfreq 40%

basics

~10 s

Around-before → Before → method → (on success) AfterReturning, (on failure) AfterThrowing → After (always) → Around-after. @AfterReturning fires only on the success path, before @After, and never on the exception path.

open as a page

How does @Around advice handle exceptions and short-circuiting, and how would you implement retry or caching with proceed()?

level: seniorimportance: should knowfreq 48%

basics

~20 s

proceed() throws Throwable, so you can wrap it in try/catch to retry, translate, suppress, or add context. To short-circuit (e.g. cache hit), skip proceed() and return your own value. To retry, call proceed() again in a loop.

open as a page

For an argument-validation gate, would you use @Before or @Around, and why?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Use @Before for pure validation that either passes or throws — it's simpler and clearly signals 'no invocation control.' Use @Around only when you must skip the call, replace arguments, alter the return value, or handle exceptions.

open as a page

How do you modify method arguments from an @Around advice, and why doesn't editing getArgs() work?

level: seniorimportance: should knowfreq 50%

basics

~20 s

Call proceed(Object[] args) with a new argument array — that array is what the target actually receives. Editing the array from getArgs() alone does not change the real call; you must pass your modified array into proceed(args).

open as a page

What is the difference between JoinPoint.getTarget() and JoinPoint.getThis()?

level: seniorimportance: should knowfreq 45%

basics

~20 s

getTarget() returns the real, un-proxied bean instance. getThis() returns the AOP proxy Spring created around it. They're usually different objects; the proxy is what other beans actually call, and the target holds your business logic.

open as a page

Explain advice ordering around a failure and the proxy limitations that determine whether @AfterThrowing fires at all.

level: principalimportance: should knowfreq 35%

basics

~20 s

On a throw, inner advice unwinds first: @AfterThrowing and @After run as the exception propagates back out through the proxy chain. But @AfterThrowing only fires for calls that go through the proxy — self-invocation, private/final/static methods, and swallowing @Around advice can prevent it.

open as a page

When should you choose @Around over @Before/@After* advice, and what design and correctness risks does @Around introduce?

level: principalimportance: should knowfreq 40%

basics

~20 s

Use @Around only when you must control whether/how the method runs or change its result or exceptions — timing, caching, retry, transactions. For pure side effects (logging, auditing), use the narrower @Before/@After* which can't accidentally drop the return value.

open as a page

When multiple aspects advise the same join point, how is @Before ordering determined, and what happens if a @Before throws?

level: principalimportance: should knowfreq 30%

basics

~20 s

Order is set by @Order / Ordered on the aspects: for before advice, the lowest order value (highest priority) runs first. If a @Before throws, later before advices and the target don't run; the exception propagates like an unwound stack.

open as a page

Explain the semantics of proceed() in the interceptor chain: what it invokes, multiple/zero calls, and the return-value and exception contract.

level: principalimportance: should knowfreq 35%

basics

~20 s

proceed() advances the AOP interceptor chain to the next advice, and eventually the target method. Not calling it skips the target; calling it multiple times re-invokes the chain (retry). It returns the downstream result and propagates any Throwable, so you must return its value.

open as a page

When would you choose @AfterThrowing over @ExceptionHandler / @ControllerAdvice, and vice versa?

level: middleimportance: nice to knowfreq 30%

basics

~10 s

@AfterThrowing is a general AOP hook that observes exceptions from any advised bean method but can't change the outcome. @ExceptionHandler/@ControllerAdvice is Spring MVC's mechanism to catch controller exceptions and turn them into HTTP responses.

open as a page

Within a single @Aspect, in what order do @After, @AfterReturning, and @AfterThrowing run, and how has that changed?

level: principalimportance: nice to knowfreq 18%

basics

~10 s

Since Spring 5.2.7, within one aspect @After runs after @AfterReturning/@AfterThrowing on the way out (finally-last, matching AspectJ). Before 5.2.7 the order was less consistent, often the reverse. Across different aspects, use @Order/Ordered.

open as a page

As a principal engineer, how would you decide between @AfterReturning and @Around for a cross-cutting concern like response auditing or metrics, and what pitfalls would you guard against?

level: principalimportance: nice to knowfreq 25%

basics

~20 s

Prefer the least-powerful advice that expresses intent: @AfterReturning for read-only success reactions (audit, metrics, cache-put). Use @Around only when you must transform the result, time the whole call, short-circuit, or handle exceptions. Guard against proxy self-invocation and non-deterministic aspect ordering.

open as a page