How do you control ordering between multiple aspects, and how does that differ from ordering within one aspect? When would you split advice across aspects for this reason?
answer
- @Order / Ordered on the aspect CLASS
- lower value = higher precedence = outermost
- within-aspect = fixed by type, same-type undefined
- split concerns into ordered aspects
- @Transactional = LOWEST_PRECEDENCE by default
basics
~20 sOrder whole aspects with @Order or by implementing Ordered — lower value = higher precedence, runs first on entry. This is the ONLY way to get deterministic ordering, because two same-type advices inside one aspect are unordered. So split advice that must be ordered into separate, @Order-ed aspects.
solid answer
~50 sOrdering **between aspects** is controlled with `@org.springframework.core.annotation.Order` on the aspect class, or by implementing `org.springframework.core.Ordered`. **Lower order value = higher precedence**, and the highest-precedence aspect's 'before' advice runs first while its 'after' advice runs last (it wraps the others). AspectJ's `@DeclarePrecedence` is an alternative. This is fundamentally different from **within-aspect** ordering, which is fixed by advice type and *undefined* for two same-type advices (Spring can't read source order from javac bytecode, and `@Order` on a method is ignored). So the standard design pattern when you need a guaranteed sequence — e.g. security check must run before transaction management must run before audit logging — is to put each concern in its **own aspect** and assign explicit `@Order` values. `@Transactional` internally sits at `Ordered.LOWEST_PRECEDENCE`, so custom aspects often need a lower value to run outside the transaction.
code
java · 21 lines@Aspect
@Component
@Order(1) // highest precedence: outermost wrapper
public class SecurityAspect {
@Before("execution(* svc..*(..))")
public void checkAccess() { /* runs FIRST on entry */ }
}
@Aspect
@Component
@Order(2) // runs inside SecurityAspect
public class AuditAspect {
@After("execution(* svc..*(..))")
public void audit() { /* runs later on exit */ }
}
// Rationale: these two concerns needed a guaranteed order.
// Two advice methods in ONE aspect could NOT be ordered
// deterministically, so each concern is its own @Order-ed aspect.
// To wrap Spring's @Transactional advice, use an order value
// lower than Ordered.LOWEST_PRECEDENCE (its default).go deeper
Know @Order exists to order aspects; details not expected.
Know @Order/Ordered on the class and that lower = higher precedence.
Explain outer-wraps-inner semantics and that within-aspect same-type order is undefined, motivating splitting.
Design ordered aspect chains, reason about @Transactional's LOWEST_PRECEDENCE interplay, @DeclarePrecedence, and cohesion trade-offs of one-concern-per-aspect.
**Two independent ordering layers.** 1. **Across aspects** — configurable and deterministic. 2. **Within one aspect** — fixed by advice type, and *undefined* between two advices of the same type. **Across-aspect ordering mechanism.** When advice from *different* aspects applies to the same join point, Spring orders the aspects by precedence: - Annotate the aspect class with `@Order(n)`, or - Implement `org.springframework.core.Ordered` and return a value from `getOrder()`. **Semantics of the value:** **lower value = higher precedence.** The highest-precedence aspect is the *outermost* — its `@Before`/around-before runs **first** on the way in, and its after/around-after runs **last** on the way out. Think of aspects as nested wrappers: lowest order number on the outside. `Ordered.HIGHEST_PRECEDENCE` = `Integer.MIN_VALUE`, `Ordered.LOWEST_PRECEDENCE` = `Integer.MAX_VALUE`. **AspectJ alternative.** `@DeclarePrecedence("AspectA, AspectB, ...")` declares an explicit precedence chain and can be used instead of/along with `@Order`. **Contrast with within-aspect ordering.** Inside one aspect, ordering is by advice **type** (`@Around` > `@Before` > `@After` > `@AfterReturning` > `@AfterThrowing`, since 5.2.7), and two advices of the **same type** are **undefined** because declaration order isn't recoverable from javac-compiled bytecode. Critically, **`@Order` on an advice method does nothing** — it only orders aspects. So there is no in-aspect knob for same-type sequencing. **The design consequence — split to order.** Because you cannot deterministically order two same-type advices within one aspect, the idiomatic solution when order matters is to **refactor each concern into its own `@Aspect` and assign `@Order` values**. Classic ordered chain: security/authorization (outermost) -> transaction management -> caching -> audit/metrics (innermost), each its own aspect with increasing order numbers. This also improves cohesion — one aspect = one concern. **Interaction with framework aspects.** Spring's `@Transactional` support is itself an ordered aspect at `Ordered.LOWEST_PRECEDENCE` by default (configurable via `@EnableTransactionManagement(order=...)`). If your custom aspect must run **outside** the transaction (e.g. open/close a resource around the tx, or run before the tx begins), give it a **lower order value** so it has higher precedence and wraps the transactional advice. Getting this wrong is a common production bug: an aspect meant to run before the transaction ends up nested inside it. **Edge cases / gotchas.** - Aspects with **no** `@Order`/`Ordered` have effectively undefined relative order — don't rely on registration/scan order. - `@Order` value comparison is a total order; ties fall back to undefined ordering. - Ordering applies at a **join point** — two aspects that don't both match a given join point simply don't interact there. - Mixing `@DeclarePrecedence` and `@Order` should be done carefully to avoid contradictory declarations. **Interview framing.** A principal-level answer connects the *mechanism* (@Order/Ordered, lower=higher, outer wraps) to the *design decision* (split concerns into separately-ordered aspects precisely because intra-aspect same-type ordering is unavailable) and to *real framework interplay* (@Transactional's LOWEST_PRECEDENCE default).
- An aspect must run before the database transaction opens. What order value does it need relative to @Transactional?Spring's transaction advice defaults to Ordered.LOWEST_PRECEDENCE. Your aspect needs a lower order value (higher precedence) so it becomes the outer wrapper and runs before the transaction begins / after it commits.
- Does lower @Order mean it runs first or last?Lower value = higher precedence = outermost. Its before/entry advice runs first; its after/exit advice runs last. It wraps the lower-precedence aspects.
- Why is splitting into separate aspects the recommended way to order same-type advice?Because within one aspect two same-type advices have undefined order and @Order on a method is ignored. Only aspect-level @Order/Ordered gives determinism, so each orderable concern must be its own aspect.
saying these in an interview costs you the question
- Thinking @Order on an advice method orders advice within an aspect
- Believing higher @Order value means higher precedence
- Assuming aspects without @Order have a stable, predictable order
- Not knowing @Transactional advice defaults to LOWEST_PRECEDENCE, leading to wrong wrapping