For the latest stable version, please use Spring Integration 6.4.1!

Integration Flows Composition

With the MessageChannel abstraction as a first class citizen in Spring Integration, the composition of integration flows was always assumed. The input channel of any endpoint in the flow can be used to send messages from any other endpoint and not only from the one which has this channel as an output. Furthermore, with a @MessagingGateway contract, Content Enricher components, composite endpoints like a <chain>, and now with IntegrationFlow beans (e.g. IntegrationFlowAdapter), it is straightforward enough to distribute the business logic between shorter, reusable parts. All that is needed for the final composition is knowledge about a MessageChannel to send to or receive from.

Starting with version 5.5.4, to abstract more from MessageChannel and hide implementation details from the end-user, the IntegrationFlow introduces the from(IntegrationFlow) factory method to allow starting the current IntegrationFlow from the output of an existing flow:

@Bean
IntegrationFlow templateSourceFlow() {
    return IntegrationFlow.fromSupplier(() -> "test data")
            .channel("sourceChannel")
            .get();
}

@Bean
IntegrationFlow compositionMainFlow(IntegrationFlow templateSourceFlow) {
    return IntegrationFlow.from(templateSourceFlow)
            .<String, String>transform(String::toUpperCase)
            .channel(c -> c.queue("compositionMainFlowResult"))
            .get();
}

On the other hand, the IntegrationFlowDefinition has added a to(IntegrationFlow) terminal operator to continue the current flow at the input channel of some other flow:

@Bean
IntegrationFlow mainFlow(IntegrationFlow otherFlow) {
    return f -> f
            .<String, String>transform(String::toUpperCase)
            .to(otherFlow);
}

@Bean
IntegrationFlow otherFlow() {
    return f -> f
            .<String, String>transform(p -> p + " from other flow")
            .channel(c -> c.queue("otherFlowResultChannel"));
}

The composition in the middle of the flow is simply achievable with an existing gateway(IntegrationFlow) EIP-method. This way we can build flows with any complexity by composing them from simpler, reusable logical blocks. For example, you may add a library of IntegrationFlow beans as a dependency, and it is just enough to have their configuration classes imported to the final project and autowired for your IntegrationFlow definitions.