How do PollerMetadata and @Poller configure a polling consumer, and what is the default-poller mechanism?
answer
- PollerMetadata: trigger, maxMessagesPerPoll, receiveTimeout, taskExecutor, advice, errorHandler
- @Poller inline vs named bean vs default bean
- DEFAULT_POLLER_META_DATA_BEAN_NAME = defaultPollerMetadata
- order: explicit -> default bean -> startup failure
- one-or-the-other, not merged; exactly one default
basics
~20 sPollerMetadata is a bean holding a poller's settings — trigger, maxMessagesPerPoll, receiveTimeout, task executor, transaction/advice, error handler. @Poller is the annotation form on an endpoint. If none is given, Spring uses a bean named the default poller; if that's missing too, startup fails.
solid answer
~40 sA PollingConsumer needs a Poller, described by a PollerMetadata bean: a Trigger (PeriodicTrigger via fixedDelay/fixedRate or a CronTrigger), maxMessagesPerPoll (messages drained per poll cycle), receiveTimeout (how long receive() blocks), an optional taskExecutor to run polls on a pool, and a transactionManager/adviceChain plus errorHandler. You attach it three ways: the @Poller attribute on @ServiceActivator, an XML <poller>, or by defining a single default PollerMetadata bean named PollerMetadata.DEFAULT_POLLER_META_DATA_BEAN_NAME ('...defaultPollerMetadata') which all poller-less endpoints inherit. Resolution order per endpoint: explicit poller first, else the default poller bean, else the context fails to start with 'no poller has been defined ... and no default poller is available'. Note @Poller and the default bean are mutually exclusive per endpoint — you get one or the other, not merged.
code
java · 18 lines@Configuration
public class Pollers {
// Default poller: every poller-less endpoint inherits this.
@Bean(name = PollerMetadata.DEFAULT_POLLER_META_DATA_BEAN_NAME)
public PollerMetadata defaultPoller() {
PollerMetadata pm = new PollerMetadata();
pm.setTrigger(new PeriodicTrigger(Duration.ofMillis(500))); // fixedDelay
pm.setMaxMessagesPerPoll(5);
pm.setReceiveTimeout(1000);
return pm;
}
// This endpoint overrides the default with an inline @Poller.
@ServiceActivator(inputChannel = "queued",
poller = @Poller(cron = "0 0 * * * *", maxMessagesPerPoll = "50"))
public void hourlyBatch(Job job) { /* ... */ }
}go deeper
Know a poller has a schedule (fixedDelay/cron) and that pollable channels need one.
List the main PollerMetadata knobs and the three ways to attach a poller.
Explain resolution order, the default poller bean name, transactional polling via advice, and maxMessagesPerPoll trade-offs.
Design poller topology: dedicated executors, batch sizing, cron windows, transactional at-least-once, scheduler thread contention.
## PollerMetadata — the poller's settings object `PollerMetadata` is a plain configuration holder describing **how** a `PollingConsumer` (or `SourcePollingChannelAdapter`) polls: - **`trigger`** — a `Trigger` deciding *when* to poll. Common: `PeriodicTrigger` (configured by `fixedDelay` or `fixedRate`) or `CronTrigger` (`cron`). `fixedDelay` waits N ms **after** the previous poll finishes; `fixedRate` fires every N ms **regardless** of duration. - **`maxMessagesPerPoll`** — how many messages to receive within one poll cycle. `-1` (`MAX_MESSAGES_UNBOUNDED`) means keep receiving until the channel returns nothing; `1` means one-per-tick. High/unbounded values on a hot channel can monopolise the scheduler thread. - **`receiveTimeout`** — how long `channel.receive(timeout)` blocks waiting for a message before the poll gives up (default 1000 ms). - **`taskExecutor`** — if set, each poll runs on a pooled thread (concurrency); if unset, polls run on the shared `TaskScheduler` thread (serial). - **`adviceChain` / `transactionManager`** — wrap each poll in AOP advice, notably a `TransactionInterceptor` so the receive-and-process is transactional (message rolled back on failure). - **`errorHandler`** — handles exceptions escaping the poll (defaults route to an error channel via `MessagePublishingErrorHandler`). ## Three ways to attach a poller 1. **`@Poller` annotation** — inline on `@ServiceActivator(poller = @Poller(fixedDelay="500", maxMessagesPerPoll="5"))`. You can also reference a named `PollerMetadata` bean via `@Poller("myPoller")`. 2. **XML** — `<int:poller .../>` element (global or endpoint-scoped). 3. **Default poller bean** — define **one** `PollerMetadata` bean named `PollerMetadata.DEFAULT_POLLER_META_DATA_BEAN_NAME` (`"org.springframework.integration.context.defaultPollerMetadata"`; the `@Bean` method can be named `defaultPollerMetadata` or use `Pollers.fixedDelay(...)` from the DSL). Every poller-less endpoint inherits it. ## Resolution order (per endpoint) 1. Explicit poller on the endpoint (`@Poller` / XML) → use it. 2. Otherwise → the default `PollerMetadata` bean, if present. 3. Otherwise → **BeanInitializationException at startup**: *"No poller has been defined for endpoint '…', and no default poller is available within the context."* Important: these are **alternatives, not merged** — an endpoint uses either its own `@Poller` or the default bean, never a blend of both. ## Gotchas - Defining **more than one** default poller bean is an error — there must be exactly one. - `fixedRate` can overlap polls if a poll outlives the interval **only** when a `taskExecutor` is present; without one, polls are serialized on the scheduler thread and effectively can't overlap. - Event-driven consumers (`SubscribableChannel`) **ignore pollers** — a `@Poller` there is meaningless. - `maxMessagesPerPoll = -1` plus a fast producer can starve other scheduled tasks sharing the `TaskScheduler`; give hot pollers their own `taskExecutor` or bound the count. - Transactional polling requires the advice/`transactionManager` on the **poller**, not on the handler — putting `@Transactional` on the service method doesn't make the *receive* transactional. ## When to use Tune `PollerMetadata` when you need throttling (batch size), scheduling (cron), concurrency (executor), or transactional/at-least-once semantics on pull-based sources (JDBC, file, queues).
- How do you make the receive-and-process step of a polling consumer transactional?Add a transactionManager/adviceChain (a TransactionInterceptor) to the poller itself — e.g. @Poller(...) with a transactional advice, or configure PollerMetadata.setAdviceChain. @Transactional on the handler method only wraps the handler, not the receive; the poller advice makes the whole poll a transaction so a failure rolls the message back.
- What is the difference between fixedDelay and fixedRate on a poller's trigger?fixedDelay waits the interval after the previous poll completes (no overlap, gap adapts to work time). fixedRate schedules the next poll at a fixed period from the start regardless of how long the last one took, so polls can bunch up if work is slow and a taskExecutor allows concurrency.
saying these in an interview costs you the question
- Thinking @Poller and the default poller bean are merged together
- Believing @Transactional on the service method makes polling transactional
- Assuming a missing poller just disables polling instead of failing startup
- Putting a @Poller on an event-driven (subscribable-channel) endpoint expecting it to matter