GH-3869: Add ContextHolderRequestHandlerAdvice
Fixes https://github.com/spring-projects/spring-integration/issues/3869 * Move `ContextHolderRequestHandlerAdvice` to the `core` module for more general purposes * Add `ContextHolderRequestHandlerAdviceTests` * Rework `DelegatingSessionFactoryTests` to rely on the `ContextHolderRequestHandlerAdvice`. This allows us to remove unnecessary XML configuration for this test class * Document the feature
This commit is contained in:
@@ -231,33 +231,10 @@ private static final class SharedSSLFTPSClient extends FTPSClient {
|
||||
|
||||
Version 4.2 introduced the `DelegatingSessionFactory`, which allows the selection of the actual session factory at runtime.
|
||||
Prior to invoking the FTP endpoint, call `setThreadKey()` on the factory to associate a key with the current thread.
|
||||
That key is then used to lookup the actual session factory to be used.
|
||||
That key is then used to look up the actual session factory to be used.
|
||||
You can clear the key by calling `clearThreadKey()` after use.
|
||||
|
||||
We added convenience methods so that you can easily do use a delegating session factory from a message flow.
|
||||
|
||||
The following example shows how to declare a delegating session factory:
|
||||
|
||||
====
|
||||
[source, xml]
|
||||
----
|
||||
<bean id="dsf" class="org.springframework.integration.file.remote.session.DelegatingSessionFactory">
|
||||
<constructor-arg>
|
||||
<bean class="o.s.i.file.remote.session.DefaultSessionFactoryLocator">
|
||||
<!-- delegate factories here -->
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<int:service-activator input-channel="in" output-channel="c1"
|
||||
expression="@dsf.setThreadKey(#root, headers['factoryToUse'])" />
|
||||
|
||||
<int-ftp:outbound-gateway request-channel="c1" reply-channel="c2" ... />
|
||||
|
||||
<int:service-activator input-channel="c2" output-channel="out"
|
||||
expression="@dsf.clearThreadKey(#root)" />
|
||||
----
|
||||
====
|
||||
See <<./handler-advice.adoc#context-holder-advice, Context Holder Advice>> for more information how this factory can be used together with a `ContextHolderRequestHandlerAdvice`.
|
||||
|
||||
IMPORTANT: When you use session caching (see <<ftp-session-caching>>), each of the delegates should be cached.
|
||||
You cannot cache the `DelegatingSessionFactory` itself.
|
||||
|
||||
@@ -57,6 +57,9 @@ In addition to providing the general mechanism to apply AOP advice classes, Spri
|
||||
* `RateLimiterRequestHandlerAdvice` (described in <<rate-limiter-advice>>)
|
||||
* `CacheRequestHandlerAdvice` (described in <<cache-advice>>)
|
||||
* `ReactiveRequestHandlerAdvice` (described in <<reactive-advice>>)
|
||||
* `ContextHolderRequestHandlerAdvice` (described in <<context-holder-advice>>)
|
||||
|
||||
[[expression-advice]]
|
||||
|
||||
[[retry-advice]]
|
||||
===== Retry Advice
|
||||
@@ -571,6 +574,44 @@ The `message` argument is the request message for the message handler and can be
|
||||
The `mono` argument is the result of this message handler's `handleRequestMessage()` method implementation.
|
||||
A nested `Mono.transform()` can also be called from this function to apply, for example, a https://spring.io/projects/spring-cloud-circuitbreaker[Reactive Circuit Breaker].
|
||||
|
||||
[[context-holder-advice]]
|
||||
==== Context Holder Advice
|
||||
|
||||
Starting with version 6.1, the `ContextHolderRequestHandlerAdvice` has been introduced.
|
||||
This advice takes some value from the request message as and stores it in the context holder.
|
||||
The value is clear from the context when an execution is finished on the target `MessageHandler`.
|
||||
The best way to think about this advice is similar to the programming flow where we store some value into a `ThreadLocal`, get access to it from the target call and then clean up the `ThreadLocal` after execution.
|
||||
The `ContextHolderRequestHandlerAdvice` requires these constructor arguments: a `Function<Message<?>, Object>` as a value provider, `Consumer<Object>` as a context set callback and `Runnable` as a context clean up hook.
|
||||
|
||||
Following is a sample how a `ContextHolderRequestHandlerAdvice` can be used in combination with a `o.s.i.file.remote.session.DelegatingSessionFactory`:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@Bean
|
||||
DelegatingSessionFactory<?> dsf(SessionFactory<?> one, SessionFactory<?> two) {
|
||||
return new DelegatingSessionFactory<>(Map.of("one", one, "two", two), null);
|
||||
}
|
||||
|
||||
@Bean
|
||||
ContextHolderRequestHandlerAdvice contextHolderRequestHandlerAdvice(DelegatingSessionFactory<String> dsf) {
|
||||
return new ContextHolderRequestHandlerAdvice(message -> message.getHeaders().get("FACTORY_KEY"),
|
||||
dsf::setThreadKey, dsf::clearThreadKey);
|
||||
}
|
||||
|
||||
@ServiceActivator(inputChannel = "in", adviceChain = "contextHolderRequestHandlerAdvice")
|
||||
FtpOutboundGateway ftpOutboundGateway(DelegatingSessionFactory<?> sessionFactory) {
|
||||
return new FtpOutboundGateway(sessionFactory, "ls", "payload");
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
And it is just enough to send a message to the `in` channel with a `FACTORY_KEY` header set to either `one` or `two`.
|
||||
The `ContextHolderRequestHandlerAdvice` sets the value from that header into a `DelegatingSessionFactory` via its `setThreadKey`.
|
||||
Then when `FtpOutboundGateway` executes an `ls` command a proper delegating `SessionFactory` is chosen from the `DelegatingSessionFactory` according to the value in its `ThreadLocal`.
|
||||
When the result is produced from the `FtpOutboundGateway`, a `ThreadLocal` value in the `DelegatingSessionFactory` is cleared according to the `clearThreadKey()` call from the `ContextHolderRequestHandlerAdvice`.
|
||||
See <<./ftp.adoc#ftp-dsf,Delegating Session Factory>> for more information.
|
||||
|
||||
[[custom-advice]]
|
||||
==== Custom Advice Classes
|
||||
|
||||
|
||||
@@ -23,6 +23,11 @@ In general the project has been moved to the latest dependency versions.
|
||||
The Zip Spring Integration Extension project has been migrated as the `spring-integration-zip` module.
|
||||
See <<./zip.adoc#zip,Zip Support>> for more information.
|
||||
|
||||
[[x6.1-context-holder-advice]]
|
||||
==== `ContextHolderRequestHandlerAdvice`
|
||||
|
||||
The `ContextHolderRequestHandlerAdvice` allows to store a value from a request message into some context around `MessageHandler` execution.
|
||||
See <<./handler-advice.adoc#context-holder-advice, Context Holder Advice>> for more information.
|
||||
|
||||
[[x6.1-general]]
|
||||
=== General Changes
|
||||
|
||||
Reference in New Issue
Block a user