Spring Integration offers a number of configuration options. Which option you choose depends upon your particular needs and at what level you prefer to work. As with the Spring framework in general, you can mix and match the various techniques to suit the problem at hand. For example, you can choose the XSD-based namespace for the majority of configuration and combine it with a handful of objects that you configure with annotations. As much as possible, the two provide consistent naming. The XML elements defined by the XSD schema match the names of the annotations, and the attributes of those XML elements match the names of annotation properties. You can also use the API directly, but we expect most developers to choose one of the higher-level options or a combination of the namespace-based and annotation-driven configuration.
You can configure Spring Integration components with XML elements that map directly to the terminology and concepts of enterprise integration. In many cases, the element names match those of the Enterprise Integration Patterns book.
To enable Spring Integration’s core namespace support within your Spring configuration files, add the following namespace reference and schema mapping in your top-level beans element:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
(We have emphasized the lines that are particular to Spring Integration.)
You can choose any name after "xmlns:".
We use int
(short for Integration) for clarity, but you might prefer another abbreviation.
On the other hand, if you use an XML editor or IDE support, the availability of auto-completion may convince you to keep the longer name for clarity.
Alternatively, you can create configuration files that use the Spring Integration schema as the primary namespace, as the following example shows:
<beans:beans xmlns="http://www.springframework.org/schema/integration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
(We have emphasized the lines that are particular to Spring Integration.)
When using this alternative, no prefix is necessary for the Spring Integration elements.
On the other hand, if you define a generic Spring bean within the same configuration file, the bean element requires a prefix (<beans:bean .../>
).
Since it is generally a good idea to modularize the configuration files themselves (based on responsibility or architectural layer), you may find it appropriate to use the latter approach in the integration-focused configuration files, since generic beans are seldom necessary within those files.
For the purposes of this documentation, we assume the integration namespace is the primary.
Spring Integration provides many other namespaces.
In fact, each adapter type (JMS, file, and so on) that provides namespace support defines its elements within a separate schema.
In order to use these elements, add the necessary namespaces with an xmlns
entry and the corresponding schemaLocation
mapping.
For example, the following root element shows several of these namespace declarations:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration" xmlns:int-file="http://www.springframework.org/schema/integration/file" xmlns:int-jms="http://www.springframework.org/schema/integration/jms" xmlns:int-mail="http://www.springframework.org/schema/integration/mail" xmlns:int-rmi="http://www.springframework.org/schema/integration/rmi" xmlns:int-ws="http://www.springframework.org/schema/integration/ws" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd http://www.springframework.org/schema/integration/file http://www.springframework.org/schema/integration/file/spring-integration-file.xsd http://www.springframework.org/schema/integration/jms http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd http://www.springframework.org/schema/integration/mail http://www.springframework.org/schema/integration/mail/spring-integration-mail.xsd http://www.springframework.org/schema/integration/rmi http://www.springframework.org/schema/integration/rmi/spring-integration-rmi.xsd http://www.springframework.org/schema/integration/ws http://www.springframework.org/schema/integration/ws/spring-integration-ws.xsd"> ... </beans>
This reference manual provides specific examples of the various elements in their corresponding chapters. Here, the main thing to recognize is the consistency of the naming for each namespace URI and schema location.
In Spring Integration, the ApplicationContext
plays the central role of a message bus, and you need to consider only a couple of configuration options.
First, you may want to control the central TaskScheduler
instance.
You can do so by providing a single bean named taskScheduler
.
This is also defined as a constant, as follows:
IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME
By default, Spring Integration relies on an instance of ThreadPoolTaskScheduler
, as described in the Task Execution and Scheduling section of the Spring Framework reference manual.
That default TaskScheduler
starts up automatically with a pool of ten threads, but see Section E.4, “Global Properties”.
If you provide your own TaskScheduler
instance instead, you can set the autoStartup property to false
or provide your own pool size value.
When polling consumers provide an explicit task executor reference in their configuration, the invocation of the handler methods happens within that executor’s thread pool and not the main scheduler pool. However, when no task executor is provided for an endpoint’s poller, it is invoked by one of the main scheduler’s threads.
Caution | |
---|---|
Do not run long-running tasks on poller threads.
Use a task executor instead.
If you have a lot of polling endpoints, you can cause thread starvation, unless you increase the pool size.
Also, polling consumers have a default |
Note | |
---|---|
An endpoint is a Polling Consumer if its input channel is one of the queue-based (that is, pollable) channels. Event-driven consumers are those having input channels that have dispatchers instead of queues (in other words, they are subscribable). Such endpoints have no poller configuration, since their handlers are invoked directly. |
Important | |
---|---|
When running in a JEE container, you may need to use Spring’s <bean id="taskScheduler" class="o.s.scheduling.commonj.TimerManagerTaskScheduler"> <property name="timerManagerName" value="tm/MyTimerManager" /> <property name="resourceRef" value="true" /> </bean> |
The next section describes what happens if exceptions occur within the asynchronous invocations.
As described in the overview at the very beginning of this manual, one of the main motivations behind a message-oriented framework such as Spring Integration is to promote loose coupling between components. The message channel plays an important role, in that producers and consumers do not have to know about each other. However, the advantages also have some drawbacks. Some things become more complicated in a loosely coupled environment, and one example is error handling.
When sending a message to a channel, the component that ultimately handles that message may or may not be operating within the same thread as the sender.
If using a simple default DirectChannel
(when the <channel>
element that has no <queue>
child element and no task-executor attribute),
the message handling occurs in the same thread that sends the initial message.
In that case, if an Exception
is thrown, it can be caught by the sender (or it may propagate past the sender if it is an uncaught RuntimeException
).
So far, everything is fine.
This is the same behavior as an exception-throwing operation in a normal call stack.
A message flow that runs on a caller thread might be invoked through a messaging gateway (see Section 10.4, “Messaging Gateways”) or a MessagingTemplate
(see Section 6.1.4, “MessagingTemplate
”).
In either case, the default behavior is to throw any exceptions to the caller.
For the messaging gateway, see Section 10.4.8, “Error Handling” for details about how the exception is thrown and how to configure the gateway to route the errors to an error channel instead.
When using a MessagingTemplate
or sending to a MessageChannel
directly, exceptions are always thrown to the caller.
When adding asynchronous processing, things become rather more complicated.
For instance, if the channel element does provide a queue child element, the component that handles the message operates in a different thread than the sender.
The same is true when an ExecutorChannel
is used.
The sender may have dropped the Message
into the channel and moved on to other things.
There is no way for the Exception
to be thrown directly back to that sender by using standard Exception
throwing techniques.
Instead, handling errors for asynchronous processes requires that the error-handling mechanism also be asynchronous.
Spring Integration supports error handling for its components by publishing errors to a message channel.
Specifically, the Exception
becomes the payload of a Spring Integration ErrorMessage
.
That Message
is then sent to a message channel that is resolved in a way that is similar to the replyChannel resolution.
First, if the request Message
being handled at the time the Exception
occurred contains an errorChannel header (the header name is defined in the MessageHeaders.ERROR_CHANNEL
constant), the ErrorMessage
is sent to that channel.
Otherwise, the error handler sends to a "global
" channel whose bean name is errorChannel
(this is also defined as a constant: IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME
).
A default errorChannel
bean is created internally by the Framework.
However, you can define your own if you want to control the settings.
The following example shows how to define an error channel backed by a queue with a capacity of 500:
<int:channel id="errorChannel"> <int:queue capacity="500"/> </int:channel>
Note | |
---|---|
The default error channel is a |
The most important thing to understand here is that the messaging-based error handling applies only to exceptions that are thrown by a Spring Integration task that is executing within a TaskExecutor
.
This does not apply to exceptions thrown by a handler that operates within the same thread as the sender (for example, through a DirectChannel
as described earlier in this section).
Note | |
---|---|
When exceptions occur in a scheduled poller task’s execution, those exceptions are wrapped in |
To enable global error handling, register a handler on that channel.
For example, you can configure Spring Integration’s ErrorMessageExceptionTypeRouter
as the handler of an endpoint that is subscribed to the errorChannel.
That router can then spread the error messages across multiple channels, based on the Exception
type.
Starting with version 4.3.10, Spring Integration provides the ErrorMessagePublisher
and the ErrorMessageStrategy
.
You can use them as a general mechanism for publishing ErrorMessage
instances.
You can call or extend them in any error handling scenarios.
The ErrorMessageSendingRecoverer
extends this class as a RecoveryCallback
implementation that can be used with retry, such as the
RequestHandlerRetryAdvice
.
The ErrorMessageStrategy
is used to build an ErrorMessage
based on the provided exception and an AttributeAccessor
context.
It can be injected into any MessageProducerSupport
or MessagingGatewaySupport
.
The requestMessage
is stored under ErrorMessageUtils.INPUT_MESSAGE_CONTEXT_KEY
in the AttributeAccessor
context.
The ErrorMessageStrategy
can use that requestMessage
as the originalMessage
property of the ErrorMessage
it creates.
The DefaultErrorMessageStrategy
does exactly that.
Certain global framework properties can be overridden by providing a properties file on the classpath.
The default properties can be found in /META-INF/spring.integration.default.properties
in the spring-integration-core
jar.
You can see them on GitHub here.
The following listing shows the default values:
spring.integration.channels.autoCreate=true spring.integration.channels.maxUnicastSubscribers=0x7fffffff spring.integration.channels.maxBroadcastSubscribers=0x7fffffff spring.integration.taskScheduler.poolSize=10 spring.integration.messagingTemplate.throwExceptionOnLateReply=false spring.integration.readOnly.headers= spring.integration.endpoints.noAutoStartup= spring.integration.postProcessDynamicBeans=false
When true, | |
Sets the default number of subscribers allowed on, for example, a | |
This property provides the default number of subscribers allowed on, for example, a | |
The number of threads available in the default | |
When | |
A comma-separated list of message header names that should not be populated into | |
A comma-separated list of | |
A boolean flag to indicate that |
These properties can be overridden by adding a /META-INF/spring.integration.properties
file to the classpath.
You need not provide all the properties — only those that you want to override.
Starting with version 5.1, all the merged global properties are printed in the logs after application context startup when a DEBUG
logic level is turned on for the org.springframework.integration
category.
The output looks like this:
Spring Integration global properties: spring.integration.endpoints.noAutoStartup=fooService* spring.integration.taskScheduler.poolSize=20 spring.integration.channels.maxUnicastSubscribers=0x7fffffff spring.integration.channels.autoCreate=true spring.integration.channels.maxBroadcastSubscribers=0x7fffffff spring.integration.readOnly.headers= spring.integration.messagingTemplate.throwExceptionOnLateReply=true
In addition to the XML namespace support for configuring message endpoints, you can also use annotations.
First, Spring Integration provides the class-level @MessageEndpoint
as a stereotype annotation, meaning that it is itself annotated with Spring’s @Component
annotation and is therefore automatically recognized as a bean definition by Spring’s component scanning.
Even more important are the various method-level annotations. They indicate that the annotated method is capable of handling a message. The following example demonstrates both class-level and method-level annotations:
@MessageEndpoint public class FooService { @ServiceActivator public void processMessage(Message message) { ... } }
Exactly what it means for the method to "handle
" the Message depends on the particular annotation.
Annotations available in Spring Integration include:
@Aggregator
(see Section 8.4, “Aggregator”)
@Filter
(see Section 8.2, “Filter”)
@Router
(see Section 8.1, “Routers”)
@ServiceActivator
(see Section 10.5, “Service Activator”)
@Splitter
(see Section 8.3, “Splitter”)
@Transformer
(see Section 9.1, “Transformer”)
@InboundChannelAdapter
(see Section 6.3, “Channel Adapter”)
@BridgeFrom
(see Section 6.4.2, “Configuring a Bridge with Java Configuration”)
@BridgeTo
(see Section 6.4.2, “Configuring a Bridge with Java Configuration”)
@MessagingGateway
(see Section 10.4, “Messaging Gateways”)
@IntegrationComponentScan
(see Section 5.5, “Configuration and @EnableIntegration
”)
Note | |
---|---|
If you use XML configuration in combination with annotations, the |
In most cases, the annotated handler method should not require the Message
type as its parameter.
Instead, the method parameter type can match the message’s payload type, as the following example shows:
public class ThingService { @ServiceActivator public void bar(Thing thing) { ... } }
When the method parameter should be mapped from a value in the MessageHeaders
, another option is to use the parameter-level @Header
annotation.
In general, methods annotated with the Spring Integration annotations can accept the Message
itself, the message payload, or a header value (with @Header
) as the parameter.
In fact, the method can accept a combination, as the following example shows:
public class ThingService { @ServiceActivator public void otherThing(String payload, @Header("x") int valueX, @Header("y") int valueY) { ... } }
You can also use the @Headers
annotation to provide all of the message headers as a Map
, as the following example shows:
public class ThingService { @ServiceActivator public void otherThing(String payload, @Headers Map<String, Object> headerMap) { ... } }
Note | |
---|---|
The value of the annotation can also be a SpEL expression (for example, |
For several of these annotations, when a message-handling method returns a non-null value, the endpoint tries to send a reply.
This is consistent across both configuration options (namespace and annotations) in that such an endpoint’s output channel is used (if available), and the REPLY_CHANNEL
message header value is used as a fallback.
Tip | |
---|---|
The combination of output channels on endpoints and the reply channel message header enables a pipeline approach, where multiple components have an output channel and the final component allows the reply message to be forwarded to the reply channel (as specified in the original request message). In other words, the final component depends on the information provided by the original sender and can dynamically support any number of clients as a result. This is an example of the return address pattern. |
In addition to the examples shown here, these annotations also support the inputChannel
and outputChannel
properties, as the following example shows:
@Service public class ThingService { @ServiceActivator(inputChannel="input", outputChannel="output") public void otherThing(String payload, @Headers Map<String, Object> headerMap) { ... } }
The processing of these annotations creates the same beans as the corresponding XML components — AbstractEndpoint
instances and MessageHandler
instances (or MessageSource
instances for the inbound channel adapter).
See Section E.4, “Global Properties”.
The bean names are generated from the following pattern: [componentName].[methodName].[decapitalizedAnnotationClassShortName]
(for example, for the preceding example the bean name is thingService.otherThing.serviceActivator
) for the AbstractEndpoint
and the same name with an additional .handler
(.source
) suffix for the MessageHandler
(MessageSource
) bean.
The MessageHandler
instances (MessageSource
instances) are also eligible to be tracked by the message history.
Starting with version 4.0, all messaging annotations provide SmartLifecycle
options (autoStartup
and phase
) to allow endpoint lifecycle control on application context initialization.
They default to true
and 0
, respectively.
To change the state of an endpoint (such as ` start()` or stop()
), you can obtain a reference to the endpoint bean by using the BeanFactory
(or autowiring) and invoke the methods.
Alternatively, you can send a command message to the Control Bus
(see Section 12.6, “Control Bus”).
For these purposes, you should use the beanName
mentioned earlier in the preceding paragraph.
==== Using the @Poller
Annotation
Before Spring Integration 4.0, messaging annotations required that the inputChannel
be a reference to a SubscribableChannel
.
For PollableChannel
instances, an <int:bridge/>
element was needed to configure an <int:poller/>
and make the composite endpoint be a PollingConsumer
.
Version 4.0 introduced the @Poller
annotation to allow the configuration of poller
attributes directly on the messaging annotations, as the following example shows:
public class AnnotationService { @Transformer(inputChannel = "input", outputChannel = "output", poller = @Poller(maxMessagesPerPoll = "${poller.maxMessagesPerPoll}", fixedDelay = "${poller.fixedDelay}")) public String handle(String payload) { ... } }
The @Poller
annotation provides only simple PollerMetadata
options.
You can configure the @Poller
annotation’s attributes (maxMessagesPerPoll
, fixedDelay
, fixedRate
, and cron
) with property placeholders.
Also, starting with version 5.1, the receiveTimeout
option for PollingConsumer
s is also provided.
If it is necessary to provide more polling options (for example, transaction
, advice-chain
, error-handler
, and others), you should configure the PollerMetadata
as a generic bean and use its bean name as the @Poller
's value
attribute.
In this case, no other attributes are allowed (they must be specified on the PollerMetadata
bean).
Note, if inputChannel
is a PollableChannel
and no @Poller
is configured, the default PollerMetadata
is used (if it is present in the application context).
To declare the default poller by using a @Configuration
annotation, use code similar to the following example:
@Bean(name = PollerMetadata.DEFAULT_POLLER) public PollerMetadata defaultPoller() { PollerMetadata pollerMetadata = new PollerMetadata(); pollerMetadata.setTrigger(new PeriodicTrigger(10)); return pollerMetadata; }
The following example shows how to use the default poller:
public class AnnotationService { @Transformer(inputChannel = "aPollableChannel", outputChannel = "output") public String handle(String payload) { ... } }
The following example shows how to use a named poller:
@Bean public PollerMetadata myPoller() { PollerMetadata pollerMetadata = new PollerMetadata(); pollerMetadata.setTrigger(new PeriodicTrigger(1000)); return pollerMetadata; }
The following example shows an endpoint that uses the default poller:
public class AnnotationService { @Transformer(inputChannel = "aPollableChannel", outputChannel = "output" poller = @Poller("myPoller")) public String handle(String payload) { ... } }
Starting with version 4.3.3, the @Poller
annotation has the errorChannel
attribute for easier configuration of the underlying MessagePublishingErrorHandler
.
This attribute plays the same role as error-channel
in the <poller>
XML component.
See Section 10.1.4, “Endpoint Namespace Support” for more information.
==== Using the @InboundChannelAdapter
Annotation
Version 4.0 introduced the @InboundChannelAdapter
method-level annotation.
It produces a SourcePollingChannelAdapter
integration component based on a MethodInvokingMessageSource
for the annotated method.
This annotation is an analogue of the <int:inbound-channel-adapter>
XML component and has the same restrictions: The method cannot have parameters, and the return type must not be void
.
It has two attributes: value
(the required MessageChannel
bean name) and poller
(an optional @Poller
annotation, as described earlier).
If you need to provide some MessageHeaders
, use a Message<?>
return type and use a MessageBuilder
to build the Message<?>
.
Using a MessageBuilder
lets you configure the MessageHeaders
.
The following example shows how to use an @InboundChannelAdapter
annotation:
@InboundChannelAdapter("counterChannel") public Integer count() { return this.counter.incrementAndGet(); } @InboundChannelAdapter(value = "fooChannel", poller = @Poller(fixed-rate = "5000")) public String foo() { return "foo"; }
Version 4.3 introduced the channel
alias for the value
annotation attribute, to provide better source code readability.
Also, the target MessageChannel
bean is resolved in the SourcePollingChannelAdapter
by the provided name (set by the outputChannelName
option) on the first receive()
call, not during the initialization phase.
It allows "late binding
" logic: The target MessageChannel
bean from the consumer perspective is created and registered a bit later than the @InboundChannelAdapter
parsing phase.
The first example requires that the default poller has been declared elsewhere in the application context.
Using the @MessagingGateway
Annotation
See Section 10.4.6, “@MessagingGateway
Annotation”.
==== Using the @IntegrationComponentScan
Annotation
The standard Spring Framework @ComponentScan
annotation does not scan interfaces for stereotype @Component
annotations.
To overcome this limitation and allow the configuration of @MessagingGateway
(see Section 10.4.6, “@MessagingGateway
Annotation”), we introduced the @IntegrationComponentScan
mechanism.
This annotation must be placed with a @Configuration
annotation and be customized to define its scanning options,
such as basePackages
and basePackageClasses
.
In this case, all discovered interfaces annotated with @MessagingGateway
are parsed and registered as GatewayProxyFactoryBean
instances.
All other class-based components are parsed by the standard @ComponentScan
.
=== Messaging Meta-Annotations
Starting with version 4.0, all messaging annotations can be configured as meta-annotations and all user-defined messaging annotations can define the same attributes to override their default values. In addition, meta-annotations can be configured hierarchically, as the following example shows:
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @ServiceActivator(inputChannel = "annInput", outputChannel = "annOutput") public @interface MyServiceActivator { String[] adviceChain = { "annAdvice" }; } @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @MyServiceActivator public @interface MyServiceActivator1 { String inputChannel(); String outputChannel(); } ... @MyServiceActivator1(inputChannel = "inputChannel", outputChannel = "outputChannel") public Object service(Object payload) { ... }
Configuring meta-annotations hierarchically lets users set defaults for various attributes and enables isolation of framework Java dependencies to user annotations, avoiding their use in user classes. If the framework finds a method with a user annotation that has a framework meta-annotation, it is treated as if the method were annotated directly with the framework annotation.
==== Annotations on @Bean
Methods
Starting with version 4.0, you can configure messaging annotations on @Bean
method definitions in @Configuration
classes, to produce message endpoints based on the beans, not the methods.
It is useful when @Bean
definitions are "out-of-the-box
" MessageHandler
instances (AggregatingMessageHandler
, DefaultMessageSplitter
, and others), Transformer
instances (JsonToObjectTransformer
, ClaimCheckOutTransformer
, and others), and MessageSource
instances (FileReadingMessageSource
, RedisStoreMessageSource
, and others).
The following example shows how to use messaging annotations with @Bean
annotations:
@Configuration @EnableIntegration public class MyFlowConfiguration { @Bean @InboundChannelAdapter(value = "inputChannel", poller = @Poller(fixedDelay = "1000")) public MessageSource<String> consoleSource() { return CharacterStreamReadingMessageSource.stdin(); } @Bean @Transformer(inputChannel = "inputChannel", outputChannel = "httpChannel") public ObjectToMapTransformer toMapTransformer() { return new ObjectToMapTransformer(); } @Bean @ServiceActivator(inputChannel = "httpChannel") public MessageHandler httpHandler() { HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler("http://foo/service"); handler.setExpectedResponseType(String.class); handler.setOutputChannelName("outputChannel"); return handler; } @Bean @ServiceActivator(inputChannel = "outputChannel") public LoggingHandler loggingHandler() { return new LoggingHandler("info"); } }
Version 5.0 introduced support for a @Bean
annotated with @InboundChannelAdapter
that returns java.util.function.Supplier
, which can produce either a POJO or a Message
.
The followig example shows how to use that combination:
@Configuration @EnableIntegration public class MyFlowConfiguration { @Bean @InboundChannelAdapter(value = "inputChannel", poller = @Poller(fixedDelay = "1000")) public Supplier<String> pojoSupplier() { return () -> "foo"; } @Bean @InboundChannelAdapter(value = "inputChannel", poller = @Poller(fixedDelay = "1000")) public Supplier<Message<String>> messageSupplier() { return () -> new GenericMessage<>("foo"); } }
The meta-annotation rules work on @Bean
methods as well (the @MyServiceActivator
annotation described earlier can be applied to a @Bean
definition).
Note | |
---|---|
When you use these annotations on consumer |
Note | |
---|---|
The bean names are generated with the following algorithm: |
MessageHandler
(MessageSource
) @Bean
gets its own standard name from the method name or name
attribute on the @Bean
.
This works as though there were no messaging annotation on the @Bean
method.
AbstractEndpoint
bean name is generated with the following pattern: [configurationComponentName].[methodName].[decapitalizedAnnotationClassShortName]
.
For example, the SourcePollingChannelAdapter
endpoint for the consoleSource()
definition shown earlier gets a bean name of myFlowConfiguration.consoleSource.inboundChannelAdapter
.
See also Section 5.4.8, “Endpoint Bean Names”.
Important | |
---|---|
When using these annotations on |
Note | |
---|---|
With Java configuration, you can use any |
@Bean @ServiceActivator(inputChannel = "skippedChannel") @Profile("thing") public MessageHandler skipped() { return System.out::println; }
Together with the existing Spring container logic, the messaging endpoint bean (based on the @ServiceActivator
annotation), is also not registered.
==== Creating a Bridge with Annotations
Starting with version 4.0, Java configuration provides the @BridgeFrom
and @BridgeTo
@Bean
method annotations to mark MessageChannel
beans in @Configuration
classes.
These really exists for completeness, providing a convenient mechanism to declare a BridgeHandler
and its message endpoint configuration:
@Bean public PollableChannel bridgeFromInput() { return new QueueChannel(); } @Bean @BridgeFrom(value = "bridgeFromInput", poller = @Poller(fixedDelay = "1000")) public MessageChannel bridgeFromOutput() { return new DirectChannel(); } @Bean public QueueChannel bridgeToOutput() { return new QueueChannel(); } @Bean @BridgeTo("bridgeToOutput") public MessageChannel bridgeToInput() { return new DirectChannel(); }
You can use these annotations as meta-annotations as well.
==== Advising Annotated Endpoints
See Section 10.9.7, “Advising Endpoints Using Annotations”.
=== Message Mapping Rules and Conventions
Spring Integration implements a flexible facility to map messages to methods and their arguments without providing extra configuration, by relying on some default rules and defining certain conventions. The examples in the following sections articulate the rules.
The following example shows a single un-annotated parameter (object or primitive) that is not a Map
or a Properties
object with a non-void return type:
public String doSomething(Object o);
The input parameter is a message payload. If the parameter type is not compatible with a message payload, an attempt is made to convert it by using a conversion service provided by Spring 3.0. The return value is incorporated as a payload of the returned message.
The following example shows a single un-annotated parameter (object or primitive)that is not a Map
or a Properties
with a Message
return type:
public Message doSomething(Object o);
The input parameter is a message payload. If the parameter type is not compatible with a message payload, an attempt is made to convert it by using a conversion service provided by Spring 3.0. The return value is a newly constructed message that is sent to the next destination.
The followig example shows a single parameter that is a message (or one of its subclasses) with an arbitrary object or primitive return type:
public int doSomething(Message msg);
The input parameter is itself a Message
.
The return value becomes a payload of the Message
that is sent to the next destination.
The following example shows a single parameter that is a Message
(or one of its subclasses) with a Message
(or one of its subclasses) as the return type:
public Message doSomething(Message msg);
The input parameter is itself a Message
.
The return value is a newly constructed Message
that is sent to the next destination.
The following example shows a single parameter of type Map
or Properties
with a Message
as the return type:
public Message doSomething(Map m);
This one is a bit interesting.
Although, at first, it might seem like an easy mapping straight to message headers, preference is always given to a Message
payload.
This means that if a Message
payload is of type Map
, this input argument represents a Message
payload.
However, if the Message
payload is not of type Map
, the conversion service does not try to convert the payload, and the input argument is mapped to message headers.
The following example shows two parameters, where one of them is an arbitrary type (an object or a primitive) that is not a Map
or a Properties
object and the other is of type Map
or Properties
type (regardless of the return):
public Message doSomething(Map h, <T> t);
This combination contains two input parameters where one of them is of type Map
.
The non-Map
parameters (regardless of the order) are mapped to a Message
payload and the Map
or Properties
(regardless of the order) is mapped to message headers, giving you a nice POJO way of interacting with Message
structure.
The following example shows no parameters (regardless of the return):
public String doSomething();
This message handler method is invoked based on the Message sent to the input channel to which this handler is connected.
However no Message
data is mapped, thus making the Message
act as event or trigger to invoke the handler.
The output is mapped according to the rules described earlier.
The following example shows no parameters and a void return:
public void soSomething();
This example is the same as the previous example, but it produces no output.
==== Annotation-based Mapping
Annotation-based mapping is the safest and least ambiguous approach to map messages to methods. The following example shows how to explicitly map a method to a header:
public String doSomething(@Payload String s, @Header("someheader") String b)
As you can see later on, without an annotation this signature would result in an ambiguous condition.
However, by explicitly mapping the first argument to a Message
payload and the second argument to a value of the someheader
message header, we avoid any ambiguity.
The following example is nearly identical to the preceding example:
public String doSomething(@Payload String s, @RequestParam("something") String b)
@RequestMapping
or any other non-Spring Integration mapping annotation is irrelevant and is therefore ignored, leaving the second parameter unmapped.
Although the second parameter could easily be mapped to a payload, there can only be one payload.
Therefore, the annotations keep this method from being ambiguous.
The following example shows another similar method that would be ambiguous were it not for annotations to clarify the intent:
public String foo(String s, @Header("foo") String b)
The only difference is that the first argument is implicitly mapped to the message payload.
The following example shows yet another signature that would definitely be treated as ambiguous without annotations, because it has more than two arguments:
public String soSomething(@Headers Map m, @Header("something") Map f, @Header("someotherthing") String bar)
This example would be especially problematic, because two of its arguments are Map
instances.
However, with annotation-based mapping, the ambiguity is easily avoided.
In this example the first argument is mapped to all the message headers, while the second and third argument map to the values of the message headers named something and someotherthing.
The payload is not being mapped to any argument.
The following example uses multiple parameters:
Multiple parameters can create a lot of ambiguity with regards to determining the appropriate mappings.
The general advice is to annotate your method parameters with @Payload
, @Header
, and @Headers
.
The examples in this section show ambiguous conditions that result in an exception being raised.
public String doSomething(String s, int i)
The two parameters are equal in weight. Therefore, there is no way to determine which one is a payload.
The following example shows a similar problem, only with three parameters:
public String foo(String s, Map m, String b)
Although the Map could be easily mapped to message headers, there is no way to determine what to do with the two String parameters.
The following example shows another ambiguous method:
public String foo(Map m, Map f)
Although one might argue that one Map
could be mapped to the message payload and the other one to the message headers, we cannot rely on the order.
Tip | |
---|---|
Any method signature with more than one method argument that is not (Map, <T>) and with unannotated parameters results in an ambiguous condition and triggers an exception. |
The next set of examples each show mutliple methods that result in ambiguity.
Message handlers with multiple methods are mapped based on the same rules that are described earlier (in the examples). However, some scenarios might still look confusing.
The following example shows multiple methods with legal (mappable and unambiguous) signatures:
public class Something { public String doSomething(String str, Map m); public String doSomething(Map m); }
(Whether the methods have the same name or different names makes no difference).
The Message
could be mapped to either method.
The first method would be invoked when the message payload could be mapped to str
and the message headers could be mapped to m
.
The second method could also be a candidate by mapping only the message headers to m
.
To make matters worse, both methods have the same name.
At first, that might look ambiguous because of the following configuration:
<int:service-activator input-channel="input" output-channel="output" method="doSomething"> <bean class="org.things.Something"/> </int:service-activator>
It works because mappings are based on the payload first and everything else next. In other words, the method whose first argument can be mapped to a payload takes precedence over all other methods.
Now consider an alternate example, which produces a truly ambiguous condition:
public class Something { public String doSomething(String str, Map m); public String doSomething(String str); }
Both methods have signatures that could be mapped to a message payload.
They also have the same name.
Such handler methods will trigger an exception.
However, if the method names were different, you could influence the mapping with a method
attribute (shown in the next example).
The following example shows the same example with two different method names:
public class Something { public String doSomething(String str, Map m); public String doSomethingElse(String str); }
The following example shows how to use the method
attribute to dictate the mapping:
<int:service-activator input-channel="input" output-channel="output" method="doSomethingElse"> <bean class="org.bar.Foo"/> </int:service-activator>
Because the configuration explicitly maps the doSomethingElse
method, we have eliminated the ambiguity.
Spring Integration provides a number of utilities and annotations to help you test your application. Testing support is presented by two modules:
spring-integration-test-support
contains core items and shared utilities
spring-integration-test
provides mocking and application context configuration components for integration tests
spring-integration-test-support
(spring-integration-test
in versions before 5.0) provides basic, standalone utilities, rules, and matchers for unit testing.
(it also has no dependencies on Spring Integration itself and is used internally in Framework tests).
spring-integration-test
aims to help with integration testing and provides a comprehensive high-level API to mock integration components and verify the behavior of individual components, including whole integration flows or only parts of them.
A thorough treatment of testing in the enterprise is beyond the scope of this reference manual.
See the "Test-Driven Development in Enterprise Integration Projects
" paper, by Gregor Hohpe and Wendy Istvanick, for a source of ideas and principles for testing your target integration solution.
The Spring Integration Test Framework and test utilities are fully based on existing JUnit, Hamcrest, and Mockito libraries. The application context interaction is based on the Spring test framework. See the documentation for those projects for further information.
Thanks to the canonical implementation of the EIP in Spring Integration Framework and its first-class citizens (such as MessageChannel
, Endpoint
and MessageHandler
), abstractions, and loose coupling principles, you can implement integration solutions of any complexity.
With the Spring Integration API for the flow definitions, you can improve, modify or even replace some part of the flow without impacting (mostly) other components in the integration solution.
Testing such an integration solution is still a challenge, both from an end-to-end approach and from an in-isolation approach.
Several existing tools can help to test or mock some integration protocols, and they work well with Spring Integration channel adapters. Examples of such tools include the following:
MockMVC
and its MockRestServiceServer
can be used for testing HTTP.
FtpServer
and SshServer
from the Apache Mina project can be used for testing the FTP and SFTP protocols.
TestingServer
for Zookeeper interaction.
Most of these tools and libraries are used in Spring Integration tests.
Also, from the GitHub repository (in the test
directory of each module), you can discover ideas for how to build your own tests for integration solutions.
The rest of this chapter describes the testing tools and utilities provided by Spring Integration.
The spring-integration-test-support
module provides utilities and helpers for unit testing.
==== TestUtils
The TestUtils
class is mostly used for properties assertions in JUnit tests, as the following example shows:
@Test public void loadBalancerRef() { MessageChannel channel = channels.get("lbRefChannel"); LoadBalancingStrategy lbStrategy = TestUtils.getPropertyValue(channel, "dispatcher.loadBalancingStrategy", LoadBalancingStrategy.class); assertTrue(lbStrategy instanceof SampleLoadBalancingStrategy); }
TestUtils.getPropertyValue()
is based on Spring’s DirectFieldAccessor
and provides the ability to get a value from the target private property.
As shown in the preceding example, it also supports nested properties access by using dotted notation.
The createTestApplicationContext()
factory method produces a TestApplicationContext
instance with the supplied Spring Integration environment.
See the Javadoc of other TestUtils
methods for more information about this class.
==== Using the SocketUtils
Class
The SocketUtils
class provides several methods that select one or more random ports for exposing server-side components without conflicts, as the following example shows:
<bean id="socketUtils" class="org.springframework.integration.test.util.SocketUtils" /> <int-syslog:inbound-channel-adapter id="syslog" channel="sysLogs" port="#{socketUtils.findAvailableUdpSocket(1514)}" /> <int:channel id="sysLogs"> <int:queue/> </int:channel>
The following example shows how the preceding configuration is used from the unit test:
@Autowired @Qualifier("syslog.adapter") private UdpSyslogReceivingChannelAdapter adapter; @Autowired private PollableChannel sysLogs; ... @Test public void testSimplestUdp() throws Exception { int port = TestUtils.getPropertyValue(adapter1, "udpAdapter.port", Integer.class); byte[] buf = "<157>JUL 26 22:08:35 WEBERN TESTING[70729]: TEST SYSLOG MESSAGE".getBytes("UTF-8"); DatagramPacket packet = new DatagramPacket(buf, buf.length, new InetSocketAddress("localhost", port)); DatagramSocket socket = new DatagramSocket(); socket.send(packet); socket.close(); Message<?> message = foo.receive(10000); assertNotNull(message); }
Note | |
---|---|
This technique is not foolproof.
Some other process could be allocated the " |
==== Using OnlyOnceTrigger
OnlyOnceTrigger
is useful for polling endpoints when you need to produce only one test message and verify the behavior without impacting other period messages.
The following example shows how to configure OnlyOnceTrigger
:
<bean id="testTrigger" class="org.springframework.integration.test.util.OnlyOnceTrigger" /> <int:poller id="jpaPoller" trigger="testTrigger"> <int:transactional transaction-manager="transactionManager" /> </int:poller>
The following example shows how to use the preceding configuration of OnlyOnceTrigger
for testing:
@Autowired @Qualifier("jpaPoller") PollerMetadata poller; @Autowired OnlyOnceTrigger testTrigger; ... @Test @DirtiesContext public void testWithEntityClass() throws Exception { this.testTrigger.reset(); ... JpaPollingChannelAdapter jpaPollingChannelAdapter = new JpaPollingChannelAdapter(jpaExecutor); SourcePollingChannelAdapter adapter = JpaTestUtils.getSourcePollingChannelAdapter( jpaPollingChannelAdapter, this.outputChannel, this.poller, this.context, this.getClass().getClassLoader()); adapter.start(); ... }
==== Support Components
The org.springframework.integration.test.support
package contains various abstract classes that you should implement in target tests
==== JUnit Rules and Conditions
The LongRunningIntegrationTest
JUnit 4 test rule is present to indicate if test should be run if RUN_LONG_INTEGRATION_TESTS
environment or system property is set to true
.
Otherwise it is skipped.
For the same reason since version 5.1, a @LongRunningTest
conditional annotation is provided for JUnit 5 tests.
==== Hamcrest and Mockito Matchers
The org.springframework.integration.test.matcher
package contains several Matcher
implementations to assert Message
and its properties in unit tests.
The following example shows how to use one such matcher (PayloadMatcher
):
import static org.springframework.integration.test.matcher.PayloadMatcher.hasPayload; ... @Test public void transform_withFilePayload_convertedToByteArray() throws Exception { Message<?> result = this.transformer.transform(message); assertThat(result, is(notNullValue())); assertThat(result, hasPayload(is(instanceOf(byte[].class)))); assertThat(result, hasPayload(SAMPLE_CONTENT.getBytes(DEFAULT_ENCODING))); }
The MockitoMessageMatchers
factory can be used for mocks for stubbing and verifications, as the following example shows:
static final Date SOME_PAYLOAD = new Date(); static final String SOME_HEADER_VALUE = "bar"; static final String SOME_HEADER_KEY = "test.foo"; ... Message<?> message = MessageBuilder.withPayload(SOME_PAYLOAD) .setHeader(SOME_HEADER_KEY, SOME_HEADER_VALUE) .build(); MessageHandler handler = mock(MessageHandler.class); handler.handleMessage(message); verify(handler).handleMessage(messageWithPayload(SOME_PAYLOAD)); verify(handler).handleMessage(messageWithPayload(is(instanceOf(Date.class)))); ... MessageChannel channel = mock(MessageChannel.class); when(channel.send(messageWithHeaderEntry(SOME_HEADER_KEY, is(instanceOf(Short.class))))) .thenReturn(true); assertThat(channel.send(message), is(false));
=== Spring Integration and the Test Context
Typically, tests for Spring applications use the Spring Test Framework.
Since Spring Integration is based on the Spring Framework foundation, everything we can do with the Spring Test Framework also applies when testing integration flows.
The org.springframework.integration.test.context
package provides some components for enhancing the test context for integration needs.
First of all, we configure our test class with a @SpringIntegrationTest
annotation to enable the Spring Integration Test Framework, as the following example shows:
@RunWith(SpringRunner.class) @SpringIntegrationTest(noAutoStartup = {"inboundChannelAdapter", "*Source*"}) public class MyIntegrationTests { @Autowired private MockIntegrationContext mockIntegrationContext; }
The @SpringIntegrationTest
annotation populates a MockIntegrationContext
bean, which you can autowire to the test class to access its methods.
With the noAutoStartup
option, the Spring Integration Test Framework prevents endpoints that are normally autoStartup=true
from starting. The endpoints are matched to the provided patterns, which support the following simple pattern styles: xxx*
, *xxx
, *xxx*
, and xxx*yyy
.
This is useful when we would like to not have real connections to the target systems from inbound channel adapters (for example an AMQP Inbound Gateway, JDBC Polling Channel Adapter, WebSocket Message Producer in client mode, and so on).
The MockIntegrationContext
is meant to be used in the target test cases for modifications to beans in the real application context.
For example, endpoints that have autoStartup
overridden to false
can be replaced with mocks, as the following example shows:
@Test public void testMockMessageSource() { MessageSource<String> messageSource = () -> new GenericMessage<>("foo"); this.mockIntegrationContext.substituteMessageSourceFor("mySourceEndpoint", messageSource); Message<?> receive = this.results.receive(10_000); assertNotNull(receive); }
Note | |
---|---|
The |
After test is performed you can restore the state of endpoint beans to the real configuration using MockIntegrationContext.resetBeans()
:
@After public void tearDown() { this.mockIntegrationContext.resetBeans(); }
See the Javadoc for more information.
The org.springframework.integration.test.mock
package offers tools and utilities for mocking, stubbing, and verification of activity on Spring Integration components.
The mocking functionality is fully based on and compatible with the well known Mockito Framework.
(The current Mockito transitive dependency is on version 2.5.x or higher.)
==== MockIntegration
The MockIntegration
factory provides an API to build mocks for Spring Integration beans that are parts of the integration flow (MessageSource
, MessageProducer
, MessageHandler
, and MessageChannel
).
You can use the target mocks during the configuration phase as well as in the target test method to replace the real endpoints before performing verifications and assertions, as the following example shows:
<int:inbound-channel-adapter id="inboundChannelAdapter" channel="results"> <bean class="org.springframework.integration.test.mock.MockIntegration" factory-method="mockMessageSource"> <constructor-arg value="a"/> <constructor-arg> <array> <value>b</value> <value>c</value> </array> </constructor-arg> </bean> </int:inbound-channel-adapter>
The following example shows how to use Java Configuration to achieve the same configuration as the preceding example:
@InboundChannelAdapter(channel = "results") @Bean public MessageSource<Integer> testingMessageSource() { return MockIntegration.mockMessageSource(1, 2, 3); } ... StandardIntegrationFlow flow = IntegrationFlows .from(MockIntegration.mockMessageSource("foo", "bar", "baz")) .<String, String>transform(String::toUpperCase) .channel(out) .get(); IntegrationFlowRegistration registration = this.integrationFlowContext.registration(flow) .register();
For this purpose, the aforementioned MockIntegrationContext
should be used from the test, as the following example shows:
this.mockIntegrationContext.substituteMessageSourceFor("mySourceEndpoint", MockIntegration.mockMessageSource("foo", "bar", "baz")); Message<?> receive = this.results.receive(10_000); assertNotNull(receive); assertEquals("FOO", receive.getPayload());
Unlike the Mockito MessageSource
mock object, the MockMessageHandler
is a regular AbstractMessageProducingHandler
extension with a chain API to stub handling for incoming messages.
The MockMessageHandler
provides handleNext(Consumer<Message<?>>)
to specify a one-way stub for the next request message.
It is used to mock message handlers that do not produce replies.
handleNextAndReply(Function<Message<?>, ?>)
is provided for performing the same stub logic for the next request message and producing a reply for it.
They can be chained to simulate any arbitrary request-reply scenarios for all expected request messages variants.
These consumers and functions are applied to the incoming messages, one at a time from the stack, until the last, which is then used for all remaining messages.
The behavior is similar to the Mockito Answer
or doReturn()
API.
In addition, you can supply a Mockito ArgumentCaptor<Message<?>>
to the MockMessageHandler
in a constructor argument.
Each request message for the MockMessageHandler
is captured by that ArgumentCaptor
.
During the test, you can use its getValue()
and getAllValues()
methods to verify and assert those request messages.
The MockIntegrationContext
provides a substituteMessageHandlerFor()
API that lets you replace the actual configured MessageHandler
with a MockMessageHandler
in the endpoint under test.
The following example shows a typical usage scenario:
ArgumentCaptor<Message<?>> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class); MessageHandler mockMessageHandler = mockMessageHandler(messageArgumentCaptor) .handleNextAndReply(m -> m.getPayload().toString().toUpperCase()); this.mockIntegrationContext.substituteMessageHandlerFor("myService.serviceActivator", mockMessageHandler); GenericMessage<String> message = new GenericMessage<>("foo"); this.myChannel.send(message); Message<?> received = this.results.receive(10000); assertNotNull(received); assertEquals("FOO", received.getPayload()); assertSame(message, messageArgumentCaptor.getValue());
See the MockIntegration
and MockMessageHandler
Javadoc for more information.
As well as exploring the test cases in the framework itself, the Spring Integration Samples repository has some sample applications specifically made to show testing, such as testing-examples
and advanced-testing-examples
.
In some cases, the samples themselves have comprehensive end-to-end tests, such as the file-split-ftp
sample.
As of Spring Integration 2.0, the Spring Integration distribution no longer includes the samples. Instead, we have switched to a much simpler collaborative model that should promote better community participation and, ideally, more contributions. Samples now have a dedicated Git repository and a dedicated JIRA Issue Tracking system. Sample development also has its own lifecycle, which is not dependent on the lifecycle of the framework releases, although the repository is still tagged with each major release for compatibility reasons.
The great benefit to the community is that we can now add more samples and make them available to you right away without waiting for the next release. Having its own JIRA that is not tied to the the actual framework is also a great benefit. You now have a dedicated place to suggest samples as well as report issues with existing samples. You can also submit a sample to us as an attachment through JIRA or, better, through the collaborative model that Git promotes. If we believe your sample adds value, we would be more then glad to add it to the samples repository, properly crediting you as the author.
The Spring Integration Samples project is hosted on GitHub. You can find the repository at:
https://github.com/SpringSource/spring-integration-samples
In order to check out or clone the samples, you must have a Git client installed on your system. There are several GUI-based products available for many platforms (such as EGit for the Eclipse IDE). A simple Google search can help you find them. You can also use the command line interface for <http://git-scm.com/,Git>.
Note | |
---|---|
If you need more information on how to install or use Git, visit: http://git-scm.com/. |
To clone (check out) the Spring Integration samples repository by using the Git command line tool, issue the following command:
$ git clone https://github.com/SpringSource/spring-integration-samples.git
The preceding command clones the entire samples repository into a directory named spring-integration-samples
within the working directory where you issued that git
command.
Since the samples repository is a live repository, you might want to perform periodic pulls (updates) to get new samples and updates to the existing samples.
To do so, issue the following git pull
command:
$ git pull
=== Submitting Samples or Sample Requests
You can submit both new samples and requests for samples. We greatly appreciate any effort toward improving the samples, including the sharing of good ideas.
==== How Can I Contribute My Own Samples?
Github is for social coding: if you want to submit your own code examples to the Spring Integration Samples project, we encourage contributions through pull requests from forks of this repository. If you want to contribute code this way, please reference, if possible, a JIRA ticket that provides some details regarding your sample.
Sign the contributor license agreement | |
---|---|
Very important: Before we can accept your Spring Integration sample, we need you to sign the SpringSource contributor license agreement (CLA). Signing the contributor’s agreement does not grant anyone commit rights to the main repository, but it does mean that we can accept your contributions, and you will get an author credit if we do. In order to read and sign the CLA, go to: https://support.springsource.com/spring_committer_signup From the Project drop down, select Spring Integration. The Project Lead is Gary Russell. |
==== Code Contribution Process
For the actual code contribution process, read the the Contributor Guidelines for Spring Integration. They apply for the samples project as well. You can find them at https://github.com/spring-projects/spring-integration/blob/master/CONTRIBUTING.md
This process ensures that every commit gets peer-reviewed. As a matter of fact, the core committers follow the exact same rules. We gratefully look forward to your Spring Integration samples!
==== Sample Requests
As mentioned earlier, the Spring Integration Samples project has a dedicated JIRA issue tracking system. To submit new sample requests, visit the JIRA Issue Tracking system at https://jira.springframework.org/browse/INTSAMPLES.
Starting with Spring Integration 2.0, the structure of the samples has changed. With plans for more samples, we realized that not all samples have the same goals. They all share the common goal of showing you how to apply and work with the Spring Integration framework. However, they differ in that some samples concentrate on a technical use case, while others focus on a business use case. Also, some samples are about showcasing various techniques that could be applied to address certain scenarios (both technical and business). The new categorization of samples lets us better organize them based on the problem each sample addresses while giving you a simpler way of finding the right sample for your needs.
Currently there are four categories. Within the samples repository, each category has its own directory, which is named after the category name:
samples/basic
)samples/basic
is a good place to get started.
samples/intermediate
)what else
" types of problems, this is the right place to find these type of samples.
samples/advanced
)samples/applications
)Important | |
---|---|
Spring Integration is a community-driven framework. Therefore community participation is IMPORTANT. That includes samples. If you cannot find what you are looking for, let us know! |
Currently, Spring Integration comes with quite a few samples and you can only expect more.
To help you better navigate through them, each sample comes with its own readme.txt
file which covers several details about the sample (for example, what EIP patterns it addresses, what problem it is trying to solve, how to run the sample, and other details).
However, certain samples require a more detailed and sometimes graphical explanation.
In this section, you can find details on samples that we believe require special attention.
This section covers the loan broker sample application that is included in the Spring Integration samples. This sample is inspired by one of the samples featured in Gregor Hohpe and Bobby Woolf’s book, Enterprise Integration Patterns.
The following diagram shows the entire process:
At the core of an EIP architecture are the very simple yet powerful concepts of pipes, filters, and, of course: messages. Endpoints (filters) are connected with one another via channels (pipes). Producing endpoints send messages to the channel, and the consuming endpoint retrieves the messages. This architecture is meant to define various mechanisms that describe how information is exchanged between the endpoints, without any awareness of what those endpoints are or what information they are exchanging. Thus, it provides for a very loosely coupled and flexible collaboration model while also decoupling integration concerns from business concerns. EIP extends this architecture by further defining:
Chapter 9 of the EIP book nicely describes the details and variations of this use case, but here is the brief summary: While shopping for the best loan quote, a consumer subscribes to the services of a loan broker, which handles such details as:
The real process of obtaining a loan quote is generally a bit more complex. However, since our goal is to demonstrate how Enterprise Integration Patterns are realized and implemented within Spring Integration, the use case has been simplified to concentrate only on the integration aspects of the process. It is not an attempt to give you advice in consumer finances.
By engaging a loan broker, the consumer is isolated from the details of the loan broker’s operations, and each loan broker’s operations may defer from one another to maintain competitive advantage, so whatever we assemble and implement must be flexible so that any changes could be introduced quickly and painlessly.
Note | |
---|---|
The loan broker sample does not actually talk to any imaginary Banks or Credit bureaus. Those services are stubbed out. |
Our goal here is to assemble, orchestrate, and test the integration aspects of the process as a whole. Only then can we start thinking about wiring such processes to the real services. At that time, the assembled process and its configuration do not change regardless of the number of banks with which a particular loan broker deals or the type of communication media (or protocols) used (JMS, WS, TCP, and so on) to communicate with these banks.
===== Design
As you analyze the six requirements listed earlier, you can see that they are all integration concerns. For example, in the consumer pre-screening step, we need to gather additional information about the consumer and the consumer’s desires and enrich the loan request with additional meta-information. We then have to filter such information to select the most appropriate list of banks and so on. Enrich, filter, and select are all integration concerns for which EIP defines a solution in the form of patterns. Spring Integration provides an implementation of these patterns.
The following image shows a representation of a messaging gateway:
The messaging gateway pattern provides a simple mechanism to access messaging systems, including our loan broker.
In Spring Integration, you can define the gateway as a plain old java interface (you need not provide an implementation), configure it with the XML <gateway>
element or with an annotation in Java, and use it as you would any other Spring bean.
Spring Integration takes care of delegating and mapping method invocations to the messaging infrastructure by generating a message (the payload is mapped to an input parameter of the method) and sending it to the designated channel.
The following example shows how to define such a gateway with XML:
<int:gateway id="loanBrokerGateway" default-request-channel="loanBrokerPreProcessingChannel" service-interface="org.springframework.integration.samples.loanbroker.LoanBrokerGateway"> <int:method name="getBestLoanQuote"> <int:header name="RESPONSE_TYPE" value="BEST"/> </int:method> </int:gateway>
Our current gateway provides two methods that could be invoked.
One that returns the best single quote and another one that returns all quotes.
Somehow, downstream, we need to know what type of reply the caller needs.
The best way to achieve this in messaging architecture is to enrich the content of the message with some metadata that describes your intentions.
Content Enricher is one of the patterns that addresses this.
Spring Integration does, as a convenience, provide a separate configuration element to enrich message headers with arbitrary data (described later)
However, since the gateway
element is responsible for constructing the initial message, it includes ability to enrich the newly created message with arbitrary message headers.
In our example, we add a RESPONSE_TYPE
header with a value of BEST
whenever the getBestQuote()
method is invoked.
For other methods, we do not add any header.
Now we can check downstream for the existence of this header.
Based on its presence and its value, we can determine what type of reply the caller wants.
Based on the use case, we also know tat some pre-screening steps need to be performed, such as getting and evaluating the consumer’s credit score, because some premiere banks only accept quote requests from consumers that meet a minimum credit score requirement. So it would be nice if the message would be enriched with such information before it is forwarded to the banks. It would also be nice if, when several processes need to be completed to provide such meta-information, those processes could be grouped in a single unit. In our use case, we need to determine the credit score and, based on the credit score and some rule, select a list of message channels (bank channels) to which to send quote request.
===== Composed Message Processor
The composed message processor pattern describes rules around building endpoints that maintain control over message flow, which consists of multiple message processors.
In Spring Integration, the composed message processor pattern is implemented by the <chain>
element.
The following image shows the chain pattern:
The preceding image shows that we have a chain with an inner header-enricher element that further enriches the content of the message with the CREDIT_SCORE
header and the value (which is determined by the call to a credit service — a simple POJO spring bean identified by creditBureau name).
Then it delegates to the message router.
The following image shows the message router pattern:
Spring Integration offers several implementations of the message routing pattern.
In this case, we use a router that determines a list of channels based on evaluating an expression (in Spring Expression Language) that looks at the credit score (determined in the previous step) and selects the list of channels from the Map
bean with an id
of banks
whose values are premier
or secondary
, based on the value of credit score.
Once the list of channels is selected, the message is routed to those channels.
Now, one last thing the loan broker needs to receive the loan quotes form the banks, aggregate them by consumer (we do not want to show quotes from one consumer to another), assemble the response based on the consumer’s selection criteria (single best quote or all quotes) and send the reply to the consumer.
The following image shows the message aggregator pattern:
An aggregator pattern describes an endpoint that groups related messages into a single message. Criteria and rules can be provided to determine an aggregation and correlation strategy. Spring Integration provides several implementations of the aggregator pattern as well as a convenient namespace-based configuration.
The following example shows how to define an aggregator:
<int:aggregator id="quotesAggregator" input-channel="quotesAggregationChannel" method="aggregateQuotes"> <beans:bean class="org.springframework.integration.samples.loanbroker.LoanQuoteAggregator"/> </int:aggregator>
Our Loan Broker defines a quotesAggregator bean with the <aggregator>
element, which provides a default aggregation and correlation strategy.
The default correlation strategy correlates messages based on the correlationId
header (see the correlation identifier pattern in the EIP book).
Note that we never provided the value for this header.
It was automatically set earlier by the router, when it generated a separate message for each bank channel.
Once the messages are correlated, they are released to the actual aggregator implementation.
Although Spring Integration provides a default aggregator, its strategy (gather the list of payloads from all messages and construct a new message with this list as its payload) does not satisfy our requirement.
Having all the results in the message is a problem, because our consumer might require a single best quote or all quotes.
To communicate the consumer’s intention, earlier in the process we set the RESPONSE_TYPE
header.
Now we have to evaluate this header and return either all the quotes (the default aggregation strategy would work) or the best quote (the default aggregation strategy does not work because we have to determine which loan quote is the best).
In a more realistic application, selecting the best quote might be based on complex criteria that might influence the complexity of the aggregator implementation and configuration.
For now, though, we are making it simple.
If the consumer wants the best quote, we select a quote with the lowest interest rate.
To accomplish that, the LoanQuoteAggregator
class sorts all the quotes by interest rate and returns the first one.
The LoanQuote
class implements Comparable
to compare quotes based on the rate attribute.
Once the response message is created, it is sent to the default reply channel of the messaging gateway (and, thus, to the consumer) that started the process.
Our consumer got the loan quote!
In conclusion, a rather complex process was assembled based on POJO (that is existing or legacy) logic and a light-weight, embeddable messaging framework (Spring Integration) with a loosely coupled programming model intended to simplify integration of heterogeneous systems without requiring a heavy-weight ESB-like engine or a proprietary development and deployment environment. As a developer, you should not need to port your Swing or console-based application to an ESB-like server or implement proprietary interfaces just because you have an integration concern.
This sample and the other samples in this section are built on top of Enterprise Integration Patterns.
You can consider them to be "building blocks
" for your solution.
They are not intended to be complete solutions.
Integration concerns exist in all types of application (whether server-based or not).
Our goal is to make is so that integrating applications does not require changes in design, testing, and deployment strategy.
This section covers the cafe sample application that is included in the Spring Integration samples. This sample is inspired by another sample featured in Gregor Hohpe’s Ramblings.
The domain is that of a cafe, and the following diagram depicts the basic flow:
The Order
object may contain multiple OrderItems
.
Once the order is placed, a splitter breaks the composite order message into a single message for each drink.
Each of these is then processed by a router that determines whether the drink is hot or cold (by checking the OrderItem
object’s isIced property).
The Barista
prepares each drink, but hot and cold drink preparation are handled by two distinct methods: prepareHotDrink and prepareColdDrink.
The prepared drinks are then sent to the Waiter
where they are aggregated into a Delivery
object.
The following listing shows the XML configuration:
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns:int="http://www.springframework.org/schema/integration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:int-stream="http://www.springframework.org/schema/integration/stream" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd http://www.springframework.org/schema/integration/stream http://www.springframework.org/schema/integration/stream/spring-integration-stream.xsd"> <int:gateway id="cafe" service-interface="o.s.i.samples.cafe.Cafe"/> <int:channel id="orders"/> <int:splitter input-channel="orders" ref="orderSplitter" method="split" output-channel="drinks"/> <int:channel id="drinks"/> <int:router input-channel="drinks" ref="drinkRouter" method="resolveOrderItemChannel"/> <int:channel id="coldDrinks"><int:queue capacity="10"/></int:channel> <int:service-activator input-channel="coldDrinks" ref="barista" method="prepareColdDrink" output-channel="preparedDrinks"/> <int:channel id="hotDrinks"><int:queue capacity="10"/></int:channel> <int:service-activator input-channel="hotDrinks" ref="barista" method="prepareHotDrink" output-channel="preparedDrinks"/> <int:channel id="preparedDrinks"/> <int:aggregator input-channel="preparedDrinks" ref="waiter" method="prepareDelivery" output-channel="deliveries"/> <int-stream:stdout-channel-adapter id="deliveries"/> <beans:bean id="orderSplitter" class="org.springframework.integration.samples.cafe.xml.OrderSplitter"/> <beans:bean id="drinkRouter" class="org.springframework.integration.samples.cafe.xml.DrinkRouter"/> <beans:bean id="barista" class="o.s.i.samples.cafe.xml.Barista"/> <beans:bean id="waiter" class="o.s.i.samples.cafe.xml.Waiter"/> <int:poller id="poller" default="true" fixed-rate="1000"/> </beans:beans>
Each message endpoint connects to input channels, output channels, or both.
Each endpoint manages its own lifecycle (by default, endpoints start automatically upon initialization, to prevent that, add the auto-startup
attribute with a value of false
).
Most importantly, notice that the objects are simple POJOs with strongly typed method arguments.
The following example shows the Splitter:
public class OrderSplitter { public List<OrderItem> split(Order order) { return order.getItems(); } }
In the case of the router, the return value does not have to be a MessageChannel
instance (although it can be).
In this example, a String
value that holds the channel name is returned instead, as the following listing shows.
public class DrinkRouter { public String resolveOrderItemChannel(OrderItem orderItem) { return (orderItem.isIced()) ? "coldDrinks" : "hotDrinks"; } }
Now, turning back to the XML, you can see that there are two <service-activator>
elements.
Each of these is delegating to the same Barista
instance but with different methods (prepareHotDrink
or prepareColdDrink
), each corresponding to one of the two channels where order items have been routed.
The following listing shows the Barista class (which contains the prepareHotDrink
and prepareColdDrink
methods)
public class Barista { private long hotDrinkDelay = 5000; private long coldDrinkDelay = 1000; private AtomicInteger hotDrinkCounter = new AtomicInteger(); private AtomicInteger coldDrinkCounter = new AtomicInteger(); public void setHotDrinkDelay(long hotDrinkDelay) { this.hotDrinkDelay = hotDrinkDelay; } public void setColdDrinkDelay(long coldDrinkDelay) { this.coldDrinkDelay = coldDrinkDelay; } public Drink prepareHotDrink(OrderItem orderItem) { try { Thread.sleep(this.hotDrinkDelay); System.out.println(Thread.currentThread().getName() + " prepared hot drink #" + hotDrinkCounter.incrementAndGet() + " for order #" + orderItem.getOrder().getNumber() + ": " + orderItem); return new Drink(orderItem.getOrder().getNumber(), orderItem.getDrinkType(), orderItem.isIced(), orderItem.getShots()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return null; } } public Drink prepareColdDrink(OrderItem orderItem) { try { Thread.sleep(this.coldDrinkDelay); System.out.println(Thread.currentThread().getName() + " prepared cold drink #" + coldDrinkCounter.incrementAndGet() + " for order #" + orderItem.getOrder().getNumber() + ": " + orderItem); return new Drink(orderItem.getOrder().getNumber(), orderItem.getDrinkType(), orderItem.isIced(), orderItem.getShots()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return null; } } }
As you can see from the preceding code excerpt, the Barista
methods have different delays (the hot drinks take five times as long to prepare).
This simulates work being completed at different rates.
When the CafeDemo
main method runs, it loops 100 times and sends a single hot drink and a single cold drink each time.
It actually sends the messages by invoking the placeOrder method on the Cafe
interface.
In the earlier XML configuration, you can see that the <gateway>
element is specified.
This triggers the creation of a proxy that implements the given service interface and connects it to a channel.
The channel name is provided on the @Gateway
annotation of the Cafe
interface, as the following interface definition shows:
public interface Cafe { @Gateway(requestChannel="orders") void placeOrder(Order order); }
Finally, have a look at the main()
method of the CafeDemo
itself:
public static void main(String[] args) { AbstractApplicationContext context = null; if (args.length > 0) { context = new FileSystemXmlApplicationContext(args); } else { context = new ClassPathXmlApplicationContext("cafeDemo.xml", CafeDemo.class); } Cafe cafe = context.getBean("cafe", Cafe.class); for (int i = 1; i <= 100; i++) { Order order = new Order(i); order.addItem(DrinkType.LATTE, 2, false); order.addItem(DrinkType.MOCHA, 3, true); cafe.placeOrder(order); } }
Tip | |
---|---|
To run this sample as well as eight others, refer to the |
When you run cafeDemo
, you can see that the cold drinks are initially prepared more quickly than the hot drinks.
Because there is an aggregator, the cold drinks are effectively limited by the rate of the hot drink preparation.
This is to be expected, based on their respective delays of 1000 and 5000 milliseconds.
However, by configuring a poller with a concurrent task executor, you can dramatically change the results.
For example, you could use a thread pool executor with five workers for the hot drink barista while keeping the cold drink barista as it is.
The following listing configures such an arrangement:
<int:service-activator input-channel="hotDrinks" ref="barista" method="prepareHotDrink" output-channel="preparedDrinks"/> <int:service-activator input-channel="hotDrinks" ref="barista" method="prepareHotDrink" output-channel="preparedDrinks"> <int:poller task-executor="pool" fixed-rate="1000"/> </int:service-activator> <task:executor id="pool" pool-size="5"/>
Also, notice that the worker thread name is displayed with each invocation. You can see that the hot drinks are prepared by the task-executor threads. If you provide a much shorter poller interval (such as 100 milliseconds), you can see that it occasionally throttles the input by forcing the task scheduler (the caller) to invoke the operation.
Note | |
---|---|
In addition to experimenting with the poller’s concurrency settings, you can also add the transactional child element and then refer to any |
The XML messaging sample in basic/xml
shows how to use some of the provided components that deal with XML payloads.
The sample uses the idea of processing an order for books represented as XML.
Note | |
---|---|
This sample shows that the namespace prefix can be whatever you want.
While we usually use, |
First, the order is split into a number of messages, each one representing a single order item from the XPath splitter component. The following listing shows the configuration of the splitter:
<si-xml:xpath-splitter id="orderItemSplitter" input-channel="ordersChannel" output-channel="stockCheckerChannel" create-documents="true"> <si-xml:xpath-expression expression="/orderNs:order/orderNs:orderItem" namespace-map="orderNamespaceMap" /> </si-xml:xpath-splitter>
A service activator then passes the message into a stock checker POJO.
The order item document is enriched with information from the stock checker about the order item stock level.
This enriched order item message is then used to route the message.
In the case where the order item is in stock, the message is routed to the warehouse.
The following listing configures the xpath-router
that routes the messages:
<si-xml:xpath-router id="instockRouter" input-channel="orderRoutingChannel" resolution-required="true"> <si-xml:xpath-expression expression="/orderNs:orderItem/@in-stock" namespace-map="orderNamespaceMap" /> <si-xml:mapping value="true" channel="warehouseDispatchChannel"/> <si-xml:mapping value="false" channel="outOfStockChannel"/> </si-xml:xpath-router>
When the order item is not in stock, the message is transformed with XSLT into a format suitable for sending to the supplier. The following listing configures the XSLT transformer:
<si-xml:xslt-transformer input-channel="outOfStockChannel" output-channel="resupplyOrderChannel" xsl-resource="classpath:org/springframework/integration/samples/xml/bigBooksSupplierTransformer.xsl"/>
The definitive source of information about Spring Integration is the Spring Integration Home at http://spring.io. That site serves as a hub of information and is the best place to find up-to-date announcements about the project as well as links to articles, blogs, and new sample applications.
=== Changes between 4.3 and 5.0
See the Migration Guide for important changes that might affect your applications. You can find migration guides for all versions back to 2.1 on the wiki.
Version 5.0 added a number of new components.
==== Java DSL
The separate Spring Integration Java DSL project has now been merged into the core Spring Integration project.
The IntegrationComponentSpec
implementations for channel adapters and gateways are distributed to their specific modules.
See Chapter 11, Java DSL for more information about Java DSL support.
See also the 4.3 to 5.0 Migration Guide for the required steps to move to Spring Integration 5.0.
==== Testing Support
We created a new Spring Integration Test Framework to help with testing Spring Integration applications.
Now, with the @SpringIntegrationTest
annotation on test classes and the MockIntegration
factory, you can make your JUnit tests for integration flows somewhat easier.
See Section E.4, “Global Properties” for more information.
==== MongoDB Outbound Gateway
The new MongoDbOutboundGateway
lets you make queries to the database on demand by sending a message to its request channel.
See Section 25.5, “MongoDB Outbound Gateway” for more information.
==== WebFlux Gateways and Channel Adapters
We introduced the new WebFlux support module for Spring WebFlux Framework gateways and channel adapters.
See Chapter 35, WebFlux Support for more information.
==== Content Type Conversion
Now that we use the new InvocableHandlerMethod
-based infrastructure for service method invocations, we can perform contentType
conversion from the payload to a target method argument.
See Section 10.1.7, “Content Type Conversion” for more information.
==== ErrorMessagePublisher
and ErrorMessageStrategy
We added ErrorMessagePublisher
and the ErrorMessageStrategy
for creating ErrorMessage
instances.
See Section E.3, “Error Handling” for more information.
==== JDBC Metadata Store
We added a JDBC implementation of the MetadataStore
implementation.
This is useful when you need to ensure transactional boundaries for metadata.
See Section 21.7, “JDBC Metadata Store” for more information.
Spring Integration is now fully based on Spring Framework 5.0
and Project Reactor 3.1
.
Previous Project Reactor versions are no longer supported.
==== Core Changes
The @Poller
annotation now has the errorChannel
attribute for easier configuration of the underlying MessagePublishingErrorHandler
.
See Section E.4, “Global Properties” for more information.
All the request-reply endpoints (based on AbstractReplyProducingMessageHandler
) can now start transactions and, therefore, make the whole downstream flow transactional.
See Section 10.9.5, “Transaction Support” for more information.
The SmartLifecycleRoleController
now provides methods to obtain status of endpoints in roles.
See Section 10.2, “Endpoint Roles” for more information.
By default, POJO methods are now invoked by using an InvocableHandlerMethod
, but you can configure them to use SpEL, as before.
See Section 5.8, “POJO Method invocation” for more information.
When targeting POJO methods as message handlers, you can now mark one of the service methods with the @Default
annotation to provide a fallback mechanism for non-matched conditions.
See Section 10.5.1, “Configuring Service Activator” for more information.
We added a simple PassThroughTransactionSynchronizationFactory
to always store a polled message in the current transaction context.
That message is used as a failedMessage
property of the MessagingException
, which wraps any raw exception thrown during transaction completion.
See Section C.3, “Transaction Synchronization” for more information.
The aggregator expression-based ReleaseStrategy
now evaluates the expression against the MessageGroup
instead of just the collection of Message<?>
.
See the section called “Aggregators and Spring Expression Language (SpEL)” for more information.
You can now supply the ObjectToMapTransformer
with a customized JsonObjectMapper
.
See the section called “Aggregators and Spring Expression Language (SpEL)” for more information.
The @GlobalChannelInterceptor
annotation and <int:channel-interceptor>
now support negative patterns (via !
prepending) for component names matching.
See the section called “Global Channel Interceptor Configuration” for more information.
When a candidate failed to acquire the lock, the LockRegistryLeaderInitiator
now emits a new OnFailedToAcquireMutexEvent
through DefaultLeaderEventPublisher
.
See <<leadership-event-handling>>
for more information.
==== Gateway Changes
When the gateway method has a void
return type and an error channel is provided, the gateway now correctly sets the errorChannel
header.
Previously, the header was not populated.
This caused synchronous downstream flows (running on the calling thread) to send the exception to the configured channel, but an exception on an asynchronous downstream flow would be sent to the default errorChannel
instead.
The RequestReplyExchanger
interface now has a throws MessagingException
clause to meet the proposed messages exchange contract.
You can now specify the request and reply timeouts with SpEL expressions. See Section 10.4, “Messaging Gateways” for more information.
==== Aggregator Performance Changes
By default, aggregators now use a SimpleSequenceSizeReleaseStrategy
, which is more efficient, especially with large groups.
Empty groups are now scheduled for removal after empty-group-min-timeout
.
See Section 8.4, “Aggregator” for more information.
==== Splitter Changes
The splitter component can now handle and split Java Stream
and Reactive Streams Publisher
objects.
If the output channel is a ReactiveStreamsSubscribableChannel
, the AbstractMessageSplitter
builds a Flux
for subsequent iteration instead of a regular Iterator
, independent of the object being split.
In addition, AbstractMessageSplitter
provides protected obtainSizeIfPossible()
methods to allow determination of the size of the Iterable
and Iterator
objects, if that is possible.
See Section 8.3, “Splitter” for more information.
==== JMS Changes
Previously, Spring Integration JMS XML configuration used a default bean name of connectionFactory
for the JMS connection factory, letting the property be omitted from component definitions.
We renamed it to jmsConnectionFactory
, which is the bean name used by Spring Boot to auto-configure the JMS connection factory bean.
If your application relies on the previous behavior, you can rename your connectionFactory
bean to jmsConnectionFactory
or specifically configure your components to use your bean by using its current name.
See Chapter 23, JMS Support for more information.
==== Mail Changes
Some inconsistencies with rendering IMAP mail content have been resolved.
See the note in the "Mail-receiving Channel Adapter
" section for more information.
==== Feed Changes
Instead of the com.rometools.fetcher.FeedFetcher
, which is deprecated in ROME, we introduced a new Resource
property for the FeedEntryMessageSource
.
See Chapter 16, Feed Adapter for more information.
==== File Changes
We introduced the new FileHeaders.RELATIVE_PATH
message header to represent relative path in FileReadingMessageSource
.
The tail adapter now supports idleEventInterval
to emit events when there is no data in the file during that period.
The flush predicates for the FileWritingMessageHandler
now have an additional parameter.
The file outbound channel adapter and gateway (FileWritingMessageHandler
) now support the REPLACE_IF_MODIFIED
FileExistsMode
.
They also now support setting file permissions on the newly written file.
A new FileSystemMarkerFilePresentFileListFilter
is now available.
See Section 17.1.9, “Dealing With Incomplete Data” for more information.
The FileSplitter
now provides a firstLineAsHeader
option to carry the first line of content as a header in the messages emitted for the remaining lines.
See Chapter 17, File Support for more information.
==== FTP and SFTP Changes
The inbound channel adapters now have a property called max-fetch-size
, which is used to limit the number of files fetched during a poll when no files are currently in the local directory.
By default, they also are configured with a FileSystemPersistentAcceptOnceFileListFilter
in the local-filter
.
You can also provide a custom DirectoryScanner
implementation to inbound channel adapters by setting the newly introduced scanner
attribute.
You can now configure the regex and pattern filters to always pass directories. This can be useful when you use recursion in the outbound gateways.
By default, all the inbound channel adapters (streaming and synchronization-based) now use an appropriate AbstractPersistentAcceptOnceFileListFilter
implementation to prevent duplicate downloads of remote files.
The FTP and SFTP outbound gateways now support the REPLACE_IF_MODIFIED
FileExistsMode
when fetching remote files.
The FTP and SFTP streaming inbound channel adapters now add remote file information in a message header.
The FTP and SFTP outbound channel adapters (as well as the PUT
command for outbound gateways) now support InputStream
as payload
, too.
The inbound channel adapters can now build file trees locally by using a newly introduced RecursiveDirectoryScanner
.
See the scanner
option in the Section 18.4, “FTP Inbound Channel Adapter” section for injection.
Also, you can now switch these adapters to the WatchService
instead.
We added The NLST
command to the AbstractRemoteFileOutboundGateway
to perform the list files names remote command.
You can now supply the FtpOutboundGateway
with workingDirExpression
to change the FTP client working directory for the current request message.
The RemoteFileTemplate
is supplied now with the invoke(OperationsCallback<F, T> action)
to perform several RemoteFileOperations
calls in the scope of the same, thread-bounded, Session
.
We added new filters for detecting incomplete remote files.
The FtpOutboundGateway
and SftpOutboundGateway
now support an option to remove the remote file after a successful transfer by using the GET
or MGET
commands.
See Chapter 18, FTP/FTPS Adapters and Chapter 30, SFTP Adapters for more information.
==== Integration Properties
Version 4.3.2 added a new spring.integration.readOnly.headers
global property to let you customize the list of headers that should not be copied to a newly created Message
by the MessageBuilder
.
See Section E.4, “Global Properties” for more information.
==== Stream Changes
We added a new option on the CharacterStreamReadingMessageSource
to let it be used to "pipe
" stdin and publish an application event when the pipe is closed.
See Section 32.1, “Reading from Streams” for more information.
==== Barrier Changes
The BarrierMessageHandler
now supports a discard channel to which late-arriving trigger messages are sent.
See Section 8.8, “Thread Barrier” for more information.
==== AMQP Changes
The AMQP outbound endpoints now support setting a delay expression when you use the RabbitMQ Delayed Message Exchange plugin.
The inbound endpoints now support the Spring AMQP DirectMessageListenerContainer
.
Pollable AMQP-backed channels now block the poller thread for the poller’s configured receiveTimeout
(default: one second).
Headers, such as contentType
, that are added to message properties by the message converter are now used in the final message.
Previously, it depended on the converter type as to which headers and message properties appeared in the final message.
To override the headers set by the converter, set the headersMappedLast
property to true
.
See Chapter 14, AMQP Support for more information.
==== HTTP Changes
By default, the DefaultHttpHeaderMapper.userDefinedHeaderPrefix
property is now an empty string instead of X-
.
See Section 20.7, “HTTP Header Mappings” for more information.
By default, uriVariablesExpression
now uses a SimpleEvaluationContext
(since 5.0.4).
See Section 20.3.7, “Mapping URI Variables” for more information.
==== MQTT Changes
Inbound messages are now mapped with the RECEIVED_TOPIC
, RECEIVED_QOS
, and RECEIVED_RETAINED
headers to avoid inadvertent propagation to outbound messages when an application relays messages.
The outbound channel adapter now supports expressions for the topic, qos, and retained properties. The defaults remain the same. See Chapter 26, MQTT Support for more information.
==== STOMP Changes
We changed the STOMP module to use ReactorNettyTcpStompClient
, based on the Project Reactor 3.1
and reactor-netty
extension.
We renamed Reactor2TcpStompSessionManager
to ReactorNettyTcpStompSessionManager
, according to the ReactorNettyTcpStompClient
foundation.
See Chapter 31, STOMP Support for more information.
==== Web Services Changes
You can now supply WebServiceOutboundGateway
instances with an externally configured WebServiceTemplate
instances.
DefaultSoapHeaderMapper
can now map a javax.xml.transform.Source
user-defined header to a SOAP header element.
Simple WebService inbound and outbound gateways can now deal with the complete WebServiceMessage
as a payload
, allowing the manipulation of MTOM attachments.
See Chapter 37, Web Services Support for more information.
==== Redis Changes
The RedisStoreWritingMessageHandler
is supplied now with additional String
-based setters for SpEL expressions (for convenience with Java configuration).
You can now configure the zsetIncrementExpression
on the RedisStoreWritingMessageHandler
as well.
In addition, this property has been changed from true
to false
since the INCR
option on ZADD
Redis command is optional.
You can now supply the RedisInboundChannelAdapter
with an Executor
for executing Redis listener invokers.
In addition, the received messages now contain a RedisHeaders.MESSAGE_SOURCE
header to indicate the source of the message (topic or pattern).
See Chapter 27, Redis Support for more information.
==== TCP Changes
We added a new ThreadAffinityClientConnectionFactory
to bind TCP connections to threads.
You can now configure the TCP connection factories to support PushbackInputStream
instances, letting deserializers "unread
" (push back) bytes after "reading ahead
".
We added a ByteArrayElasticRawDeserializer
without maxMessageSize
to control and buffer incoming data as needed.
See Chapter 34, TCP and UDP Support for more information.
==== Gemfire Changes
The GemfireMetadataStore
now implements ListenableMetadataStore
, letting you listen to cache events by providing MetadataStoreListener
instances to the store.
See Chapter 19, Pivotal GemFire and Apache Geode Support for more information.
==== JDBC Changes
The JdbcMessageChannelStore
now provides a setter for ChannelMessageStorePreparedStatementSetter
, letting you customize message insertion in the store.
The ExpressionEvaluatingSqlParameterSourceFactory
now provides a setter for sqlParameterTypes
, letting you customize the SQL types of the parameters.
See Chapter 21, JDBC Support for more information.
==== Metrics Changes
Micrometer application monitoring is now supported (since version 5.0.2). See Section 12.1.2, “Micrometer Integration” for more information.
Important | |
---|---|
Changes were made to the Micrometer |
==== @EndpointId
Annotations
Introduced in version 5.0.4, this annotation provides control over bean naming when you use Java configuration. See Section 5.4.8, “Endpoint Bean Names” for more information.
=== Changes between 4.2 and 4.3
See the Migration Guide for important changes that might affect your applications. You can find migration guides for all versions back to 2.1 on the Wiki.
Version 4.3 added a number of new components.
==== AMQP Async Outbound Gateway
See Section 14.7, “Asynchronous Outbound Gateway”.
==== MessageGroupFactory
We introduced the MessageGroupFactory
strategy to allow control over MessageGroup
instances in MessageGroupStore
logic.
We added SimpleMessageGroupFactory
implementation for the SimpleMessageGroup
, with the GroupType.HASH_SET
as the default
factory for the standard MessageGroupStore
implementations.
See Section 12.4, “Message Store” for more information.
==== PersistentMessageGroup
We added the PersistentMessageGroup
(lazy-load proxy) implementation for persistent MessageGroupStore
instances,
which return this instance for the getMessageGroup()
when their lazyLoadMessageGroups
is true
(the default).
See Section 12.4, “Message Store” for more information.
==== FTP and SFTP Streaming Inbound Channel Adapters
We added inbound channel adapters that return an InputStream
for each file, letting you retrieve remote files without writing them to the local file system.
See Section 18.5, “FTP Streaming Inbound Channel Adapter” and Section 30.7, “SFTP Streaming Inbound Channel Adapter” for more information.
==== StreamTransformer
We added StreamTransformer
to transform an InputStream
payload to either a byte[]
or a String
.
See the section called “Stream Transformer” for more information.
==== Integration Graph
We added IntegrationGraphServer
, together with the IntegrationGraphController
REST service, to expose the runtime model of a Spring Integration application as a graph.
See Section 12.8, “Integration Graph” for more information.
==== JDBC Lock Registry
We added JdbcLockRegistry
for distributed locks shared through a database table.
See Section 21.6, “JDBC Lock Registry” for more information.
==== LeaderInitiator
for LockRegistry
We added LeaderInitiator
implementation based on the LockRegistry
strategy.
See Section 10.3, “Leadership Event Handling” for more information.
This section describes general changes that version 4.3 brought to Spring Integration.
==== Core Changes
This section describes general changes to the core of Spring Integration.
===== Outbound Gateway within a Chain
Previously, you could specify a reply-channel
on an outbound gateway within a chain.
It was completely ignored.
The gateway’s reply goes to the next chain element or, if the gateway is the last element, to the chain’s output channel.
This condition is now detected and disallowed.
If you have such a configuration, remove the reply-channel
.
===== Asynchronous Service Activator
We added an option to make the service activator be synchronous. See Section 10.5.2, “Asynchronous Service Activator” for more information.
===== Messaging Annotation Support changes
The messaging annotation support does not require a @MessageEndpoint
(or any other @Component
) annotation declaration on the class level.
To restore the previous behavior, set the spring.integration.messagingAnnotations.require.componentAnnotation
of
spring.integration.properties
to true
.
See Section E.4, “Global Properties” and Section E.4, “Global Properties” for more information.
==== Mail Changes
This section describes general changes to the Spring Integration Mail functionality.
===== Customizable User Flag
The customizable userFlag
(added in 4.2.2 to provide customization of the flag used to denote that the mail has been
seen) is now available in the XML namespace.
See Section 24.5, “Marking IMAP Messages When \Recent
Is Not Supported” for more information.
===== Mail Message Mapping
You can now map inbound mail messages with the MessageHeaders
containing the mail headers and the payload containing the email content.
Previously, the payload was always the raw MimeMessage
.
See Section 24.3, “Inbound Mail Message Mapping” for more information.
==== JMS Changes
This section describes general changes to the Spring Integration JMS functionality.
===== Header Mapper
The DefaultJmsHeaderMapper
now maps the standard correlationId
header as a message property by invoking its toString()
method.
See Section 23.6, “Mapping Message Headers to and from JMS Message” for more information.
===== Asynchronous Gateway
The JMS outbound gateway now has an async
property.
See Section 23.5.4, “Async Gateway” for more information.
==== Aggregator Changes
There is a change in behavior when a POJO aggregator releases a collection of Message<?>
objects.
This is rare, but, if your application does that, you need to make a small change to your POJO.
See this Important note for more information.
==== TCP/UDP Changes
This section describes general changes to the Spring Integration TCP/UDP functionality.
===== Events
A new TcpConnectionServerListeningEvent
is emitted when a server connection factory is started.
See Section 34.5, “TCP Connection Events” for more information.
You can now use the destination-expression
and socket-expression
attributes on <int-ip:udp-outbound-channel-adapter>
.
See Section 34.2, “UDP Adapters” for more information.
===== Stream Deserializers
The various deserializers that cannot allocate the final buffer until the whole message has been assembled now support pooling the raw buffer into which the data is received rather than creating and discarding a buffer for each message. See Section 34.3, “TCP Connection Factories” for more information.
===== TCP Message Mapper
The message mapper now, optionally, sets a configured content type header. See Section 34.13, “IP Message Headers” for more information.
==== File Changes
This section describes general changes to the Spring Integration File functionality.
===== Destination Directory Creation
The generated file name for the FileWritingMessageHandler
can represent a sub-path to save the desired directory structure for a file in the target directory.
See Section 17.2.1, “Generating File Names” for more information.
The FileReadingMessageSource
now hides the WatchService
directory scanning logic in the inner class.
We added the use-watch-service
and watch-events
options to enable this behavior.
We deprecated the top-level WatchServiceDirectoryScanner
because of inconsistency around the API.
See Section 17.1.4, “WatchServiceDirectoryScanner
” for more information.
===== Buffer Size
When writing files, you can now specify the buffer size.
===== Appending and Flushing
You can now avoid flushing files when appending and use a number of strategies to flush the data during idle periods.
See Section 17.2.4, “Flushing Files When Using APPEND_NO_FLUSH
” for more information.
===== Preserving Timestamps
You can now configure the outbound channel adapter to set the destination file’s lastmodified
timestamp.
See Section 17.2.5, “File Timestamps” for more information.
===== Splitter Changes
The FileSplitter
now automatically closes an FTP or SFTP session when the file is completely read.
This applies when the outbound gateway returns an InputStream
or when you use the new FTP or SFTP streaming channel adapters.
We also introduced a new markers-json
option to convert FileSplitter.FileMarker
to JSON String
for relaxed downstream network interaction.
See Section 17.4, “File Splitter” for more information.
===== File Filters
We added ChainFileListFilter
as an alternative to CompositeFileListFilter
.
See Section 17.1, “Reading Files” for more information.
==== AMQP Changes
This section describes general changes to the Spring Integration AMQP functionality.
===== Content Type Message Converter
The outbound endpoints now support a RabbitTemplate
configured with a ContentTypeDelegatingMessageConverter
such
that you can choose the converter based on the message content type.
See Section 14.8, “Outbound Message Conversion” for more information.
===== Headers for Delayed Message Handling
Spring AMQP 1.6 adds support for delayed message exchanges.
Header mapping now supports the headers (amqp_delay
and amqp_receivedDelay
) used by this feature.
===== AMQP-Backed Channels
AMQP-backed channels now support message mapping. See Section 14.11, “AMQP-backed Message Channels” for more information.
==== Redis Changes
This section describes general changes to the Spring Integration Redis functionality.
===== List Push/Pop Direction
Previously, the queue channel adapters always used the Redis list in a fixed direction, pushing to the left end and reading from the right end.
You can now configure the reading and writing direction with the rightPop
and leftPush
options for the
RedisQueueMessageDrivenEndpoint
and RedisQueueOutboundChannelAdapter
, respectively.
See Section 27.2.4, “Redis Queue Inbound Channel Adapter” and Section 27.2.5, “Redis Queue Outbound Channel Adapter” for more information.
===== Queue Inbound Gateway Default Serializer
The default serializer in the inbound gateway has been changed to a JdkSerializationRedisSerializer
for compatibility with the outbound gateway.
See Section 27.9, “Redis Queue Inbound Gateway” for more information.
==== HTTP Changes
Previously, with requests that had a body (such as POST
) that had no content-type
header, the body was ignored.
With this release, the content type of such requests is considered to be application/octet-stream
as recommended
by RFC 2616.
See Section 20.1, “Http Inbound Components” for more information.
uriVariablesExpression
now uses a SimpleEvaluationContext
by default (since 4.3.15).
See Section 20.3.7, “Mapping URI Variables” for more information.
==== SFTP Changes
This section describes general changes to the Spring Integration SFTP functionality.
===== Factory Bean
We added a new factory bean to simplify the configuration of Jsch proxies for SFTP. See Section 30.2, “Proxy Factory Bean” for more information.
===== chmod
Changes
The SFTP outbound gateway (for put
and mput
commands) and the SFTP outbound channel adapter now support the chmod
attribute to change the remote file permissions after uploading.
See <<sftp-outbound>>
and <<sftp-outbound-gateway>>
for more information.
==== FTP Changes
This section describes general changes to the Spring Integration FTP functionality.
===== Session Changes
The FtpSession
now supports null
for the list()
and listNames()
methods, since underlying FTP Client can use it.
With that, you can now configure the FtpOutboundGateway
without the remoteDirectory
expression.
You can also configure the <int-ftp:inbound-channel-adapter>
without remote-directory
or remote-directory-expression
.
See Chapter 18, FTP/FTPS Adapters for more information.
==== Router Changes
The ErrorMessageExceptionTypeRouter
now supports the Exception
superclass mappings to avoid duplication for the same channel in case of multiple inheritors.
For this purpose, the ErrorMessageExceptionTypeRouter
loads mapping classes during initialization to fail-fast for a ClassNotFoundException
.
See Section 8.1, “Routers” for more information.
==== Header Mapping
This section describes the changes to header mapping between version 4.2 and 4.3.
===== General
AMQP, WS, and XMPP header mappings (such as request-header-mapping
and reply-header-mapping
) now support negated patterns.
See Section 14.12, “AMQP Message Headers”, Section 37.5, “WS Message Headers”, and Section 39.5, “XMPP Message Headers” for more information.
===== AMQP Header Mapping
Previously, only standard AMQP headers were mapped by default.
You had to explicitly enable mapping of user-defined headers.
With this release, all headers are mapped by default.
In addition, the inbound amqp_deliveryMode
header is no longer mapped by default.
See Section 14.12, “AMQP Message Headers” for more information.
==== Groovy Scripts
You can now configure groovy scripts with the compile-static
hint or any other CompilerConfiguration
options.
See Section 10.8.1, “Groovy Configuration” for more information.
==== @InboundChannelAdapter
Changes
The @InboundChannelAdapter
now has an alias channel
attribute for the regular value
.
In addition, the target SourcePollingChannelAdapter
components can now resolve the target outputChannel
bean from its provided name (outputChannelName
options) in a late-binding manner.
See Section E.4, “Global Properties” for more information.
==== XMPP Changes
The XMPP channel adapters now support the XMPP Extensions (XEP). See Section 39.6, “XMPP Extensions” for more information.
==== WireTap Late Binding
The WireTap
ChannelInterceptor
now can accept a channelName
that is resolved to the target MessageChannel
later, during the first active interceptor operation.
See the section called “Wire Tap” for more information.
==== ChannelMessageStoreQueryProvider
Changes
The ChannelMessageStoreQueryProvider
now supports H2 databases.
See Section 21.4.3, “Backing Message Channels” for more information.
==== WebSocket Changes
The ServerWebSocketContainer
now exposes an allowedOrigins
option, and SockJsServiceOptions
exposes a suppressCors
option.
See Chapter 36, WebSockets Support for more information.
=== Changes between 4.1 and 4.2
See the Migration Guide for important changes that might affect your applications. You can find migration guides for all versions back to 2.1 on the wiki.
Version 4.2 added a number of new components.
==== Major Management/JMX Rework
We added a new MetricsFactory
strategy interface.
This change, together with other changes in the JMX and management infrastructure, provides much more control over management configuration and runtime performance.
However, this has some important implications for (some) user environments.
For complete details, see Section 12.1, “Metrics and Management” and the section called “JMX Improvements”.
The MongoDbMetadataStore
is now available.
For more information, see Section 25.2.2, “MongoDB Metadata Store”.
==== SecuredChannel Annotation
We introduced the @SecuredChannel
annotation, replacing the deprecated ChannelSecurityInterceptorFactoryBean
.
For more information, see Appendix D, Security in Spring Integration.
==== SecurityContext
Propagation
We introduced the SecurityContextPropagationChannelInterceptor
for the SecurityContext
propagation from one message flow’s thread to another.
For more information, see Appendix D, Security in Spring Integration.
In 4.1.2, we added FileSplitter
, which splits text files into lines.
It now has full support in the int-file:
namespace.
See Section 17.4, “File Splitter” for more information.
We added Zookeeper support to the framework to assist when running on a clustered or multi-host environment. The change impacts the following features:
ZookeeperMetadataStore
ZookeeperLockRegistry
See Chapter 40, Zookeeper Support for more information.
A new thread <int:barrier/>
component is available, letting a thread be suspended until some asynchronous event occurs.
See Section 8.8, “Thread Barrier” for more information.
We added STOMP support to the framework as an inbound and outbound channel adapters pair. See Chapter 31, STOMP Support for more information.
==== Codec
A new Codec
abstraction has been introduced, to encode and decode objects to and from byte[]
.
We added an implementation that uses Kryo.
We also added codec-based transformers and message converters.
See Section 9.4, “Codec” for more information.
==== Message PreparedStatement Setter
A new MessagePreparedStatementSetter
functional interface callback is available for the JdbcMessageHandler
(<int-jdbc:outbound-gateway>
and <int-jdbc:outbound-channel-adapter>
) as an alternative to using SqlParameterSourceFactory
to populate parameters on the PreparedStatement
with the requestMessage
context.
See Section 21.2, “Outbound Channel Adapter” for more information.
This section describes general changes from version 4.1 to version 4.2.
As an alternative to the existing selector
attribute, the <wire-tap/>
element now supports the selector-expression
attribute.
See Chapter 17, File Support for more information about these changes.
===== Appending New Lines
The <int-file:outbound-channel-adapter>
and <int-file:outbound-gateway>
now support an append-new-line
attribute.
If set to true
, a new line is appended to the file after a message is written.
The default attribute value is false
.
===== Ignoring Hidden Files
We added the ignore-hidden
attribute for the <int-file:inbound-channel-adapter>
to let you set whether to pick up hidden files from the source directory.
It defaults to true
.
===== Writing InputStream
Payloads
The FileWritingMessageHandler
now also accepts InputStream
as a valid message payload type.
===== HeadDirectoryScanner
You can now use the HeadDirectoryScanner
with other FileListFilter
implementations.
===== Last Modified Filter
We added the LastModifiedFileListFilter
.
===== Watch Service Directory Scanner
We added the WatchServiceDirectoryScanner
.
===== Persistent File List Filter Changes
The AbstractPersistentFileListFilter
has a new property (flushOnUpdate
) which, when set to true
, calls flush()
on the metadata store if it implements Flushable
(for example, PropertiesPersistingMetadataStore
).
We moved the ScatterGatherHandler
class from the org.springframework.integration.handler
to the org.springframework.integration.scattergather
.
==== TCP Changes
This section describes general changes to the Spring Integration TCP functionality.
The TCP Serializers
no longer flush()
the OutputStream
.
This is now done by the TcpNxxConnection
classes.
If you use the serializers directly within your code, you may have to flush()
the OutputStream
.
===== Server Socket Exceptions
TcpConnectionServerExceptionEvent
instances are now published whenever an unexpected exception occurs on a TCP server socket (also added to 4.1.3 and 4.0.7).
See Section 34.5, “TCP Connection Events” for more information.
If you configure a TCP server socket factory to listen on a random port, you can now obtain the actual port chosen by the OS by using getPort()
.
getServerSocketAddress()
is also available.
See "Section 34.3, “TCP Connection Factories”" for more information.
===== TCP Gateway Remote Timeout
The TcpOutboundGateway
now supports remote-timeout-expression
as an alternative to the existing remote-timeout
attribute.
This allows setting the timeout based on each message.
Also, the remote-timeout
no longer defaults to the same value as reply-timeout
, which has a completely different meaning.
See Table 34.7, “TCP Outbound Gateway Attributes” for more information.
===== TCP SSLSession Available for Header Mapping
TcpConnection
implementations now support getSslSession()
to let you extract information from the session to add to message headers.
See Section 34.13, “IP Message Headers” for more information.
New events are now published whenever a correlation exception occurs — such as sending a message to a non-existent socket.
The TcpConnectionEventListeningMessageProducer
is deprecated.
Use the generic event adapter instead.
See Section 34.5, “TCP Connection Events” for more information.
==== @InboundChannelAdapter
Changes
Previously, the @Poller
on an inbound channel adapter defaulted the maxMessagesPerPoll
attribute to -1
(infinity).
This was inconsistent with the XML configuration of <inbound-channel-adapter/>
, which defaults to 1
.
The annotation now defaults this attribute to 1
.
o.s.integration.util.FunctionIterator
now requires a o.s.integration.util.Function
instead of a reactor.function.Function
.
This was done to remove an unnecessary hard dependency on Reactor.
Any uses of this iterator need to change the import.
Reactor is still supported for functionality such as the Promise
gateway.
The dependency was removed for those users who do not need it.
This section describes general changes to the Spring Integration TCP functionality.
===== Reply Listener Lazy Initialization
You can now configure the reply listener in JMS outbound gateways to be initialized on-demand and stopped after an idle period, instead of being controlled by the gateway’s lifecycle. See Section 23.5, “Outbound Gateway” for more information.
===== Conversion Errors in Message-Driven Endpoints
The error-channel
is now used for the conversion errors. In previous versions, they caused transaction rollback and message redelivery.
See Section 23.2, “Message-driven Channel Adapter” and Section 23.4, “Inbound Gateway” for more information.
===== Default Acknowledge Mode
When using an implicitly defined DefaultMessageListenerContainer
, the default acknowledge
is now transacted
.
We recommend using transacted
when using this container, to avoid message loss.
This default now applies to the message-driven inbound adapter and the inbound gateway.
It was already the default for JMS-backed channels.
See Section 23.2, “Message-driven Channel Adapter” and Section 23.4, “Inbound Gateway” for more information.
===== Shared Subscriptions
We added Namespace support for shared subscriptions (JMS 2.0) to message-driven endpoints and the <int-jms:publish-subscribe-channel>
.
Previously, you had to wire up listener containers as <bean/>
declarations to use shared connections.
See Chapter 23, JMS Support for more information.
We now provide much more flexibility for dynamic polling.
See Section 6.2.4, “Conditional Pollers for Message Sources” for more information.
This section describes general changes to the Spring Integration AMQP functionality.
===== Publisher Confirmations
The <int-amqp:outbound-gateway>
now supports confirm-correlation-expression
, confirm-ack-channel
, and confirm-nack-channel
attributes (which have a purpose similar to that of <int-amqp:outbound-channel-adapter>
).
===== Correlation Data
For both the outbound channel adapter and the inbound gateway, if the correlation data is a Message<?>
, it becomes the basis of the message on the ack or nack channel, with the additional header(s) added.
Previously, any correlation data (including Message<?>
) was returned as the payload of the ack or nack message.
===== Inbound Gateway Properties
The <int-amqp:inbound-gateway>
now exposes the amqp-template
attribute to allow more control over an external bean for the reply RabbitTemplate
.
You can also provide your own AmqpTemplate
implementation.
In addition, you can use default-reply-to
if the request message does not have a replyTo
property.
See Chapter 14, AMQP Support for more information.
==== XPath Splitter Improvements
The XPathMessageSplitter
(<int-xml:xpath-splitter>
) now allows the configuration of output-properties
for the internal javax.xml.transform.Transformer
and supports an Iterator
mode (defaults to true
) for the XPath evaluation org.w3c.dom.NodeList
result.
See Section 38.4, “Splitting XML Messages” for more information.
This section describes general changes to the Spring Integration HTTP functionality.
===== CORS
The HTTP inbound endpoints (<int-http:inbound-channel-adapter>
and <int-http:inbound-gateway>
) now allow the
configuration of Cross-origin Resource Sharing (CORS).
See Section 20.3.3, “Cross-origin Resource Sharing (CORS) Support” for more information.
===== Inbound Gateway Timeout
You can configure the HTTP inbound gate way to return a status code that you specify when a request times out.
The default is now 500 Internal Server Error
instead of 200 OK
.
See Section 20.3.4, “Response Status Code” for more information.
===== Form Data
We added documentation for proxying multipart/form-data
requests.
See Chapter 20, HTTP Support for more information.
This section describes general changes to the Spring Integration Gateway functionality.
===== Gateway Methods can Return CompletableFuture<?>
When using Java 8, gateway methods can now return CompletableFuture<?>
.
See the section called “CompletableFuture
” for more information.
===== MessagingGateway Annotation
The request and reply timeout properties are now String
instead of Long
to allow configuration with property placeholders or SpEL.
See Section 10.4.6, “@MessagingGateway
Annotation”.
This section describes general changes to the Spring Integration aggregator functionality.
===== Aggregator Performance
This release includes some performance improvements for aggregating components (aggregator, resequencer, and others), by more efficiently removing messages from groups when they are released.
New methods (removeMessagesFromGroup
) have been added to the message store.
Set the removeBatchSize
property (default: 100
) to adjust the number of messages deleted in each operation.
Currently, the JDBC, Redis, and MongoDB message stores support this property.
===== Output Message Group Processor
When using a ref
or inner bean for the aggregator, you can now directly bind a MessageGroupProcessor
.
In addition, we added a SimpleMessageGroupProcessor
that returns the collection of messages in the group.
When an output processor produces a collection of Message<?>
, the aggregator releases those messages individually.
Configuring the SimpleMessageGroupProcessor
makes the aggregator a message barrier, where messages are held up until they all arrive and are then released individually.
See Section 8.4, “Aggregator” for more information.
==== FTP and SFTP Changes
This section describes general changes to the Spring Integration FTP and SFTP functionality.
===== Inbound Channel Adapters
You can now specify a remote-directory-expression
on the inbound channel adapters, to determine the directory at runtime.
See Chapter 18, FTP/FTPS Adapters and Chapter 30, SFTP Adapters for more information.
===== Gateway Partial Results
When you use FTP or SFTP outbound gateways to operate on multiple files (with mget
and mput
), an exception can
occur after part of the request is completed.
If such a condition occurs, a PartialSuccessException
that contains the partial results is thrown.
See Section 18.9, “FTP Outbound Gateway” and Section 30.11, “SFTP Outbound Gateway” for more information.
===== Delegating Session Factory
We added a delegating session factory, enabling the selection of a particular session factory based on some thread context value.
See Section 18.3, “Delegating Session Factory” and Section 30.3, “Delegating Session Factory” for more information.
===== Default Sftp Session Factory
Previously, the DefaultSftpSessionFactory
unconditionally allowed connections to unknown hosts.
This is now configurable (default: false
).
The factory now requires a configured knownHosts
, file unless the allowUnknownKeys
property is true
(default: false
).
See Section 30.1.1, “Configuration Properties” for more information.
===== Message Session Callback
We introduced the MessageSessionCallback<F, T>
to perform any custom Session
operations with the requestMessage
context in the <int-(s)ftp:outbound-gateway/>
.
See Section 18.12, “Using MessageSessionCallback
” and Section 30.13, “MessageSessionCallback” for more information.
==== Websocket Changes
We added WebSocketHandlerDecoratorFactory
support to the ServerWebSocketContainer
to allow chained customization for the internal WebSocketHandler
.
See Section 36.4, “WebSockets Namespace Support” for more information.
==== Application Event Adapters changes
The ApplicationEvent
adapters can now operate with payload
as an event
to directly allow omitting custom ApplicationEvent
extensions.
For this purpose, we introduced the publish-payload
boolean attribute has been introduced on the <int-event:outbound-channel-adapter>
.
See Chapter 15, Spring ApplicationEvent
Support for more information.
=== Changes between 4.0 and 4.1
See the Migration Guide for important changes that might affect your applications. You can find migration guides for all versions back to 2.1 on the wiki.
==== New Components
Version 4.1 added a number of new components.
The messaging gateway methods now support a Reactor Promise
return type.
See Section 10.4.10, “Asynchronous Gateway”.
The WebSocket
module is now available.
It is fully based on the Spring WebSocket and Spring Messaging modules and provides an <inbound-channel-adapter>
and an <outbound-channel-adapter>
.
See Chapter 36, WebSockets Support for more information.
===== Scatter-Gather Enterprise Integration Pattern
We implemented the scatter-gather enterprise integration pattern. See Section 8.7, “Scatter-Gather” for more information.
We added the routing slip EIP pattern implementation. See the section called “Routing Slip” for more information.
===== Idempotent Receiver Pattern
We added the idempotent receiver enterprise integration pattern implementation by adding the <idempotent-receiver>
component in XML or the IdempotentReceiverInterceptor
and IdempotentReceiver
annotations for Java configuration.
See Section 10.9.10, “Idempotent Receiver Enterprise Integration Pattern” and the Javadoc for more information.
We added the Boon JsonObjectMapper
for the JSON transformers.
See Section 9.1, “Transformer” for more information.
We added the <redis-queue-inbound-gateway>
and <redis-queue-outbound-gateway>
components.
See Section 27.9, “Redis Queue Inbound Gateway” and Section 27.8, “Redis Queue Outbound Gateway”.
We added the PollSkipAdvice
, which you can use within the <advice-chain>
of the <poller>
to determine if the current poll should be suppressed (skipped) by some condition that you implement with PollSkipStrategy
.
See Section 6.2, “Poller” for more information.
This section describes general changes from version 4.0 to version 4.1.
===== AMQP Inbound Endpoints, Channel
Elements that use a message listener container (inbound endpoints and channel) now support the missing-queues-fatal
attribute.
See Chapter 14, AMQP Support for more information.
The AMQP outbound endpoints support a new property called lazy-connect
(default: true
).
When true
, the connection to the broker is not established until the first message arrives (assuming there are no inbound endpoints, which always try to establish the connection during startup).
When set to false
, an attempt to establish the connection is made during application startup.
See Chapter 14, AMQP Support for more information.
The SimpleMessageStore
no longer makes a copy of the group when calling getMessageGroup()
.
See Caution about SimpleMessageStore
for more information.
===== Web Service Outbound Gateway: encode-uri
The <ws:outbound-gateway/>
now provides an encode-uri
attribute to allow disabling the encoding of the URI object before sending the request.
===== Http Inbound Channel Adapter and Status Code
The <http:inbound-channel-adapter>
can now be configured with a status-code-expression
to override the default 200 OK
status.
See Section 20.3, “HTTP Namespace Support” for more information.
You can now configure the MQTT channel adapters to connect to multiple servers — for example, to support High Availability (HA). See Chapter 26, MQTT Support for more information.
The MQTT message-driven channel adapter now supports specifying the QoS setting for each subscription. See Section 26.1, “Inbound (Message-driven) Channel Adapter” for more information.
The MQTT outbound channel adapter now supports asynchronous sends, avoiding blocking until delivery is confirmed. See Section 26.2, “Outbound Channel Adapter” for more information.
It is now possible to programmatically subscribe to and unsubscribe from topics at runtime. See Section 26.1, “Inbound (Message-driven) Channel Adapter” for more information.
===== FTP and SFTP Adapter Changes
The FTP and SFTP outbound channel adapters now support appending to remote files and taking specific actions when a remote file already exists.
The remote file templates now also supports this, as well as rmdir()
and exists()
.
In addition, the remote file templates provide access to the underlying client object, enabling access to low-level APIs.
See Chapter 18, FTP/FTPS Adapters and Chapter 30, SFTP Adapters for more information.
Splitter
components now support an Iterator
as the result object for producing output messages.
See Section 8.3, “Splitter” for more information.
Aggregator
instancess now support a new attribute expire-groups-upon-timeout
.
See Section 8.4, “Aggregator” for more information.
===== Content Enricher Improvements
We added a null-result-expression
attribute, which is evaluated and returned if <enricher>
returns null
.
You can add it in <header>
and <property>
.
See Section 9.2, “Content Enricher” for more information.
We added an error-channel
attribute, which is used to handle an error flow if an Exception
occurs downstream of the request-channel
.
This lets you return an alternative object to use for enrichment.
See Section 9.2, “Content Enricher” for more information.
The <header-enricher/>
element’s <header-channels-to-string/>
child element can now override the header channel registry’s default time for retaining channel mappings.
See the section called “Header Channel Registry” for more information.
We made improvements to the orderly shutdown algorithm. See Section 12.7, “Orderly Shutdown” for more information.
===== Management for RecipientListRouter
The RecipientListRouter
now provides several management operations to configure recipients at runtime.
With that, you can now configure the <recipient-list-router>
without any <recipient>
from the start.
See the section called “RecipientListRouterManagement
” for more information.
===== AbstractHeaderMapper: NON_STANDARD_HEADERS token
The AbstractHeaderMapper
implementation now provides the additional NON_STANDARD_HEADERS
token to map any user-defined headers, which are not mapped by default.
See Section 14.12, “AMQP Message Headers” for more information.
===== AMQP Channels: template-channel-transacted
We introduced the template-channel-transacted
attribute for AMQP MessageChannel
instances.
See Section 14.11, “AMQP-backed Message Channels” for more information.
The default syslog message converter now has an option to retain the original message in the payload while still setting the headers. See Section 33.1, “Syslog Inbound Channel Adapter” for more information.
In addition to the Promise
return type mentioned earlier, gateway methods may now return a ListenableFuture
, introduced in Spring Framework 4.0.
You can also disable asynchronous processing in the gateway, letting a downstream flow directly return a Future
.
See Section 10.4.10, “Asynchronous Gateway”.
Aggregator
and Resequencer
now support <expire-advice-chain/>
and <expire-transactional/>
child elements to advise the forceComplete
operation.
See ??? for more information.
===== Outbound Channel Adapter and Scripts
The <int:outbound-channel-adapter/>
now supports the <script/>
child element.
The underlying script must have a void
return type or return null
.
See Section 10.8, “Groovy support” and Section 10.7, “Scripting Support”.
When a message group in a resequencer times out (using group-timeout
or a MessageGroupStoreReaper
), late arriving messages are now, by default, discarded immediately.
See Section 8.5, “Resequencer”.
===== Optional POJO method parameter
Spring Integration now consistently handles the Java 8’s Optional
type.
See Section 10.5.1, “Configuring Service Activator”.
===== QueueChannel
backed Queue type
The QueueChannel
backed Queue type
has been changed from BlockingQueue
to the more generic Queue
.
This change allows the use of any external Queue
implementation (for example, Reactor’s PersistentQueue
).
See the section called “QueueChannel
Configuration”.
===== ChannelInterceptor
Changes
The ChannelInterceptor
now supports additional afterSendCompletion()
and afterReceiveCompletion()
methods.
See Section 6.1.3, “Channel Interceptors”.
Since version 4.1.1 there is a change of behavior if you explicitly set the mail.[protocol].peek
JavaMail property to false
(where [protocol]
is imap
or imaps
).
See Important: IMAP PEEK.
=== Changes between 3.0 and 4.0
See the Migration Guide for important changes that might affect your applications. You can find migration guides for all versions back to 2.1 on the wiki.
Version 4.0 added a number of new components.
The MQTT channel adapters (previously available in the Spring Integration Extensions repository) are now available as part of the normal Spring Integration distribution. See Chapter 26, MQTT Support.
We added the @EnableIntegration
annotation to permit declaration of standard Spring Integration beans when using @Configuration
classes.
See Section E.4, “Global Properties” for more information.
===== @IntegrationComponentScan
We added the @IntegrationComponentScan
annotation to permit classpath scanning for Spring Integration-specific components.
See Section E.4, “Global Properties” for more information.
You can now enable message history with the @EnableMessageHistory
annotation in a @Configuration
class.
In addition, a JMX MBean can modify the message history settings.
Also, MessageHistory
can track auto-created MessageHandler
instances for annotated endpoints (such as @ServiceActivator
, @Splitter
, and others).
For more information, see Section 12.3, “Message History”.
You can now configure messaging gateway interfaces with the @MessagingGateway
annotation.
It is an analogue of the <int:gateway/>
XML element.
For more information, see Section 10.4.6, “@MessagingGateway
Annotation”.
===== Spring Boot @EnableAutoConfiguration
As well as the @EnableIntegration
annotation mentioned earlier, we introduced a hook to allow the Spring Integration infrastructure beans to be configured with Spring Boot’s @EnableAutoConfiguration
annotation.
For more information, see "Auto-configuration
" in the Spring Boot Reference Guide.
===== @GlobalChannelInterceptor
As well as the @EnableIntegration
annotation mentioned above, we introduced the @GlobalChannelInterceptor
annotation.
For more information, see Section E.4, “Global Properties”.
We introduced the @IntegrationConverter
annotation as an analogue of the <int:converter/>
component.
For more information, see Section E.4, “Global Properties”.
We added the @EnablePublisher
annotation to allow the specification of a default-publisher-channel
for @Publisher
annotations.
See Section E.4, “Global Properties” for more information.
===== Redis Channel Message Stores
We added a Redis MessageGroupStore
that is optimized for use when backing a QueueChannel
for persistence.
For more information, see Section 27.3.1, “Redis Channel Message Stores”.
We added a Redis ChannelPriorityMessageStore
.
You can use it to retrieve messages by priority.
For more information, see Section 27.3.1, “Redis Channel Message Stores”.
===== MongodDB Channel Message Store
The MongoDB support now provides the MongoDbChannelMessageStore
, which is a channel-specific MessageStore
implementation.
With priorityEnabled = true
, you can use it in <int:priority-queue>
elements to achieve priority order polling of persisted messages.
For more information see Section 25.2.1, “MongoDB Channel Message Store”.
===== @EnableIntegrationMBeanExport
You can now enable the IntegrationMBeanExporter
with the @EnableIntegrationMBeanExport
annotation in a @Configuration
class.
For more information, see Section 12.2.7, “MBean Exporter”.
===== ChannelSecurityInterceptorFactoryBean
ChannelSecurityInterceptorFactoryBean
now supports configuration of Spring Security for message channels that use @Configuration
classes.
For more information, see Appendix D, Security in Spring Integration.
The Redis support now provides the <outbound-gateway>
component to perform generic Redis commands by using the RedisConnection#execute
method.
For more information, see Section 27.7, “Redis Outbound Command Gateway”.
===== RedisLockRegistry
and GemfireLockRegistry
The RedisLockRegistry
and GemfireLockRegistry
are now available to support global locks visible to multiple application instances and servers.
These can be used with aggregating message handlers across multiple application instances such that group release occurs on only one instance.
For more information, see Section 27.10, “Redis Lock Registry”, Section 19.5, “Gemfire Lock Registry”, and Section 8.4, “Aggregator”.
Annotation-based messaging configuration can now have a poller
attribute.
This means that methods annotated with @ServiceActivator
, @Aggregator
, and similar annotations can now use an inputChannel
that is a reference to a PollableChannel
.
For more information, see Section E.4, “Global Properties”.
===== @InboundChannelAdapter
and SmartLifecycle
for Annotated Endpoints
We added the @InboundChannelAdapter
method annotation.
It is an analogue of the <int:inbound-channel-adapter>
XML component.
In addition, all messaging annotations now provide SmartLifecycle
options.
For more information, see Section E.4, “Global Properties”.
===== Twitter Search Outbound Gateway
We added a new twitter endpoint: <int-twitter-search-outbound-gateway/>
.
Unlike the search inbound adapter, which polls by using the same search query each time, the outbound gateway allows on-demand customized queries.
For more information, see Spring Integration Social Twitter.
We added the GemfireMetadataStore
, letting it be used, for example, in an AbstractPersistentAcceptOnceFileListFilter
implementation in a multiple application instance or server environment.
For more information, see Section 12.5, “Metadata Store”, Section 17.1, “Reading Files”, Section 18.4, “FTP Inbound Channel Adapter”, and Section 30.6, “SFTP Inbound Channel Adapter”.
===== @BridgeFrom
and @BridgeTo
Annotations
We introduced @BridgeFrom
and @BridgeTo
@Bean
method annotations to mark MessageChannel
beans in @Configuration
classes.
For more information, see Section E.4, “Global Properties”.
===== Meta-messaging Annotations
Messaging annotations (@ServiceActivator
, @Router
, @MessagingGateway
, and others) can now be configured as meta-annotations for user-defined messaging annotations.
In addition, the user-defined annotations can have the same attributes (inputChannel
, @Poller
, autoStartup
, and others).
For more information, see Section E.4, “Global Properties”.
This section describes general changes from version 3.0 to version 4.0.
===== Requires Spring Framework 4.0
We moved the core messaging abstractions (Message
, MessageChannel
, and others) to the Spring Framework spring-messaging
module.
Developers who reference these classes directly in their code need to make changes, as described in the first section of the 3.0 to 4.0 Migration Guide.
===== Header Type for XPath Header Enricher
We introduced the header-type
attribute for the header
child element of the <int-xml:xpath-header-enricher>
.
This attribute provides the target type for the header value (to which the result of the XPath expression evaluation is converted).
For more information see Section 38.6, “XPath Header Enricher”.
===== Object To JSON Transformer: Node Result
We introduced the result-type
attribute for the <int:object-to-json-transformer>
.
This attribute provides the target type for the result of mapping an object to JSON.
It supports STRING
(the default) and NODE
.
For more information see the section called “JSON Transformers”.
The DefaultJmsHeaderMapper
now maps an incoming JMSPriority
header to the Spring Integration priority
header.
Previously, priority
was only considered for outbound messages.
For more information, see Section 23.6, “Mapping Message Headers to and from JMS Message”.
===== JMS Outbound Channel Adapter
The JMS outbound channel adapter now supports the session-transacted
attribute (default: false
).
Previously, you had to inject a customized JmsTemplate
to use transactions.
See Section 23.3, “Outbound Channel Adapter”.
===== JMS Inbound Channel Adapter
The JMS inbound channel adapter now supports the session-transacted
attribute (default: false
).
Previously, you had to inject a customized JmsTemplate
to use transactions.
The adapter allowed transacted in the acknowledgeMode
, which was incorrect and didn’t work.
This value is no longer allowed.
See Section 23.1, “Inbound Channel Adapter”.
You can now specify a MessageConverter
to be used when converting (if necessary) payloads to one of the accepted datatype
instances in a Datatype channel.
For more information, see the section called “Datatype Channel Configuration”.
===== Simpler Retry Advice Configuration
We added simplified namespace support to configure a RequestHandlerRetryAdvice
.
For more information, see the section called “Configuring the Retry Advice”.
===== Correlation Endpoint: Time-based Release Strategy
We added the mutually exclusive group-timeout
and group-timeout-expression
attributes to <int:aggregator>
and <int:resequencer>
.
These attributes allow forced completion of a partial MessageGroup
, provided the ReleaseStrategy
does not release a group and no further messages arrive within the time specified.
For more information, see ???.
The RedisMetadataStore
now implements ConcurrentMetadataStore
, letting it be used, for example, in an AbstractPersistentAcceptOnceFileListFilter
implementation in a multiple application instance or server environment.
For more information, see Section 27.4, “Redis Metadata Store”, Section 17.1, “Reading Files”, Section 18.4, “FTP Inbound Channel Adapter”, and Section 30.6, “SFTP Inbound Channel Adapter”.
===== JdbcChannelMessageStore
and PriorityChannel
T`JdbcChannelMessageStore` now implements PriorityCapableChannelMessageStore
, letting it be used as a message-store
reference for priority-queue
instances.
For more information, see Section 21.4.3, “Backing Message Channels”.
===== AMQP Endpoints Delivery Mode
Spring AMQP, by default, creates persistent messages on the broker.
You can override this behavior by setting the amqp_deliveryMode
header or customizing the mappers.
We added a convenient default-delivery-mode
attribute to the adapters to provide easier configuration of this important setting.
For more information, see Section 14.5, “Outbound Channel Adapter” and Section 14.6, “Outbound Gateway”.
The DefaultFtpSessionFactory
now exposes the connectTimeout
, defaultTimeout
, and dataTimeout
properties, avoiding the need to subclass the factory to set these common properties.
The postProcess*
methods are still available for more advanced configuration.
See Section 18.1, “FTP Session Factory” for more information.
===== Twitter: StatusUpdatingMessageHandler
The StatusUpdatingMessageHandler
(<int-twitter:outbound-channel-adapter>
) now supports the tweet-data-expression
attribute to build a org.springframework.social.twitter.api.TweetData
object for updating the timeline status.
This feature allows, for example, attaching an image.
See Spring Integration Social Twitter for more information.
===== JPA Retrieving Gateway: id-expression
We introduced the id-expression
attribute for <int-jpa:retrieving-outbound-gateway>
to perform EntityManager.find(Class entityClass, Object primaryKey)
.
See Section 22.7.5, “Retrieving Outbound Gateway” for more information.
===== TCP Deserialization Events
When one of the standard deserializers encounters a problem decoding the input stream to a message, it now emits a TcpDeserializationExceptionEvent
, letting applications examine the data at the point at which the exception occurred.
See Section 34.5, “TCP Connection Events” for more information.
===== Messaging Annotations on @Bean
Definitions
You can now configure messaging annotations (@ServiceActivator
, @Router
, @InboundChannelAdapter
, and others) on @Bean
definitions in @Configuration
classes.
For more information, see Section E.4, “Global Properties”.
=== Changes Between 2.2 and 3.0
See the Migration Guide for important changes that might affect your applications. You can find migration guides for all versions back to 2.1 on the wiki.
Version 3.0 added a number of new components.
The HTTP module now provides powerful request mapping support for inbound endpoints.
We replaced the UriPathHandlerMapping
class with IntegrationRequestMappingHandlerMapping
, which is registered under the bean name of integrationRequestMappingHandlerMapping
in the application context.
Upon parsing of the HTTP inbound endpoint, either a new IntegrationRequestMappingHandlerMapping
bean is registered or an existing bean is reused.
To achieve flexible request mapping configuration, Spring Integration provides the <request-mapping/>
child element for <http:inbound-channel-adapter/>
and the <http:inbound-gateway/>
.
Both HTTP inbound endpoints are now fully based on the request mapping infrastructure that was introduced with Spring MVC 3.1.
For example, multiple paths are supported on a single inbound endpoint.
For more information see Section 20.3, “HTTP Namespace Support”.
===== Spring Expression Language (SpEL) Configuration
We added a new IntegrationEvaluationContextFactoryBean
to allow configuration of custom PropertyAccessor
implementations and functions for use in SpEL expressions throughout the framework.
For more information, see Appendix A, Spring Expression Language (SpEL).
To customize the SpEL EvaluationContext
with static Method
functions, we introduced the <spel-function/>
component.
We also added two built-in functions: #jsonPath
and #xpath
.
For more information, see Section A.2, “SpEL Functions”.
===== SpEL PropertyAccessors Support
To customize the SpEL EvaluationContext
with PropertyAccessor
implementations, we added the <spel-property-accessors/>
component.
For more information, see Section A.3, “Property Accessors”.
We added a new Redis-based MetadataStore
implementation.
You can use the RedisMetadataStore
to maintain the state of a MetadataStore
across application restarts.
This new MetadataStore
implementation can be used with adapters, such as:
We added new queue-based components.
We added the <int-redis:queue-inbound-channel-adapter/>
and <int-redis:queue-outbound-channel-adapter/>
components to perform right pop and left push operations, respectively, on a Redis List.
For more information, "see <<redis>>
".
You can now instruct the framework to store reply channels and error channels in a registry for later resolution.
This is useful for cases where the replyChannel
or errorChannel
might be lost (for example, when serializing a message).
See Section 9.2.1, “Header Enricher” for more information.
===== MongoDB support: New ConfigurableMongoDbMessageStore
In addition to the existing eMongoDbMessageStore
, we introduced a new ConfigurableMongoDbMessageStore
.
This provides a more robust and flexible implementation of MessageStore
for MongoDB.
It does not have backward compatibility with the existing store, but we recommend using it for new applications.
Existing applications can use it, but messages in the old store are not available.
See Chapter 25, MongoDb Support for more information.
Building on the 2.2 SyslogToMapTransformer
, Spring Integration 3.0 introduces UDP
and TCP
inbound channel adapters especially tailored for receiving SYSLOG messages.
For more information, see Chapter 33, Syslog Support.
We added file inbound channel adapters that use the tail
command to generate messages when lines are added to the end of text files.
See Section 17.1.8, “'tail’ing Files”.
We added <int-jmx:tree-polling-channel-adapter/>
.
This adapter queries the JMX MBean tree and sends a message with a payload that is the graph of objects that match the query.
By default, the MBeans are mapped to primitives and simple Objects (such as Map
, List
, and arrays).
It permits simple transformation to, for example, JSON.
The IntegrationMBeanExporter
now allows the configuration of a custom ObjectNamingStrategy
by using the naming-strategy
attribute.
For more information, see Section 12.2, “JMX Support”.
===== TCP/IP Connection Events and Connection Management
TcpConnection
instances now emit ApplicationEvent
instances (specifically TcpConnectionEvent
instances) when connections are opened or closed or when an exception occurs.
This change lets applications be informed of changes to TCP connections by using the normal Spring ApplicationListener
mechanism.
We renamed AbstractTcpConnection
to TcpConnectionSupport
.
Custom connections that are subclasses of this class can use its methods to publish events.
Similarly, we renamed AbstractTcpConnectionInterceptor
to TcpConnectionInterceptorSupport
.
In addition, we added <int-ip:tcp-connection-event-inbound-channel-adapter/>
.
By default, this adapter sends all TcpConnectionEvent
instances to a Channel
.
Further, the TCP connection factories now provide a new method called getOpenConnectionIds()
, which returns a list of identifiers for all open connections.
It lets applications broadcast to all open connections, among other uses.
Finally, the connection factories also provide a new method called closeConnection(String connectionId)
, which lets applications explicitly close a connection by using its ID.
For more information see Section 34.5, “TCP Connection Events”.
===== Inbound Channel Adapter Script Support
The <int:inbound-channel-adapter/>
now supports using <expression/>
and <script/>
child elements to create a MessageSource
.
See Section 6.3.3, “Channel Adapter Expressions and Scripts”.
===== Content Enricher: Headers Enrichment Support
The content enricher now provides configuration for <header/>
child elements, to enrich the outbound message with headers based on the reply message from the underlying message flow.
For more information see Section 9.2.2, “Payload Enricher”.
This section describes general changes from version 2.2 to version 3.0.
Previously, message IDs were generated by using the JDK UUID.randomUUID()
method.
With this release, the default mechanism has been changed to use a more efficient and significantly faster algorithm.
In addition, we added the ability to change the strategy used to generate message IDs.
For more information see Section 7.2.2, “Message ID Generation”.
You can now set common headers across all gateway methods, and we added more options for adding information to the message about which method was invoked.
You can now entirely customize the way that gateway method calls are mapped to messages.
The GatewayMethodMetadata
is now a public class.
It lets you programmatically configure the GatewayProxyFactoryBean
from Java.
For more information, see Section 10.4, “Messaging Gateways”.
encode-uri
: <http:outbound-gateway/>
and <http:outbound-channel-adapter/>
now provide an encode-uri
attribute to allow disabling the encoding of the URI object before sending the request.
merge-with-default-converters
: <http:inbound-gateway/>
and <http:inbound-channel-adapter/>
now have a merge-with-default-converters
attribute to include the list of default HttpMessageConverter
instances after the custom message converters.
If-Modified-Since
and If-Unmodified-Since
HTTP Headers: Previously, the If-Modified-Since
and If-Unmodified-Since
HTTP headers were incorrectly processed within from and to HTTP headers mapped in the DefaultHttpHeaderMapper
.
Now, in addition to correcting that issue, DefaultHttpHeaderMapper
provides date parsing from formatted strings for any HTTP headers that accept date-time values.
#requestParams
and #pathVariables
, the <http:inbound-gateway/>
and <http:inbound-channel-adapter/>
now support additional useful variables: #matrixVariables
, #requestAttributes
, #requestHeaders
, and #cookies
.
These variables are available in both payload and header expressions.
uri-variables-expression
attribute to specify an Expression
to evaluate a Map
for all URI variable placeholders within URL template.
This allows selection of a different map of expressions based on the outgoing message.
For more information, see Chapter 20, HTTP Support.
ObjectToJsonTransformer
and JsonToObjectTransformer
now emit/consume headers containing type information.
For more information, see "JSON Transformers
" in Section 9.1, “Transformer”.
===== Chain Elements id
Attribute
Previously, the id
attribute for elements within a <chain>
was ignored and, in some cases, disallowed.
Now, the id
attribute is allowed for all elements within a <chain>
.
The bean names of chain elements is a combination of the surrounding chain’s id
and the id
of the element itself.
For example: myChain$child.myTransformer.handler.
For more information see, Section 8.6, “Message Handler Chain”.
===== Aggregator empty-group-min-timeout property
The AbstractCorrelatingMessageHandler
provides a new property called empty-group-min-timeout
to allow empty group expiry to run on a longer schedule than expiring partial groups.
Empty groups are not removed from the MessageStore
until they have not been modified for at least this number of milliseconds.
For more information, see ???.
===== Persistent File List Filters (file, (S)FTP)
New FileListFilter
implementations that use a persistent MetadataStore
are now available.
You can use these to prevent duplicate files after a system restart.
See Section 17.1, “Reading Files”, Section 18.4, “FTP Inbound Channel Adapter”, and Section 30.6, “SFTP Inbound Channel Adapter” for more information.
===== Scripting Support: Variables Changes
We introduced a new variables
attribute for scripting components.
In addition, variable bindings are now allowed for inline scripts.
See Section 10.8, “Groovy support” and Section 10.7, “Scripting Support” for more information.
===== Direct Channel Load Balancing configuration
Previously, when configuring LoadBalancingStrategy
on the channel’s dispatcher
child element, the only available option was to use a pre-defined enumeration of values which did not let developers set a custom implementation of the LoadBalancingStrategy
.
You can now use load-balancer-ref
to provide a reference to a custom implementation of the LoadBalancingStrategy
.
For more information, see the section called “DirectChannel
”.
===== PublishSubscribeChannel Behavior
Previously, sending to a <publish-subscribe-channel/> that had no subscribers would return a false
result.
If used in conjunction with a MessagingTemplate
, this would result in an exception being thrown.
Now, the PublishSubscribeChannel
has a property called minSubscribers
(default: 0
).
If the message is sent to at least the minimum number of subscribers, the send operation is deemed to be successful (even if the number is zero).
If an application expects to get an exception under these conditions, set the minimum subscribers to at least 1.
===== FTP, SFTP and FTPS Changes
The FTP, SFTP and FTPS endpoints no longer cache sessions by default.
We removed the deprecated cached-sessions
attribute from all endpoints.
Previously, the embedded caching mechanism controlled by this attribute’s value did not provide a way to limit the size of the cache, which could grow indefinitely.
Release 2.1 introduced CachingConnectionFactory
, and it became the preferred (and is now the only) way to cache sessions.
CachingConnectionFactory
now provides a new method: resetCache()
.
This method immediately closes idle sessions and causes in-use sessions to be closed as and when they are returned to the cache.
The DefaultSftpSessionFactory
(in conjunction with a CachingSessionFactory
) now supports multiplexing channels over a single SSH connection (SFTP Only).
====== FTP, SFTP and FTPS Inbound Adapters
Previously, there was no way to override the default filter used to process files retrieved from a remote server.
The filter
attribute determines which files are retrieved, but the FileReadingMessageSource
uses an AcceptOnceFileListFilter
.
This means that, if a new copy of a file is retrieved with the same name as a previously copied file, no message was sent from the adapter.
With this release, a new attribute local-filter
lets you override the default filter (for example, with an AcceptAllFileListFilter
or some other custom filter).
If you want the behavior of the AcceptOnceFileListFilter
to be maintained across JVM executions, you can now configure a custom filter that retains state, perhaps on the file system.
Inbound channel adapters now support the preserve-timestamp
attribute, which sets the local file modified timestamp to the timestamp from the server (default: false
).
====== FTP, SFTP, and FTPS Gateways
The gateways now support the mv
command, enabling the renaming of remote files.
The gateways now support recursive ls
and mget
commands, enabling the retrieval of a remote file tree.
The gateways now support put
and mput
commands, enabling sending files to the remote server.
The local-filename-generator-expression
attribute is now supported, enabling the naming of local files during retrieval.
By default, the same name as the remote file is used.
The local-directory-expression
attribute is now supported, enabling the naming of local directories during retrieval (based on the remote directory).
====== Remote File Template
A new higher-level abstraction (RemoteFileTemplate
) is provided over the Session
implementations used by the FTP and SFTP modules.
While it is used internally by endpoints, you can also use this abstraction programmatically.
Like all Spring *Template
implementations, it reliably closes the underlying session while allowing low level access to the session.
For more information, see Chapter 18, FTP/FTPS Adapters and Chapter 30, SFTP Adapters.
===== requires-reply Attribute for Outbound Gateways
All outbound gateways (such as <jdbc:outbound-gateway/>
or <jms:outbound-gateway/>
) are designed for request-reply scenarios.
A response is expected from the external service and is published to the reply-channel
or the replyChannel
message header.
However, there are some cases where the external system might not always return a result (for example,
a <jdbc:outbound-gateway/>
when a SELECT ends with an empty ResultSet
or perhaps a one-way web service).
Consequently, developers needed an option to configure whether or not a reply is required.
For this purpose, we introduced the requires-reply
attribute for outbound gateway components.
In most cases, the default value for requires-reply
is true
.
If there is no result, a ReplyRequiredException
is thrown.
Changing the value to false
means that, if an external service does not return anything, the message flow ends at that point, similar to an outbound channel adapter.
Note | |
---|---|
The WebService outbound gateway has an additional attribute called |
Note that the requiresReply
property was previously present but set to false
in the AbstractReplyProducingMessageHandler
, and there was no way to configure it on outbound gateways by using the XML namespace.
Important | |
---|---|
Previously, a gateway receiving no reply would silently end the flow (with a DEBUG log message).
By default, with this change, an exception is now thrown by most gateways.
To revert to the previous behavior, set |
===== AMQP Outbound Gateway Header Mapping
Previously, the <int-amqp:outbound-gateway/> mapped headers before invoking the message converter, and the converter could overwrite headers such as content-type
.
The outbound adapter maps the headers after the conversion, which means headers like content-type
from the outbound Message
(if present) are used.
Starting with this release, the gateway now maps the headers after the message conversion, consistent with the adapter.
If your application relies on the previous behavior (where the converter’s headers overrode the mapped headers), you either need to filter those headers (before the message reaches the gateway) or set them appropriately.
The headers affected by the SimpleMessageConverter
are content-type
and content-encoding
.
Custom message converters may set other headers.
===== Stored Procedure Components Improvements
For more complex database-specific types not supported by the standard CallableStatement.getObject
method, we introduced two new additional attributes to the <sql-parameter-definition/>
element with OUT-direction:
type-name
return-type
The row-mapper
attribute of the stored procedure inbound channel adapter <returning-resultset/>
child element now supports a reference to a RowMapper
bean definition.
Previously, it contained only a class name (which is still supported).
For more information, see Section 21.5, “Stored Procedures”.
===== Web Service Outbound URI Configuration
The web service outbound gateway uri attribute now supports <uri-variable/>
substitution for all URI schemes supported by Spring Web Services.
For more information, see Section 37.4, “Outbound URI Configuration”.
The Redis inbound channel adapter can now use a null
value for the serializer
property, with the raw data being the message payload.
The Redis outbound channel adapter now has the topic-expression
property to determine the Redis topic for the Message
at runtime.
The Redis inbound channel adapter, in addition to the existing topics
attribute, now has the topic-patterns
attribute.
For more information, see Chapter 27, Redis Support.
Previously, when a <filter/>
had a <request-handler-advice-chain/>
, the discard action was all performed within the scope of the advice chain (including any downstream flow on the discard-channel
).
The filter element now has an attribute called discard-within-advice
(default: true
) to allow the discard action to be performed after the advice chain completes.
See Section 10.9.6, “Advising Filters”.
===== Advising Endpoints using Annotations
Request handler advice chains can now be configured using annotations. See Section 10.9.7, “Advising Endpoints Using Annotations”.
===== ObjectToStringTransformer Improvements
This transformer now correctly transforms byte[]
and char[]
payloads to String
.
For more information, see Section 9.1, “Transformer”.
Payloads to persist or merge can now be of type http://docs.oracle.com/javase/7/docs/api/java/lang/Iterable.html[java.lang.Iterable]
.
In that case, each object returned by the Iterable
is treated as an entity and persisted or merged by using the underlying EntityManager
.
Null values returned by the iterator are ignored.
The JPA adapters now have additional attributes to optionally flush and clear entities from the associated persistence context after performing persistence operations.
Retrieving gateways had no mechanism to specify the first record to be retrieved, which is a common use case.
The retrieving gateways now support specifying this parameter by adding the first-result
and first-result-expression
attributes to the gateway definition.
For more information, see Section 22.7.5, “Retrieving Outbound Gateway”.
The JPA retrieving gateway and inbound adapter now have an attribute to specify the maximum number of results in a result set as an expression.
In addition, we introduced the max-results
attribute to replace max-number-of-results
, which has been deprecated.
max-results
and max-results-expression
are used to provide the maximum number of results or an expression to compute the maximum number of results, respectively, in the result set.
For more information, see Chapter 22, JPA Support.
===== Delayer: delay expression
Previously, the <delayer>
provided a delay-header-name
attribute to determine the delay value at runtime.
In complex cases, the <delayer>
had to be preceded with a <header-enricher>
.
Spring Integration 3.0 introduced the expression
attribute and expression
child element for dynamic delay determination.
The delay-header-name
attribute is now deprecated, because you can specify the header evaluation in the expression
.
In addition, we introduced the ignore-expression-failures
to control the behavior when an expression evaluation fails.
For more information, see Section 10.6, “Delayer”.
===== JDBC Message Store Improvements
Spring Integration 3.0 adds a new set of DDL scripts for MySQL version 5.6.4 and higher. Now MySQL supports fractional seconds and is thus improving the FIFO ordering when polling from a MySQL-based message store. For more information, see Section 21.4.2, “The Generic JDBC Message Store”.
===== IMAP Idle Connection Exceptions
Previously, if an IMAP idle connection failed, it was logged, but there was no mechanism to inform an application.
Such exceptions now generate ApplicationEvent
instances.
Applications can obtain these events by using an <int-event:inbound-channel-adapter>
or any ApplicationListener
configured to receive an ImapIdleExceptionEvent
(or one of its super classes).
The TCP connection factories now enable the configuration of a flexible mechanism to transfer selected headers (as well as the payload) over TCP.
A new TcpMessageMapper
enables the selection of the headers, and you need to configure an appropriate serializer or deserializer to write the resulting Map
to the TCP stream.
We added a MapJsonSerializer
as a convenient mechanism to transfer headers and payload over TCP.
For more information, see Section 34.8.3, “Transferring Headers”.
===== JMS Message Driven Channel Adapter
Previously, when configuring a <message-driven-channel-adapter/>
, if you wished to use a specific TaskExecutor
, you had to declare a container bean and provide it to the adapter by setting the container
attribute.
We added the task-executor
, letting it be set directly on the adapter.
This is in addition to several other container attributes that were already available.
The RMI Inbound Gateway now supports an error-channel
attribute.
See Section 29.2, “Inbound RMI”.
You can now specify the transformer factory class name by setting the transformer-factory-class
attribute.
See <<xml-xslt-payload-transformers>>
.
=== Changes between 2.1 and 2.2
See the Migration Guide for important changes that might affect your applications. You can find migration guides for all versions back to 2.1 on the wiki.
Version 2.2 added a number of new components.
===== RedisStore
Inbound and Outbound Channel Adapters
Spring Integration now has RedisStore
Inbound and Outbound Channel Adapters, letting you write and read Message
payloads to and from Redis collections.
For more information, see Section 27.6, “RedisStore Outbound Channel Adapter” and Section 27.5, “Redis Store Inbound Channel Adapter”.
===== MongoDB Inbound and Outbound Channel Adapters
Spring Integration now has MongoDB inbound and outbound channel adapters, letting you write and read Message
payloads to and from a MongoDB document store.
For more information, see Section 25.4, “MongoDB Outbound Channel Adapter” and Section 25.3, “MongoDB Inbound Channel Adapter”.
Spring Integration now includes components for the Java Persistence API (JPA) for retrieving and persisting JPA entity objects. The JPA Adapter includes the following components:
For more information, see Chapter 22, JPA Support.
This section describes general changes from version 2.1 to version 2.2.
===== Spring 3.1 Used by Default
Spring Integration now uses Spring 3.1.
===== Adding Behavior to Endpoints
The ability to add an <advice-chain/>
to a poller has been available for some time.
However, the behavior added by this affects the entire integration flow.
It did not address the ability to add (for example) retry to an individual endpoint.
The 2.2. release introduced the <request-handler-advice-chain/>
to many endpoints.
In addition, we added three standard advice classes for this purpose:
MessageHandlerRetryAdvice
MessageHandlerCircuitBreakerAdvice
ExpressionEvaluatingMessageHandlerAdvice
For more information, see Section 10.9, “Adding Behavior to Endpoints”.
===== Transaction Synchronization and Pseudo Transactions
Pollers can now participate in Spring’s Transaction Synchronization feature. This allows for synchronizing such operations as renaming files by an inbound channel adapter, depending on whether the transaction commits or rolls back.
In addition, you can enable these features when no "real
" transaction is present, by means of a PseudoTransactionManager
.
For more information, see Section C.3, “Transaction Synchronization”.
===== File Adapter: Improved File Overwrite and Append Handling
When using the file outbound channel adapter or the file outbound gateway, you can use a new mode
property.
Prior to Spring Integration 2.2, target files were replaced when they existed.
Now you can specify the following options:
REPLACE
(default)
APPEND
FAIL
IGNORE
For more information, see Section 17.2.3, “Dealing with Existing Destination Files”.
===== Reply-Timeout Added to More Outbound Gateways
The XML Namespace support adds the reply-timeout attribute to the following outbound gateways:
Spring Integration now uses Spring AMQP 1.1. This enables several features to be used within a Spring Integration application, including the following:
===== JDBC Support - Stored Procedures Components
====== SpEL Support
When using the stored procedure components of the Spring Integration JDBC Adapter, you can now provide stored procedure names or stored function names by using the Spring Expression Language (SpEL).
Doing so lets you specify the stored procedures to be invoked at runtime. For example, you can provide stored procedure names that you would like to execute through message headers. For more information, see Section 21.5, “Stored Procedures”.
====== JMX Support
The stored procedure components now provide basic JMX support, exposing some of their properties as MBeans:
JdbcCallOperations
cache statistics
===== JDBC Support: Outbound Gateway
When you use the JDBC outbound gateway, the update query is no longer mandatory. You can now provide only a select query by using the request message as a source of parameters.
===== JDBC Support: Channel-specific Message Store Implementation
We added a new message channel-specific message store implementation, providing a more scalable solution using database-specific SQL queries. For more information, see Section 21.4.3, “Backing Message Channels”.
We added a method called stopActiveComponents()
to the IntegrationMBeanExporter
.
It allows a Spring Integration application to be shut down in an orderly manner, disallowing new inbound messages to certain adapters and waiting for some time to allow in-flight messages to complete.
===== JMS Outbound Gateway Improvements
You can now configure the JMS outbound gateway to use a MessageListener
container to receive replies.
Doing so can improve performance of the gateway.
By default, the ObjectToJsonTransformer
now sets the content-type
header to application/json
.
For more information, see Section 9.1, “Transformer”.
Java serialization over HTTP is no longer enabled by default.
Previously, when setting an expected-response-type
on a Serializable
object, the Accept
header was not properly set up.
We updated the SerializingHttpMessageConverter
to set the Accept
header to application/x-java-serialized-object
.
However, because this could cause incompatibility with existing applications, we decided to no longer automatically add this converter to the HTTP endpoints.
If you wish to use Java serialization, you need to add the SerializingHttpMessageConverter
to the appropriate endpoints by using the message-converters
attribute (when you use XML configuration) or by using the setMessageConverters()
method (in Java).
Alternatively, you may wish to consider using JSON instead.
It is enabled by having Jackson
on the classpath.
=== Changes between 2.0 and 2.1
See the Migration Guide for important changes that might affect your applications.
Version 2.1 added a number of new components.
===== JSR-223 Scripting Support
In Spring Integration 2.0, we added support for Groovy.
With Spring Integration 2.1, we expanded support for additional languages substantially by implementing support for JSR-223 ("Scripting for the Java™ Platform
").
Now you have the ability to use any scripting language that supports JSR-223 including:
For further details, see Section 10.7, “Scripting Support”.
Spring Integration provides support for GemFire by providing inbound adapters for entry and continuous query events, an outbound adapter to write entries to the cache, and MessageStore
and MessageGroupStore
implementations.
Spring integration leverages the Spring Gemfire project, providing a thin wrapper over its components.
For further details, see Chapter 19, Pivotal GemFire and Apache Geode Support.
Spring Integration 2.1 added several channel adapters for receiving and sending messages by using the Advanced Message Queuing Protocol (AMQP). Furthermore, Spring Integration also provides a point-to-point message channel and a publish-subscribe message channel, both of which are backed by AMQP Exchanges and Queues.
For further details, see Chapter 14, AMQP Support.
As of version 2.1, Spring Integration provides support for MongoDB by providing a MongoDB-based MessageStore
.
For further details, see Chapter 25, MongoDb Support.
As of version 2.1, Spring Integration supports Redis, an advanced key-value store, by providing a Redis-based MessageStore
as well as publish-subscribe messaging adapters.
For further details, see Chapter 27, Redis Support.
===== Support for Spring’s Resource abstraction
In version 2.1, we introduced a new resource inbound channel adapter that builds upon Spring’s resource abstraction to support greater flexibility across a variety of actual types of underlying resources, such as a file, a URL, or a classpath resource. Therefore, it is similar to but more generic than the file inbound channel adapter.
For further details, see Section 28.1, “Resource Inbound Channel Adapter”.
===== Stored Procedure Components
With Spring Integration 2.1, the JDBC
Module also provides stored procedure support by adding several new components, including inbound and outbound channel adapters and an outbound gateway.
The stored procedure support leverages Spring’s SimpleJdbcCall
class and consequently supports stored procedures for:
The stored procedure components also support SQL functions for the following databases:
For further details, see Section 21.5, “Stored Procedures”.
===== XPath and XML Validating Filter
Spring Integration 2.1 provides a new XPath-based message filter.
It is part of the XML
module.
The XPath filter lets you filter messages by using XPath Expressions.
We also added documentation for the XML validating filter.
For more details, see Section 38.7, “Using the XPath Filter” and Section 38.9, “XML Validating Filter”.
Since Spring Integration 2.1, we added the payload enricher.
A payload enricher defines an endpoint that typically passes a Message
to the exposed request channel and then expects a reply message.
The reply message then becomes the root object for evaluation of expressions to enrich the target payload.
For further details, see Section 9.2.2, “Payload Enricher”.
===== FTP and SFTP Outbound Gateways
Spring Integration 2.1 provides two new outbound gateways to interact with remote File Transfer Protocol (FTP) or Secure File Transfer Protocol (SFT) servers. These two gateways let you directly execute a limited set of remote commands.
For instance, you can use these outbound gateways to list, retrieve, and delete remote files and have the Spring Integration message flow continue with the remote server’s response.
For further details, see Section 18.9, “FTP Outbound Gateway” and Section 30.11, “SFTP Outbound Gateway”.
As of version 2.1, we have exposed more flexibility with regards to session management for remote file adapters (for example, FTP, SFTP, and others).
Specifically, we deprecated the cache-sessions
attribute (which is available via the XML namespace support).
As an alternative, we added the sessionCacheSize
and sessionWaitTimeout
attributes on the CachingSessionFactory
.
For further details, see Section 18.10, “FTP Session Caching” and Section 30.4, “SFTP Session Caching”.
We refactored the Spring Integration framework in a number of ways, all described in this section.
===== Standardizing Router Configuration
We standardized router parameters across all router implementations with Spring Integration 2.1 to provide a more consistent user experience.
In Spring Integration 2.1, we removed the ignore-channel-name-resolution-failures
attribute in favor of consolidating its behavior with the resolution-required
attribute.
Also, the resolution-required
attribute now defaults to true
.
Starting with Spring Integration 2.1, routers no longer silently drop any messages if no default output channel was defined.
This means that, by default, routers now require at least one resolved channel (if no default-output-channel
was set) and, by default, throw a MessageDeliveryException
if no channel was determined (or an attempt to send was not successful).
If, however, you do want to drop messages silently, you can set default-output-channel="nullChannel"
.
Important | |
---|---|
With the standardization of router parameters and the consolidation of the parameters described earlier, older Spring Integration based applications may break. |
For further details, see <<router>>
.
===== XML Schemas updated to 2.1
Spring Integration 2.1 ships with an updated XML Schema (version 2.1). It provides many improvements, such as the Router standardizations discussed earlier.
From now on, developers must always declare the latest XML schema (currently version 2.1). Alternatively, they can use the version-less schema. Generally, the best option is to use version-less namespaces, as these automatically use the latest available version of Spring Integration.
The following example declares a version-less Spring Integration namespace:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration" xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> ... </beans>
The following example declares a Spring Integration namespace with an explicit version:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration" xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> ... </beans>
The old 1.0 and 2.0 schemas are still there. However, if an application context still references one of those deprecated schemas, the validator fails on initialization.
==== Source Control Management and Build Infrastructure
Version 2.1 introduced a number of changes to source control management and build infrastructure. This section covers those changes.
===== Source Code Now Hosted on Github
Since version 2.0, the Spring Integration project uses Git for version control. To increase community visibility even further, the project was moved from SpringSource hosted Git repositories to Github. The Spring Integration Git repository is located at: spring-integration.
For the project, we also improved the process of providing code contributions. Further, we ensure that every commit is peer-reviewed. In fact, core committers now follow the same process as contributors. For more details, see Contributing.
===== Improved Source Code Visibility with Sonar
In an effort to provide better source code visibility and consequently to monitor the quality of Spring Integration’s source code, we set up an instance of Sonar. We gather metrics nightly and make them available at sonar.spring.io.
For the 2.1 release of Spring Integration, we also expanded the Spring Integration Samples project and added many new samples, such as samples that cover AMQP support, a sample that showcases the new payload enricher, a sample illustrating techniques for testing Spring Integration flow fragments, and a sample for executing stored procedures against Oracle databases. For details, visit spring-integration-samples.
=== Changes between Versions 1.0 and 2.0
See the Migration Guide for important changes that might affect your applications.
Spring Integration 2.0 is built on top of Spring 3.0.5 and makes many of its features available to our users.
===== Support for the Spring Expression Language (SpEL)
You can now use SpEL expressions within the transformer, router, filter, splitter, aggregator, service-activator, header-enricher, and many more elements of the Spring Integration core namespace as well as within various adapters. This guide includes many samples.
===== Conversion Service and Converter
You can now benefit from the conversion service support provided with Spring while configuring many Spring Integration components, such as a Datatype channel. See Section 6.1.2, “Message Channel Implementations” and ???. Also, the SpEL support mentioned in the previous point also relies upon the conversion service. Therefore, you can register converters once and take advantage of them anywhere you use SpEL expressions.
===== TaskScheduler
and Trigger
Spring 3.0 defines two new strategies related to scheduling: TaskScheduler
and Trigger
.
Spring Integration (which uses a lot of scheduling) now builds upon these.
In fact, Spring Integration 1.0 had originally defined some of the components (such as CronTrigger
) that have now been migrated into Spring 3.0’s core API.
Now you can benefit from reusing the same components within the entire application context (not just Spring Integration configuration).
We also greatly simplified configuration of Spring Integration pollers by providing attributes for directly configuring rates, delays, cron expressions, and trigger references.
See Section 6.3, “Channel Adapter” for sample configurations.
===== RestTemplate
and HttpMessageConverter
Our outbound HTTP adapters now delegate to Spring’s RestTemplate
for executing the HTTP request and handling its response.
This also means that you can reuse any custom HttpMessageConverter
implementations.
See Section 20.2, “HTTP Outbound Components” for more details.
==== Enterprise Integration Pattern Additions
Also in 2.0, we have added support for even more of the patterns described in Hohpe and Woolf’s Enterprise Integration Patterns book.
We now provide support for the message history pattern, letting you keep track of all traversed components, including the name of each channel and endpoint as well as the timestamp of that traversal. See Section 12.3, “Message History” for more details.
We now provide support for the message store pattern. The message store provides a strategy for persisting messages on behalf of any process whose scope extends beyond a single transaction, such as the aggregator and the resequencer. Many sections of this guide include samples of how to use a message store, as it affects several areas of Spring Integration. See Section 12.4, “Message Store”, Section 9.3, “Claim Check”, Section 6.1, “Message Channels”, Section 8.4, “Aggregator”, Chapter 21, JDBC Support`", and Section 8.5, “Resequencer” for more details.
We have added an implementation of the claim check pattern.
The idea behind the claim check pattern is that you can exchange a message payload for a "claim ticket
".
This lets you reduce bandwidth and avoid potential security issues when sending messages across channels.
See Section 9.3, “Claim Check” for more details.
We have provided implementations of the control bus pattern, which lets you use messaging to manage and monitor endpoints and channels. The implementations include both a SpEL-based approach and one that runs Groovy scripts. See Section 12.6, “Control Bus” and Section 10.8.4, “Control Bus” for more details.
==== New Channel Adapters and Gateways
We have added several new channel adapters and messaging gateways in Spring Integration 2.0.
We have added channel adapters for receiving and sending messages over the TCP and UDP internet protocols.
See Chapter 34, TCP and UDP Support for more details.
See also the following blog: "Using UDP and TCP Adapters in Spring Integration 2.0 M3
".
Twitter adapters provides support for sending and receiving Twitter status updates as well as direct messages. You can also perform Twitter Searches with an inbound channel adapter. See Spring Integration Social Twitter for more details.
The new XMPP adapters support both chat messages and presence events. See Chapter 39, XMPP Support for more details.
Inbound and outbound file transfer support over FTP and FTPS is now available. See Chapter 18, FTP/FTPS Adapters for more details.
Inbound and outbound file transfer support over SFTP is now available. See Chapter 30, SFTP Adapters for more details.
We have also added channel adapters for receiving news feeds (ATOM and RSS). See Chapter 16, Feed Adapter for more details.
==== Other Additions Spring Integration adds a number of other features. This section describes them.
Spring Integration 2.0 added Groovy support, letting you use the Groovy scripting language to provide integration and business logic. See Section 10.8, “Groovy support” for more details.
These symmetrical transformers convert payload objects to and from Map
objects.
See Section 9.1, “Transformer” for more details.
These symmetrical transformers convert payload objects to and from JSON. See Section 9.1, “Transformer” for more details.
===== Serialization Transformers
These symmetrical transformers convert payload objects to and from byte arrays. They also support the serializer and deserializer strategy interfaces that Spring 3.0.5 added. See Section 9.1, “Transformer” for more details.
The core API went through some significant refactoring to make it simpler and more usable.
Although we anticipate that the impact to developers should be minimal, you should read through this document to find what was changed.
Specifically, you should read Section 8.1.6, “Dynamic Routers”, Section 10.4, “Messaging Gateways”, Section 20.2, “HTTP Outbound Components”, Chapter 7, Message, and Section 8.4, “Aggregator”.
If you directly depend on some of the core components (Message
, MessageHeaders
, MessageChannel
, MessageBuilder
, and others), you need to update any import statements.
We restructured some packaging to provide the flexibility we needed for extending the domain model while avoiding any cyclical dependencies (it is a policy of the framework to avoid such "tangles
").
==== New Source Control Management and Build Infrastructure
With Spring Integration 2.0, we switched our build environment to use Git for source control. To access our repository, visit http://git.springsource.org/spring-integration. We have also switched our build system to Gradle.
==== New Spring Integration Samples
With Spring Integration 2.0, we have decoupled the samples from our main release distribution. Please read the following blog to get more information: New Spring Integration Samples. We have also created many new samples, including samples for every new adapter.
==== Spring Tool Suite Visual Editor for Spring Integration
There is an amazing new visual editor for Spring Integration included within the latest version of SpringSource Tool Suite. If you are not already using STS, you can download it athttps://spring.io/tools/sts[Spring Tool Suite].