Describe AbstractEndpoint and how endpoint lifecycle connects a MessageHandler to its channel.
answer
- AbstractEndpoint implements SmartLifecycle
- wiring on doStart()/doStop(), not constructor
- EventDrivenConsumer subscribes; PollingConsumer schedules
- autoStartup + phase = ordering; runtime pause/resume
- manage the endpoint bean (Control Bus), not the handler
basics
~20 sAbstractEndpoint is the base class for consumers; it implements Spring's SmartLifecycle. On start() it wires the handler to the channel (an EventDrivenConsumer subscribes; a PollingConsumer schedules polling). On stop() it unsubscribes or cancels the poll. autoStartup and phase control when it starts.
solid answer
~40 sAbstractEndpoint is the common superclass of EventDrivenConsumer, PollingConsumer and SourcePollingChannelAdapter. It implements SmartLifecycle, so the ApplicationContext drives it through start()/stop() with isAutoStartup() and getPhase() controlling ordering. The wiring between handler and channel happens in the lifecycle callbacks, not at construction: doStart() for an EventDrivenConsumer calls channel.subscribe(handler); for a PollingConsumer it schedules a polling task on the TaskScheduler using the poller's Trigger. doStop() unsubscribes the handler or cancels the scheduled poll. Because start ordering follows phase and it's a SmartLifecycle, channels and dependent infrastructure can be started/stopped in a controlled sequence — and you can stop/start individual endpoints at runtime (e.g., to pause a flow) via their bean or a Control Bus, without tearing down the context.
code
java · 15 lines// Endpoints are SmartLifecycle beans: wiring happens on start(), and you
// can pause/resume a flow at runtime without restarting the context.
@Component
public class FlowControl {
private final EventDrivenConsumer orderConsumer; // an AbstractEndpoint subtype
FlowControl(EventDrivenConsumer orderConsumer) {
this.orderConsumer = orderConsumer;
}
public void pause() { orderConsumer.stop(); } // doStop(): channel.unsubscribe(handler)
public void resume() { orderConsumer.start(); } // doStart(): channel.subscribe(handler)
public boolean isRunning() { return orderConsumer.isRunning(); }
}go deeper
Know endpoints start and stop with the context and connect a handler to a channel.
Explain SmartLifecycle, autoStartup, and that subscribe/schedule happens on start().
Detail doStart/doStop per subclass, phase ordering, and runtime pause/resume via Control Bus.
Design graceful start/stop sequencing, back-pressure via runtime stop, and operational control of live flows.
## What AbstractEndpoint is `AbstractEndpoint` (in `org.springframework.integration.endpoint`) is the abstract base for the runtime objects that read from a channel and drive a `MessageHandler`: - **`EventDrivenConsumer`** — for `SubscribableChannel` inputs. - **`PollingConsumer`** — for `PollableChannel` inputs. - **`SourcePollingChannelAdapter`** — for pull-based `MessageSource`s (file, JDBC, etc.). It implements Spring's **`SmartLifecycle`** (which extends `Lifecycle` + `Phased`). That means the **`ApplicationContext` owns its lifecycle** and calls it automatically. ## SmartLifecycle contract - **`isAutoStartup()`** — whether the context starts it during refresh (default `true`; you can set `autoStartup=false` to start it manually later). - **`getPhase()`** — an integer ordering. Lower phases start first and stop last; this lets you ensure, say, outbound infrastructure is up before consumers begin. - **`start()` / `stop()` / `stop(Runnable)`** — begin/end processing. `isRunning()` reports state. `AbstractEndpoint` implements these and delegates the real work to template methods **`doStart()`** and **`doStop()`** that subclasses override. ## The key idea: wiring happens on start(), not on construction Constructing an `EventDrivenConsumer(channel, handler)` does **not** subscribe anything. The connection is made in the lifecycle: - **`EventDrivenConsumer.doStart()`** → `channel.subscribe(handler)`. Now sends to the channel dispatch to the handler. **`doStop()`** → `channel.unsubscribe(handler)`. - **`PollingConsumer.doStart()`** → schedules a repeating poll task on the **`TaskScheduler`** driven by the poller's **`Trigger`**; each execution calls `channel.receive()` and invokes the handler. **`doStop()`** → cancels the scheduled future. This is why you can **pause and resume a flow at runtime**: call `stop()`/`start()` on the endpoint bean (or via the **Control Bus**) and it unsubscribes/cancels or re-subscribes/re-schedules — no context restart needed. ## Gotchas - Setting `autoStartup=false` means the flow is silently inert until something calls `start()` — a common "why isn't my consumer running?" bug. - Because ordering is by **phase**, a consumer that starts before its downstream is ready can drop or fail messages; use phases (or `DependsOn`) to sequence. - Stopping an `EventDrivenConsumer` only unsubscribes it; in-flight messages on other subscribers aren't affected. Stopping a `PollingConsumer` cancels future polls but lets an in-progress poll finish. - The endpoint, not the handler, is the `SmartLifecycle` bean — you manage/monitor the endpoint (Spring Integration exposes them, and Actuator/`IntegrationGraph` can list them). ## When this matters Understanding the lifecycle is essential for **graceful start/stop ordering**, **runtime pause/resume** (feature flags, maintenance windows, back-pressure), and debugging endpoints that never became active.
- How can you pause a running integration flow without restarting the application context?Call stop() on the endpoint bean (an AbstractEndpoint/EventDrivenConsumer/PollingConsumer), or send a 'stop' command through a Control Bus. That unsubscribes the handler or cancels the scheduled poll; start() re-wires it. isRunning() reports state.
- What does getPhase()/autoStartup control?autoStartup decides whether the context starts the endpoint during refresh; phase orders start/stop across SmartLifecycle beans (lower phases start first, stop last), letting you bring channels/infrastructure up before consumers and shut them down in reverse.
saying these in an interview costs you the question
- Thinking subscription/polling is wired in the constructor rather than on start()
- Not knowing endpoints are SmartLifecycle beans you can stop/start at runtime
- Confusing the handler with the endpoint — the endpoint owns the lifecycle
- Assuming autoStartup=false still runs the flow