What is a @ServiceActivator in Spring Integration, and what does it do?
answer
- method -> ServiceActivatingHandler (a MessageHandler)
- inputChannel / outputChannel / replyChannel header
- payload, @Header, whole Message mapping
- void/null return = terminal; requiresReply -> ReplyRequiredException
- general-purpose endpoint (vs transformer/filter/router)
basics
~20 sA @ServiceActivator marks a method (or bean) that consumes messages from an input channel, runs your business logic, and optionally sends the return value to an output channel. It connects a message channel to plain application code.
solid answer
~40 s@ServiceActivator is the annotation that turns an ordinary bean method into a message endpoint. You put it on a method with attributes like inputChannel and outputChannel. Spring wraps that method in a ServiceActivatingHandler (a MessageHandler), and creates an endpoint that reads Messages from the input channel, invokes your method, and — if the method returns a value — sends the result to the outputChannel, or to the replyChannel header if no outputChannel is set. Method arguments are populated from the Message: the whole Message, its payload, or headers (via @Header/@Payload). It is the primary way to plug business logic into an integration flow. If requiresReply=true and the method returns null/void, it throws ReplyRequiredException.
code
java · 12 lines@Component
public class OrderService {
// Reads Messages from "orders", runs logic, sends result to "receipts".
@ServiceActivator(inputChannel = "orders", outputChannel = "receipts")
public Receipt handle(@Payload Order order,
@Header("tenantId") String tenantId) {
return process(order, tenantId); // return value becomes the next Message payload
}
private Receipt process(Order o, String t) { /* ... */ return new Receipt(); }
}go deeper
Know it connects a channel to a method and can send the return value onward.
Explain parameter mapping (payload/@Header/Message) and the outputChannel vs replyChannel-header behaviour.
Discuss ServiceActivatingHandler/MessagingMethodInvokerHelper, requiresReply, and threading implications.
Reason about it as one uniform MessageHandler abstraction among endpoint types and how advice chains/error handling attach.
## What it is Spring Integration models data flow as **Messages** (payload + headers) moving through **MessageChannels**. A **service activator** is the endpoint that connects a channel to a piece of business logic — it "activates" a service when a message arrives. `@ServiceActivator` is placed on a bean **method**. At startup, Spring Integration's annotation post-processor wraps that method in a **`ServiceActivatingHandler`**, which is a `MessageHandler`. The method invocation itself is done reflectively through **`MessagingMethodInvokerHelper`**, which maps the incoming `Message` onto your method parameters. ## Key attributes - **`inputChannel`** — the channel the endpoint reads from. This is what causes an endpoint (a `PollingConsumer` or `EventDrivenConsumer`) to be created and wired to the handler. - **`outputChannel`** — where the return value is sent. If omitted, the result is sent to the channel named in the message's **`replyChannel`** header (enabling request/reply). - **`requiresReply`** — if `true` and the method returns `null` or `void`, a **`ReplyRequiredException`** is thrown. - **`sendTimeout`**, **`async`**, **`poller`**, **`adviceChain`**, **`order`** — additional tuning. ## Parameter mapping Your method can take: the whole `Message<?>`, just the payload (auto-converted to the parameter type), specific headers via `@Header("name")`, all headers via `@Headers Map`, or `@Payload` with a SpEL expression. If it returns `void` or `null`, the flow ends there (a one-way/terminal endpoint). ## Where it sits A service activator is one of several endpoint types (transformer, filter, router, splitter, aggregator). It is the general-purpose one: any method that takes a message/payload and optionally returns a result. ## Gotchas - Forgetting an `outputChannel` on a method that returns a value is fine **only** if a `replyChannel` header exists; otherwise you get a `DestinationResolutionException` ("no output-channel or replyChannel header available"). - If the input channel is a **pollable** channel (e.g., `QueueChannel`), the endpoint is a `PollingConsumer` and you **must** supply a poller (see `@Poller`/default poller) or startup fails. - The handler runs on the thread that delivers the message — for a subscribable channel that's the **sender's** thread (synchronous), which surprises people expecting async behavior. ## When to use Use a service activator whenever you need to call arbitrary business logic from a flow and don't need the specialized semantics of a transformer/filter/router.
- If your @ServiceActivator method returns a value but you set no outputChannel, where does the result go?To the channel named in the incoming message's replyChannel header. If there is no such header, a DestinationResolutionException is thrown because there is nowhere to send the reply.
- What happens if requiresReply=true and the method returns null?The ServiceActivatingHandler throws a ReplyRequiredException, signalling that a downstream reply was mandatory but the handler produced none.
saying these in an interview costs you the question
- Thinking @ServiceActivator always runs asynchronously (it runs on the delivering thread unless the channel is executor/queue-backed)
- Believing a method must always return a value (void/terminal is valid)
- Confusing service activator with a transformer — a transformer must return a value; a service activator need not