skip to content

How do you declare multiple functions and compose them via spring.cloud.function.definition (`;` and `|`)? What binding names result?

level: seniorimportance: should knowfreq 40%

answer

  1. ; = independent functions, own bindings each
  2. | = compose into one pipeline
  3. composite name = concatenation, no delimiter
  4. types must line up out->in
  5. Supplier|Fn, Fn|Consumer allowed

basics

~20 s

List several beans separated by ; to run them as independent handlers, each with its own bindings. Use | to compose beans into one pipeline, e.g. upper|reverse; the composite gets a single pair of bindings named after the concatenated names.

solid answer

~40 s

spring.cloud.function.definition accepts multiple entries. A semicolon (`;`) declares several independent functions — each gets its own `<name>-in-0`/`-out-0` bindings that you configure separately. A pipe (`|`) composes functions into a single chained function where each output feeds the next input; the resulting composite has one input binding and one output binding whose name is the concatenation of the parts (e.g. `upper|reverse` → binding `upperreverse-in-0`/`upperreverse-out-0`). Composition requires the adjacent types to line up (out of one = in of next). You can even compose a Supplier with a Function, or a Function with a Consumer. This lets you build reusable, testable stages and wire pipelines purely through configuration without changing code.

code

java · 14 lines
java
@Configuration
public class Pipeline {
    @Bean public Function<String,String> uppercase() { return String::toUpperCase; }
    @Bean public Function<String,String> reverse()   { return s -> new StringBuilder(s).reverse().toString(); }
    @Bean public Consumer<String> audit()             { return s -> System.out.println("seen " + s); }
}

// application.properties
// spring.cloud.function.definition=uppercase|reverse;audit
// composite "uppercasereverse" -> uppercasereverse-in-0 / uppercasereverse-out-0
// standalone "audit"           -> audit-in-0
// spring.cloud.stream.bindings.uppercasereverse-in-0.destination=words
// spring.cloud.stream.bindings.uppercasereverse-out-0.destination=processed
// spring.cloud.stream.bindings.audit-in-0.destination=processed

go deeper

for a junior

Know that ; separates multiple functions and | composes them.

for a middle

State the resulting binding names and that composed stages must be type-compatible.

for a senior

Explain concatenated composite naming, Supplier|Function / Function|Consumer forms, and config-vs-code composition trade-offs.

for a principal

Design multi-stage pipelines declaratively, weigh composition vs routing for branching, and reason about content-type conversion boundaries within a composite.

`spring.cloud.function.definition` is not limited to a single bean name. It supports two operators: **Semicolon `;` — multiple independent functions.** Each listed function is activated separately with its own bindings: ``` spring.cloud.function.definition=uppercase;audit ``` This produces `uppercase-in-0`/`uppercase-out-0` **and** `audit-in-0` (audit is a Consumer, so no out). You configure destinations for each independently. Use this when a single app hosts several unrelated handlers. **Pipe `|` — function composition.** Adjacent functions are chained so the output of the left feeds the input of the right, forming one logical function: ``` spring.cloud.function.definition=uppercase|reverse ``` The composite exposes exactly **one** input binding and **one** output binding, and its name is the **concatenation of the composed bean names with no separator**: `uppercasereverse`. So the bindings are `uppercasereverse-in-0` and `uppercasereverse-out-0`: ``` spring.cloud.stream.bindings.uppercasereverse-in-0.destination=words spring.cloud.stream.bindings.uppercasereverse-out-0.destination=done ``` **Type-compatibility rule.** Composition works only if the output type of each stage matches the input type of the next. `Function<A,B>` then `Function<B,C>` yields `Function<A,C>`. You may also: - compose a **Supplier with a Function**: `source|transform` → a `Supplier` (still has only `-out-0`, no input binding). - compose a **Function with a Consumer**: `transform|sink` → a `Consumer` (only `-in-0`, no output binding). **Mixing operators.** You can combine: `spring.cloud.function.definition=enrich|score;audit` — one composed pipeline `enrichscore` plus a standalone `audit`. **Why compose in config vs code.** Keeping each stage a small single-responsibility bean makes them unit-testable and reusable; the wiring is declarative and changeable without recompiling. Content-type conversion is applied between the app boundary and the first/last stage, while in-composition hops pass Java objects directly. **Gotchas.** - The composite binding name has **no delimiter** between parts — `a|b` becomes `ab-in-0`, which surprises people expecting `a-b` or `a|b`. This makes config keys easy to mistype. - Every referenced bean name must exist; a typo yields a startup failure (no such function in catalog). - Composition is left-to-right and strictly linear — for branching/fan-out you need separate functions or a routing function, not `|`. - Ordering matters: `a|b` ≠ `b|a`. - Reactive and imperative stages can be mixed but SCSt adapts them; be mindful that a reactive stage processes the whole Flux.

  • You compose `enrich|score`. What is the exact input binding name?
    `enrichscore-in-0` — the composite name is the two bean names concatenated with no delimiter, followed by the standard -in-0 suffix. There is a single input and single output binding for the whole composite.
  • Can `|` express a fan-out where one message goes to two different downstream functions?
    No. `|` is strictly linear left-to-right composition producing one pipeline. For branching you use separate functions (each with its own bindings) or a routing function; SCSt composition itself doesn't fan out.

saying these in an interview costs you the question

  • Expecting the composite binding name to include a hyphen or pipe between parts
  • Thinking | can fan out to multiple downstream functions
  • Believing ; composes a pipeline (it declares independent functions)

context