skip to content

@After (Finally) Advice

@After has finally semantics: it runs on both success and failure, which suits cleanup, but it sees neither the return value nor the exception. Knowing that limitation is what the question is really testing.

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

questions

4

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

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

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

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