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?
answer
- Around-pre → Before → body → AfterReturning/AfterThrowing → After → Around-post
- @After always; AfterReturning success-only
- AfterReturning & AfterThrowing mutually exclusive
- Lower @Order = outer/higher precedence
- 5.2.7 aligned same-aspect after ordering
basics
~10 sAround-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.
solid answer
~40 sFor one aspect around one method the sequence is: @Around code before proceed(), then @Before, then the target executes. On normal return: @AfterReturning runs, then @After (finally-style), then @Around resumes after proceed(). On a thrown exception: @AfterThrowing runs, then @After, and the exception propagates out through @Around (which sees it at proceed()). So @After always runs; @AfterReturning and @AfterThrowing are mutually exclusive per invocation. Across multiple aspects, ordering follows @Order / Ordered — lower value = higher priority = outermost on the 'before' side and, symmetrically, outermost/last on the 'after' side. Note the historical Spring 5.2.7+ fix that made same-aspect after-advice ordering consistent (afterReturning/afterThrowing then after, matching AspectJ) — worth knowing if asked about legacy behavior.
code
java · 27 lines@Aspect
@Component
public class LifecycleAspect {
private static final Logger log = LoggerFactory.getLogger(LifecycleAspect.class);
@Pointcut("execution(* com.app.PaymentService.charge(..))")
void charge() {}
@Before("charge()") void before() { log.info("1 before"); }
@AfterReturning("charge()") void afterReturn() { log.info("3a after-returning (success only)"); }
@AfterThrowing("charge()") void afterThrow() { log.info("3b after-throwing (failure only)"); }
@After("charge()") void after() { log.info("4 after (always)"); }
@Around("charge()")
Object around(ProceedingJoinPoint pjp) throws Throwable {
log.info("0 around-before");
try {
Object r = pjp.proceed();
log.info("5 around-after (success)");
return r;
} catch (Throwable t) {
log.info("5 around-catch (failure)");
throw t;
}
}
}
// Success log order: 0,1,(body),3a,4,5go deeper
Knows AfterReturning is success-only and After always runs.
Can lay out the full single-aspect ordering.
Explains @Order precedence and success vs failure branching precisely.
Recalls the 5.2.7 same-aspect fix and designs aspect ordering deliberately.
## Single aspect, single method — the canonical order Think of advice as nested shells around the target: 1. `@Around` — code **before** `proceed()` 2. `@Before` 3. **target method body** 4a. success → `@AfterReturning` 4b. exception → `@AfterThrowing` 5. `@After` (runs on **both** paths — like `finally`) 6. `@Around` — code **after** `proceed()` (only reached on success; on failure the exception unwinds through it, where it can catch/re-throw) So on the **success path**: Around-pre → Before → method → AfterReturning → After → Around-post. On the **failure path**: Around-pre → Before → method(throws) → AfterThrowing → After → exception propagates (Around-post is skipped unless @Around catches it). ## Where @AfterReturning sits `@AfterReturning` is strictly a **success-path, pre-@After** hook. It runs after the method produced a value but before the finally-style `@After`. It is never invoked when the method throws. ## Multiple aspects — @Order / Ordered When several aspects advise the same join point, the framework sorts them by their `org.springframework.core.Ordered` value (or `@Order` annotation): **lower number = higher precedence**. The highest-precedence aspect is **outermost** — its 'before'-style advice runs first and its 'after'-style advice runs last, wrapping the others. Two aspects with the same order have **undefined** relative ordering, which is a real-world flakiness source; always set explicit orders when interactions matter (e.g. security before transaction, transaction before caching). ## Same-aspect ordering history (Spring 5.2.7) Before Spring Framework 5.2.7, advice methods **declared in the same @Aspect class** could run in an order that didn't match AspectJ's precedence. Since 5.2.7 the behavior was aligned so that on the way out, `@AfterReturning`/`@AfterThrowing` run before `@After`, consistent with AspectJ. If an interviewer probes legacy quirks or you support old Spring versions, mention that a single class mixing multiple advice types historically had surprising ordering; splitting advice across ordered aspects avoided it. ## Practical implications - Don't put cleanup that must always run in `@AfterReturning` — it's skipped on exceptions; use `@After`. - Success-only side effects (audit 'completed', metrics increment, cache put) belong in `@AfterReturning` so they don't fire on failure. - If success handling must be able to see and react to the returned value AND you also need guaranteed cleanup, combine `@AfterReturning` (success reaction) with `@After` (cleanup). ## Self-invocation reminder All of this only applies to calls routed through the proxy. Internal `this.method()` calls bypass advice entirely.
- Two aspects both advise the same method and have no @Order. Is the ordering guaranteed?No. With equal precedence the relative order is undefined and can vary. Assign explicit @Order/Ordered values when the interaction matters (e.g. security must wrap transactions).
- You need cleanup that runs even when the method throws — which advice, and why not @AfterReturning?Use @After (finally-style), which runs on both success and exception. @AfterReturning is skipped on any thrown exception, so cleanup placed there would leak on failures.
saying these in an interview costs you the question
- Saying @AfterReturning runs after @After
- Claiming @AfterReturning and @AfterThrowing can both fire in one invocation
- Thinking higher @Order number means higher precedence
- Assuming same-order aspects have deterministic ordering