Within a single @Aspect, in what order do @After, @AfterReturning, and @AfterThrowing run, and how has that changed?
answer
- 5.2.7 aligned within-aspect order to AspectJ
- Precedence: Around>Before>After>AfterReturning>AfterThrowing
- Exit: returning/throwing first, @After last
- Same-type same-join-point = undefined
- Cross-aspect: @Order / Ordered, lower=outer
basics
~10 sSince 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.
solid answer
~40 sSpring assigns advice within a single @Aspect a fixed precedence: @Around and @Before highest, then @After, then @AfterReturning/@AfterThrowing. Higher precedence means outermost — it runs first entering and last leaving. So on exit @AfterReturning or @AfterThrowing runs first and @After runs last, giving true finally-last behavior aligned with AspectJ. This was standardized in Spring Framework 5.2.7; earlier versions had inconsistent, sometimes reversed ordering where @After ran before the returning/throwing advice — a well-known upgrade gotcha. When two advice methods of the same type in the same aspect share a join point, the order is undefined; combine them or split aspects. Ordering between different aspects is separate: implement Ordered or annotate the aspect with @Order — lower value = higher precedence, and the same outer-first-in/last-out nesting applies.
code
java · 18 lines// Spring 5.2.7+ within ONE aspect, on a normal return, execution order is:
// @Around (before proceed) -> @Before -> METHOD -> @AfterReturning -> @After -> @Around (after proceed)
@Aspect
@Component
@Order(0) // cross-aspect precedence; lower value = outermost
public class TxLikeAspect {
@Around("execution(* com.acme.Svc.*(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
try { return pjp.proceed(); } finally { /* outermost finally */ }
}
@AfterReturning(pointcut = "execution(* com.acme.Svc.*(..))", returning = "r")
public void afterReturning(Object r) { /* runs before @After */ }
@After("execution(* com.acme.Svc.*(..))")
public void after() { /* finally-last: runs after @AfterReturning */ }
}go deeper
Just know @After runs after the method; ordering nuance is beyond scope.
Know cross-aspect ordering uses @Order/Ordered (lower = outer).
Explain the within-aspect precedence and that @After is finally-last on 5.2.7+.
Discuss the 5.2.7 alignment with AspectJ, the pre-5.2.7 gotcha, undefined same-type ordering, and preferring a single @Around when sequence is load-bearing.
### Two independent ordering questions 1. **Between different aspects** hitting the same join point. 2. **Between advice methods inside one @Aspect**. They are governed by different rules; conflating them is a common mistake. ### Between different aspects Each aspect has a precedence. Set it by implementing `org.springframework.core.Ordered` or annotating the aspect class with `@Order`. **Lower value = higher precedence = outermost.** The outermost aspect's `@Before` runs first and its 'after' advice runs last — classic nesting, like Russian dolls. If you do not set an order, the relative order of two independent aspects is **undefined**. ### Inside one @Aspect (the heart of this question) Since **Spring Framework 5.2.7**, advice types in the *same* aspect are ordered by a fixed precedence, from highest to lowest: `@Around` > `@Before` > `@After` > `@AfterReturning` > `@AfterThrowing`. Apply the outer-first-in / outer-last-out nesting to that list: - **Entering**: `@Around` (before `proceed()`), then `@Before`. - **Leaving**: lowest precedence runs first, highest last. So `@AfterThrowing`/`@AfterReturning` (lowest) run **first**, then `@After`, then the code after `proceed()` in `@Around`. Concretely, on a normal return: `@AfterReturning` runs, then `@After`. On an exception: `@AfterThrowing` runs, then `@After`, then the exception propagates. This makes `@After` genuinely *finally-last* — it always closes out after the outcome-specific advice — matching AspectJ semantics. ### The historical change (why interviewers ask) Before 5.2.7, Spring's within-aspect ordering was not aligned with AspectJ and was effectively based on other heuristics; a frequently reported symptom was `@After` executing **before** `@AfterReturning`, the opposite of finally intuition. Teams that relied on ordering (e.g. `@AfterReturning` commits/audits the result, then `@After` clears context) could see behavior change on upgrade. The 5.2.7 release deliberately standardized the order to the precedence list above. On any modern Spring Boot (2.3.1+/Spring 5.2.7+) you get the finally-last behavior. ### Same-type collisions If two `@After` methods (or two `@Before`, etc.) in the **same** aspect match the **same** join point, their relative order is **undefined** and `@Order` on methods does not help. The reference guidance is to collapse them into one advice method or move them into separate aspects ordered with `@Order`. ### Design implications - Don't build correctness on within-aspect ordering across advice **types** unless you are on 5.2.7+ and have verified the precedence list; even then, prefer a single `@Around` when the sequence is load-bearing, because it makes the order explicit in code. - For cross-aspect sequencing (security before tx before audit), always assign `@Order` explicitly rather than relying on discovery order. - Remember `@After` runs after `@AfterReturning` — if `@AfterReturning` mutates shared state the `@After` cleanup depends on, the direction is now well-defined but was not pre-5.2.7. ### Quick reference Entering: Around(pre) -> Before -> [method] . Leaving: AfterReturning|AfterThrowing -> After -> Around(post).
- Two @After methods in the same aspect match the same method. Can you force one to run before the other?Not reliably. Same-type advice at the same join point within one aspect has undefined order, and @Order on methods is ignored. Merge them into one advice method, or split into two aspects ordered with @Order/Ordered.
- How do you make aspect A's advice always wrap aspect B's at the same join point?Give A a lower @Order (or Ordered value) than B. Lower value = higher precedence = outermost, so A's @Before runs first and its after-advice runs last, nesting B inside it.
- On Spring 5.2.7+, on a normal return does @After or @AfterReturning run first?@AfterReturning runs first, then @After (finally-last). Before 5.2.7 the order could be reversed, which was a known upgrade gotcha.
saying these in an interview costs you the question
- Claiming @After always runs before @AfterReturning on modern Spring
- Using @Order on advice methods to sequence same-type advice in one aspect
- Assuming two unordered aspects have a defined, stable execution order
- Thinking within-aspect ordering never changed across Spring versions