skip to content

What is a @ServiceActivator in Spring Integration, and what does it do?

level: juniorimportance: must knowfreq 35%

answer

  1. method -> ServiceActivatingHandler (a MessageHandler)
  2. inputChannel / outputChannel / replyChannel header
  3. payload, @Header, whole Message mapping
  4. void/null return = terminal; requiresReply -> ReplyRequiredException
  5. general-purpose endpoint (vs transformer/filter/router)

basics

~20 s

A @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
java
@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

for a junior

Know it connects a channel to a method and can send the return value onward.

for a middle

Explain parameter mapping (payload/@Header/Message) and the outputChannel vs replyChannel-header behaviour.

for a senior

Discuss ServiceActivatingHandler/MessagingMethodInvokerHelper, requiresReply, and threading implications.

for a principal

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

context