skip to content

Explain what 'the aspect with the lowest order value has the highest precedence' means for the execution of before advice versus after advice across two aspects.

level: middleimportance: must knowfreq 50%

answer

  1. onion rings, target at centre
  2. before = ascending, after = descending
  3. outermost first in, last out
  4. @Around wraps both legs at proceed()

basics

~20 s

The lowest-value aspect is outermost, like the outer layer of an onion. On the way in, its @Before runs first. On the way out, its @After runs last. So before advice runs highest-precedence-first, and after advice runs highest-precedence-last (reversed).

solid answer

~40 s

Precedence maps to nesting depth. The aspect with the lowest @Order value is the outermost wrapper; the highest value is innermost, closest to the target. Entering the call, control flows outer to inner, so @Before advice executes in ascending order of value (highest precedence first). Leaving the call, control unwinds inner to outer, so @After, @AfterReturning, and @AfterThrowing execute in descending order (highest precedence last). @Around advice sees both legs: the outermost @Around wraps everything, and whatever it does before proceed() runs first while what it does after proceed() runs last. This is the classic 'before highest first, after lowest first' rule. A practical consequence: a security aspect you want to gate entry AND clean up last should be given the lowest value so it is truly outermost.

code

java · 18 lines
java
@Aspect @Component @Order(1)
class OuterAspect {
    @Before("execution(* svc.*(..))") void before() { System.out.println("outer before"); }
    @AfterReturning("execution(* svc.*(..))") void after() { System.out.println("outer after"); }
}

@Aspect @Component @Order(2)
class InnerAspect {
    @Before("execution(* svc.*(..))") void before() { System.out.println("inner before"); }
    @AfterReturning("execution(* svc.*(..))") void after() { System.out.println("inner after"); }
}

// Output for one matched call:
// outer before
// inner before
// <target runs>
// inner after
// outer after

go deeper

for a junior

Grasp the 'lowest value runs first' half and the onion image.

for a middle

Must state both legs correctly: before ascending, after descending.

for a senior

Explains @Around's two legs and why symmetric bracketing is desirable.

for a principal

Uses ordering deliberately to guarantee resource lifecycles (open first / close last) across concerns.

## Mental model: nested layers Picture the target method at the centre and each matching aspect as a concentric ring. **Precedence = how far out the ring is.** Lowest `@Order` value → outermost ring; highest value → innermost ring, hugging the target. Execution walks *inward* to reach the target, then unwinds *outward*: ``` Order(1) before -> Order(2) before -> [TARGET] -> Order(2) after -> Order(1) after ``` ## The two rules - **Before-type advice (`@Before`, and the pre-`proceed()` part of `@Around`)** runs from **highest precedence to lowest** — i.e. ascending order value. Outermost first. - **After-type advice (`@After`, `@AfterReturning`, `@AfterThrowing`, and the post-`proceed()` part of `@Around`)** runs from **lowest precedence to highest** — i.e. descending order value. Outermost **last**. So `@Order(1)` runs its `before` first and its `after` last; `@Order(2)` runs its `before` second and its `after` first. This symmetry is exactly what you want: whatever set up context first tears it down last. ## @Around and proceed() An `@Around` method receives a `ProceedingJoinPoint` and must call `pjp.proceed()` to invoke the next layer (another aspect or the target). Code before `proceed()` behaves like `@Before`; code after behaves like `@After`. The outermost `@Around` therefore fully encloses inner aspects and the target. ## Worked example With `SecurityAspect @Order(1)` and `TxAspect @Order(2)` both matching `save()`: 1. Security `@Before` (open security context) 2. Tx `@Before` (begin transaction) 3. `save()` executes 4. Tx `@AfterReturning` (commit) 5. Security `@AfterReturning` (audit success) Security is outermost, so it brackets the transaction entirely. If you swapped the values, the transaction would bracket security — usually wrong. ## Gotchas - The 'first' intuition only holds for the *before* leg; people forget the after leg reverses. - Ordering applies **between** aspects. Ordering **within** one aspect (multiple advice methods in the same class) is a separate, trickier topic. - Equal order values leave the tie unresolved — avoid duplicate values for aspects that interact.

  • For @Around advice, which part behaves like @Before and which like @After?
    Code before pjp.proceed() behaves like @Before (runs on the way in); code after proceed() behaves like @After (runs on the way out). The outermost @Around wraps all inner aspects and the target.
  • If two interacting aspects accidentally share the same @Order value, what happens?
    The tie is unresolved — their relative order becomes undefined again. Give interacting aspects distinct values.

saying these in an interview costs you the question

  • Saying after advice also runs highest-precedence-first (it reverses)
  • Believing highest order value is outermost
  • Thinking @Around only affects the before leg

context