Get ahead
VMware offers training and certification to turbo-charge your progress.
Learn moreDear Spring community,
We are pleased to announce that the Spring Integration 4.1 Release Candidate is available. Please use the Milestone Repository with Maven or Gradle, or download a distribution archive, to give it a spin.
The release includes many new features and improvements, as well as a number of bug fixes. The GA release is planned in early November.
First of all, thank you all who provided feedback for the 4.1 Milestone 1 and submitted reports (bugs or new features). A special thanks to those who provided contribution via Pull Requests. Here is a summary of major changes since the milestone:
Web Sockets support
This feature was introduced in 4.1 Milestone 1, but several issues have been resolved, and we have now provided a couple of samples to better understand how Web Sockets can be used in Spring Integration applications: Basic and STOMP Chat.
JDK8 Optional<?> consistent handling
If you are using Java 8, you'll be able to use the Optional<?> container for service method arguments. For example:
public void optionals(@Payload("@myConvert.conv(payload)") Optional<Bar> payload,
@Header(value="foo") Optional<String> header)
In this case, if @myConvert.conv(payload) returns null, the payload variable will contain an Optional.empty().
The same thing for header variables - if there is no foo header in the request Message<?>. This can be used
as an alternative to the required attribute on a @Header annotation.
Routing Slip pattern
The Routing Slip pattern is now supported. Rather
than a simple static list of channel names, we have introduced the RoutingSlipRouteStrategy, which provides
dynamic runtime routing based on the request Message<?> and reply object. SpEL is supported too:
<header-enricher input-channel="input" output-channel="process">
<routing-slip value="channel1; request.headers[myRoutingSlipChannel];
routingSlipRoutingStrategy;"/>
</header-enricher>
This pattern is useful in complex, dynamic, cases when it can become difficult to configure multiple routers to determine
message flow. With this enhancement, when a message
arrives at an endpoint that has no output-channel, the routing slip is consulted to determine the next channel to which
the message will be sent. When the routing slip is exhausted, normal replyChannel processing resumes.
Idempotent Receiver pattern
With this release we have implemented the
Idempotent Receiver as a first class feature.
Previously, users would have to implement this pattern, by using a custom MessageSelector in a <filter/>, for example.
The framework now supports this capability as an Advice component that can be applied to any consuming endpoint:
<idempotent-receiver endpoint="endpoint1, foo*"
metadata-store="store"
discard-channel="duplicates"
key-expression="payload.invoiceNumber"/>
This creates an AOP IdempotentReceiverInterceptor which is applied to the MessageHandler#handleMessage within endpoints
where the id matches one of the provided endpoint patterns.
If the discard-channel is omitted, a duplicate message is still sent to the message handler, but it will contain a
duplicateMessage header, allowing user code to take further action.
For JavaConfig, the @IdempotentReceiver annotation is provided, however the IdempotentReceiverInterceptor @Bean must
be configured too:
@Bean
public IdempotentReceiverInterceptor idempotentReceiverInterceptor() {
return new IdempotentReceiverInterceptor(new MetadataStoreSelector(m ->
m.getPayload().toString()));
}
@Bean
@ServiceActivator(inputChannel = "input", outputChannel = "output")
@IdempotentReceiver("idempotentReceiverInterceptor")
public MessageHandler myService() {
....
}
For more information, please, read IdempotentReceiverInterceptor JavaDocs.
Scatter-Gather pattern
The Scatter-Gather Enterprise Integration Pattern is now provided:
<!--Auction scenario-->
<scatter-gather input-channel="inputAuction" output-channel="output"
scatter-channel="auctionChannel">
<gatherer release-strategy-expression="^[payload gt 5] != null or size() == 3"/>
</scatter-gather>
<!--Distribution scenario-->
<scatter-gather input-channel="inputDistribution" output-channel="output"
gather-channel="gatherChannel">
<scatterer apply-sequence="true">
<recipient channel="distribution1Channel"/>
<recipient channel="distribution2Channel"/>
<recipient channel="distribution3Channel"/>
</scatterer>
<gatherer release-strategy-expression="^[payload gt 5] != null or size() == 3"/>
</scatter-gather>
It is a compound endpoint, which combines publish-subscribe logic and an aggregation function.
Of course, it could previously be implemented as an integration flow using the existing publish-subscribe-channel,
or recipient-list-router, together with an aggregator
component, but this new feature provides for a cleaner implementation of scenarios such as best quote.
Redis Queue Gateways
A pair of request-reply (inbound and outbound) gateway components based on Redis Lists have been added to the Redis module:
<int-redis:queue-outbound-gateway request-channel="sendChannel" queue="foo"/>
<int-redis:queue-inbound-gateway request-channel="requestChannel" queue="foo"/>
Reactor's PersistentQueue
The QueueChannel has been changed to allow inject any Queue<?> implementation. This was done to allow the
use of the Chronicle-Queue implementation in the [Reactor]
(http://reactor.github.io/reactor/) project:
@Bean QueueChannel queueChannel() {
return new QueueChannel(new PersistentQueueSpec<Message<?>>()
.codec(new JavaSerializationCodec<>())
.basePath("/usr/queuePath")
.get());
}
Skipping Polls
When using polling endpoints, it is sometimes necessary to "skip" polls, perhaps because some downstream condition might
cause a failure or, say, a task executor pool has no available threads. This release adds the PollSkipAdvice that
can be inserted in the poller's advice chain, with the skip logic based on user-supplied code.
Notes
Conclusion
See the Release Notes for this release and the Project Page for more information. For a complete list of "What's new" in the 4.1 release, see the reference documentation. Users upgrading from earlier releases should consult the various migration guides.
As always, we very much welcome contributions.