skip to content

How does the condition attribute on @EventListener work, and how do you filter or chain events?

level: middleimportance: should knowfreq 35%

answer

  1. condition = SpEL boolean
  2. #root.event / #event / #a0 / @bean
  3. true => run, false => skip
  4. non-null return => published as new event
  5. @Order for sync ordering

basics

~10 s

@EventListener(condition = "...SpEL...") evaluates a SpEL expression against the event; the listener runs only if it returns true. You reference the event via #root.event or its payload fields via #propertyName / the special #root.args.

solid answer

~40 s

@EventListener accepts a condition attribute holding a SpEL boolean expression evaluated before invocation; the listener fires only when it evaluates true. Inside the SpEL you can reference the event object as #root.event (or #event), its payload, method arguments as #root.args / #a0, and bean references via @beanName. A common pattern is condition = "#event.premium" or "#order.total > 100". This does server-side filtering so listeners only handle relevant events. Separately, a listener may return a value — if non-null, Spring publishes it as a new event, letting you chain reactions (return a follow-up event, or a collection/array to publish several). Returning null/void publishes nothing. Combine condition for selectivity and @Order for deterministic sync ordering.

code

java · 19 lines
java
record OrderPlaced(long id, int total, boolean premium) {}
record ApprovalRequested(long orderId) {}

@Component
class OrderFlow {

    // Only fires for premium orders over 100 (SpEL guard)
    @EventListener(condition = "#event.premium and #event.total > 100")
    @Order(10)
    ApprovalRequested onBigPremium(OrderPlaced event) {
        // Non-null return is re-published as a NEW event automatically
        return new ApprovalRequested(event.id());
    }

    @EventListener
    void onApproval(ApprovalRequested event) {
        // reacts to the chained event
    }
}

go deeper

for a junior

Know condition is a SpEL string that gates whether the listener runs.

for a middle

Show real SpEL referencing payload fields and know return-value chaining.

for a senior

Combine condition with @Order and warn about cascade/loop risks and startup-vs-runtime SpEL errors.

for a principal

Weigh declarative filtering vs. explicit code and design against event cycles in chained flows.

## The condition attribute `@EventListener(condition = "<SpEL>")` guards invocation. Before calling the listener, Spring evaluates the Spring Expression Language (SpEL) string; the method runs **only if the result is true** (a `Boolean`/`boolean`). If false, the listener is skipped entirely. ### What you can reference in the SpEL Within the condition, the evaluation root exposes: - **The event / payload:** `#root.event` (the raw event) and the payload's properties directly, e.g. `#event.premium`. For payload events you commonly write `#root.event.someField` or a named reference. - **Method arguments:** `#root.args` (array), `#a0`/`#p0` (first arg), or by parameter name `#myParam` (needs `-parameters` compilation or debug info). - **Beans:** `@myBean.someMethod()` to consult other beans. ```java @EventListener(condition = "#event.total > 100") void onLargeOrder(OrderPlaced event) { ... } ``` Only the payload's public getters/fields are reachable, following normal SpEL property rules. ## Why filter here vs. inside the method `condition` keeps the listener declarative and avoids running (and possibly logging/tracing) the body for irrelevant events. It's most useful when many events of one type flow but a listener cares about a slice. ## Returning events to chain An `@EventListener` method may **return a value**. If the return is non-null, Spring treats it as a **new event and publishes it automatically**: ```java @EventListener ApprovalRequested on(OrderPlaced e) { return e.total() > 1000 ? new ApprovalRequested(e.id()) : null; // null => nothing published } ``` - Returning an array or `Collection` publishes each element as a separate event. - Returning `void` or `null` publishes nothing. - This enables small event pipelines without injecting the publisher. ## Ordering When several listeners handle the same event synchronously, use `@Order(n)` (lower runs first) or implement `Ordered`. Without it, order is unspecified. `condition` and `@Order` combine: condition decides *whether*, order decides *when*. ## Gotchas - A malformed SpEL throws at evaluation time (per publish), not at startup — test your expressions. - Parameter-name references need parameter names retained at compile time; otherwise use `#a0`. - `condition` returning a non-Boolean is an error; keep it a boolean expression. - Returned-event chaining is synchronous and can create surprising cascades or loops — avoid event A → B → A cycles. - With async listeners the returned-event publication still happens, but ordering/threading caveats apply.

  • What happens if an @EventListener returns a non-null object?
    Spring publishes that object as a new event. Returning a Collection/array publishes each element; returning null or void publishes nothing. This lets you chain event reactions without injecting the publisher.
  • How do you reference the event payload inside a condition expression?
    Use SpEL against the root: #root.event or #event for the event, its properties like #event.total, method args via #a0/#p0 or the parameter name, and beans via @beanName.

saying these in an interview costs you the question

  • Thinking a false condition still runs the method
  • Not knowing non-null return values are re-published
  • Assuming SpEL condition errors surface at startup rather than per-publish
  • Creating event cycles via chained returns

context