skip to content

Describe AbstractEndpoint and how endpoint lifecycle connects a MessageHandler to its channel.

level: seniorimportance: should knowfreq 16%

answer

  1. AbstractEndpoint implements SmartLifecycle
  2. wiring on doStart()/doStop(), not constructor
  3. EventDrivenConsumer subscribes; PollingConsumer schedules
  4. autoStartup + phase = ordering; runtime pause/resume
  5. manage the endpoint bean (Control Bus), not the handler

basics

~20 s

AbstractEndpoint 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 s

AbstractEndpoint 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
java
// 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

for a junior

Know endpoints start and stop with the context and connect a handler to a channel.

for a middle

Explain SmartLifecycle, autoStartup, and that subscribe/schedule happens on start().

for a senior

Detail doStart/doStop per subclass, phase ordering, and runtime pause/resume via Control Bus.

for a principal

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

context