INT-4565: Fix IntComponentScan for profiles (#2652)
* INT-4565: Fix IntComponentScan for profiles JIRA: https://jira.spring.io/browse/INT-4565 * Propagate an `Environment` to the internal `ClassPathScanningCandidateComponentProvider` in the `IntegrationComponentScanRegistrar` for proper profiles activation * Ensure the logic works in the `GatewayInterfaceTests` * Some polishing and performance improvement for the `GatewayInterfaceTests` * Add a note about `@Profile` in the `gateway.adoc` * Polishing for the `gateway.adoc` **Cherry-pick to 5.0.x & 4.3.x** * * Add not activated by profile gateway interface into the `GatewayInterfaceTests` * More `GatewayInterfaceTests` polishing * Fix typo in the `gateway.adoc` * Fix Checkstyle violation
This commit is contained in:
committed by
Gary Russell
parent
2cde493fbf
commit
536b6b1786
@@ -61,12 +61,14 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Artem Bilan
|
||||
* @author Gary Russell
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class IntegrationComponentScanRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
ResourceLoaderAware, EnvironmentAware {
|
||||
|
||||
private final Map<TypeFilter, ImportBeanDefinitionRegistrar> componentRegistrars = new HashMap<TypeFilter, ImportBeanDefinitionRegistrar>();
|
||||
private final Map<TypeFilter, ImportBeanDefinitionRegistrar> componentRegistrars =
|
||||
new HashMap<TypeFilter, ImportBeanDefinitionRegistrar>();
|
||||
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
@@ -98,14 +100,16 @@ public class IntegrationComponentScanRegistrar implements ImportBeanDefinitionRe
|
||||
basePackages = Collections.singleton(ClassUtils.getPackageName(importingClassMetadata.getClassName()));
|
||||
}
|
||||
|
||||
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false) {
|
||||
ClassPathScanningCandidateComponentProvider scanner =
|
||||
new ClassPathScanningCandidateComponentProvider(false, this.environment) {
|
||||
|
||||
@Override
|
||||
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
|
||||
return beanDefinition.getMetadata().isIndependent()
|
||||
&& !beanDefinition.getMetadata().isAnnotation();
|
||||
}
|
||||
};
|
||||
@Override
|
||||
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
|
||||
return beanDefinition.getMetadata().isIndependent()
|
||||
&& !beanDefinition.getMetadata().isAnnotation();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
if ((boolean) componentScan.get("useDefaultFilters")) { // NOSONAR - never null
|
||||
for (TypeFilter typeFilter : this.componentRegistrars.keySet()) {
|
||||
|
||||
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThat;
|
||||
@@ -59,6 +60,7 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.FilterType;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
@@ -77,6 +79,7 @@ import org.springframework.integration.context.IntegrationContextUtils;
|
||||
import org.springframework.integration.context.IntegrationProperties;
|
||||
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
|
||||
import org.springframework.integration.handler.BridgeHandler;
|
||||
import org.springframework.integration.handler.DelayHandler;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -93,6 +96,7 @@ import org.springframework.messaging.support.MessageHeaderAccessor;
|
||||
import org.springframework.scheduling.annotation.AsyncResult;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
@@ -107,6 +111,7 @@ import org.springframework.util.concurrent.ListenableFutureCallback;
|
||||
@ContextConfiguration(classes = GatewayInterfaceTests.TestConfig.class)
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@DirtiesContext
|
||||
@ActiveProfiles("gatewayTest")
|
||||
public class GatewayInterfaceTests {
|
||||
|
||||
private static final String IGNORE_HEADER = "ignoreHeader";
|
||||
@@ -153,20 +158,23 @@ public class GatewayInterfaceTests {
|
||||
@Autowired
|
||||
private IgnoredHeaderGateway ignoredHeaderGateway;
|
||||
|
||||
@Autowired(required = false)
|
||||
private NotActivatedByProfileGateway notActivatedByProfileGateway;
|
||||
|
||||
@Test
|
||||
public void testWithServiceSuperclassAnnotatedMethod() throws Exception {
|
||||
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this
|
||||
.getClass());
|
||||
ConfigurableApplicationContext ac =
|
||||
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelFoo", DirectChannel.class);
|
||||
final Method fooMethod = Foo.class.getMethod("foo", String.class);
|
||||
final AtomicBoolean called = new AtomicBoolean();
|
||||
MessageHandler handler = message -> {
|
||||
assertThat((String) message.getHeaders().get("name"), equalTo("foo"));
|
||||
assertThat(
|
||||
(String) message.getHeaders().get("string"),
|
||||
equalTo("public abstract void org.springframework.integration.gateway.GatewayInterfaceTests$Foo.foo(java.lang.String)"));
|
||||
assertThat((Method) message.getHeaders().get("object"), equalTo(fooMethod));
|
||||
assertThat((String) message.getPayload(), equalTo("hello"));
|
||||
assertThat(message.getHeaders().get("name"), equalTo("foo"));
|
||||
assertThat(message.getHeaders().get("string"),
|
||||
equalTo("public abstract void org.springframework.integration.gateway." +
|
||||
"GatewayInterfaceTests$Foo.foo(java.lang.String)"));
|
||||
assertThat(message.getHeaders().get("object"), equalTo(fooMethod));
|
||||
assertThat(message.getPayload(), equalTo("hello"));
|
||||
assertThat(new MessageHeaderAccessor(message).getErrorChannel(), equalTo("errorChannel"));
|
||||
called.set(true);
|
||||
};
|
||||
@@ -181,18 +189,18 @@ public class GatewayInterfaceTests {
|
||||
|
||||
@Test
|
||||
public void testWithServiceSuperclassAnnotatedMethodOverridePE() throws Exception {
|
||||
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests2-context.xml", this
|
||||
.getClass());
|
||||
ConfigurableApplicationContext ac =
|
||||
new ClassPathXmlApplicationContext("GatewayInterfaceTests2-context.xml", getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelFoo", DirectChannel.class);
|
||||
final Method fooMethod = Foo.class.getMethod("foo", String.class);
|
||||
final AtomicBoolean called = new AtomicBoolean();
|
||||
MessageHandler handler = message -> {
|
||||
assertThat((String) message.getHeaders().get("name"), equalTo("foo"));
|
||||
assertThat(
|
||||
(String) message.getHeaders().get("string"),
|
||||
equalTo("public abstract void org.springframework.integration.gateway.GatewayInterfaceTests$Foo.foo(java.lang.String)"));
|
||||
assertThat((Method) message.getHeaders().get("object"), equalTo(fooMethod));
|
||||
assertThat((String) message.getPayload(), equalTo("foo"));
|
||||
assertThat(message.getHeaders().get("name"), equalTo("foo"));
|
||||
assertThat(message.getHeaders().get("string"),
|
||||
equalTo("public abstract void org.springframework.integration.gateway." +
|
||||
"GatewayInterfaceTests$Foo.foo(java.lang.String)"));
|
||||
assertThat(message.getHeaders().get("object"), equalTo(fooMethod));
|
||||
assertThat(message.getPayload(), equalTo("foo"));
|
||||
called.set(true);
|
||||
};
|
||||
channel.subscribe(handler);
|
||||
@@ -204,8 +212,8 @@ public class GatewayInterfaceTests {
|
||||
|
||||
@Test
|
||||
public void testWithServiceAnnotatedMethod() {
|
||||
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this
|
||||
.getClass());
|
||||
ConfigurableApplicationContext ac =
|
||||
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelBar", DirectChannel.class);
|
||||
MessageHandler handler = mock(MessageHandler.class);
|
||||
channel.subscribe(handler);
|
||||
@@ -217,15 +225,16 @@ public class GatewayInterfaceTests {
|
||||
|
||||
@Test
|
||||
public void testWithServiceSuperclassUnAnnotatedMethod() throws Exception {
|
||||
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this
|
||||
.getClass());
|
||||
ConfigurableApplicationContext ac =
|
||||
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
|
||||
final Method bazMethod = Foo.class.getMethod("baz", String.class);
|
||||
final AtomicBoolean called = new AtomicBoolean();
|
||||
MessageHandler handler = message -> {
|
||||
assertThat(message.getHeaders().get("name"), equalTo("overrideGlobal"));
|
||||
assertThat(message.getHeaders().get("string"),
|
||||
equalTo("public abstract void org.springframework.integration.gateway.GatewayInterfaceTests$Foo.baz(java.lang.String)"));
|
||||
equalTo("public abstract void org.springframework.integration.gateway." +
|
||||
"GatewayInterfaceTests$Foo.baz(java.lang.String)"));
|
||||
assertThat(message.getHeaders().get("object"), equalTo(bazMethod));
|
||||
assertThat(message.getPayload(), equalTo("hello"));
|
||||
called.set(true);
|
||||
@@ -239,15 +248,16 @@ public class GatewayInterfaceTests {
|
||||
|
||||
@Test
|
||||
public void testWithServiceUnAnnotatedMethodGlobalHeaderDoesntOverride() throws Exception {
|
||||
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this
|
||||
.getClass());
|
||||
ConfigurableApplicationContext ac =
|
||||
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
|
||||
final Method quxMethod = Bar.class.getMethod("qux", String.class, String.class);
|
||||
final AtomicBoolean called = new AtomicBoolean();
|
||||
MessageHandler handler = message -> {
|
||||
assertThat(message.getHeaders().get("name"), equalTo("arg1"));
|
||||
assertThat(message.getHeaders().get("string"),
|
||||
equalTo("public abstract void org.springframework.integration.gateway.GatewayInterfaceTests$Bar.qux(java.lang.String,java.lang.String)"));
|
||||
equalTo("public abstract void org.springframework.integration.gateway." +
|
||||
"GatewayInterfaceTests$Bar.qux(java.lang.String,java.lang.String)"));
|
||||
assertThat(message.getHeaders().get("object"), equalTo(quxMethod));
|
||||
assertThat(message.getPayload(), equalTo("hello"));
|
||||
called.set(true);
|
||||
@@ -261,8 +271,8 @@ public class GatewayInterfaceTests {
|
||||
|
||||
@Test
|
||||
public void testWithServiceCastAsSuperclassAnnotatedMethod() {
|
||||
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this
|
||||
.getClass());
|
||||
ConfigurableApplicationContext ac =
|
||||
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelFoo", DirectChannel.class);
|
||||
MessageHandler handler = mock(MessageHandler.class);
|
||||
channel.subscribe(handler);
|
||||
@@ -274,8 +284,8 @@ public class GatewayInterfaceTests {
|
||||
|
||||
@Test
|
||||
public void testWithServiceCastAsSuperclassUnAnnotatedMethod() {
|
||||
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this
|
||||
.getClass());
|
||||
ConfigurableApplicationContext ac =
|
||||
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
|
||||
MessageHandler handler = mock(MessageHandler.class);
|
||||
channel.subscribe(handler);
|
||||
@@ -287,8 +297,8 @@ public class GatewayInterfaceTests {
|
||||
|
||||
@Test
|
||||
public void testWithServiceHashcode() {
|
||||
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this
|
||||
.getClass());
|
||||
ConfigurableApplicationContext ac =
|
||||
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
|
||||
MessageHandler handler = mock(MessageHandler.class);
|
||||
channel.subscribe(handler);
|
||||
@@ -300,8 +310,8 @@ public class GatewayInterfaceTests {
|
||||
|
||||
@Test
|
||||
public void testWithServiceToString() {
|
||||
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this
|
||||
.getClass());
|
||||
ConfigurableApplicationContext ac =
|
||||
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
|
||||
MessageHandler handler = mock(MessageHandler.class);
|
||||
channel.subscribe(handler);
|
||||
@@ -313,13 +323,13 @@ public class GatewayInterfaceTests {
|
||||
|
||||
@Test
|
||||
public void testWithServiceEquals() throws Exception {
|
||||
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this
|
||||
.getClass());
|
||||
ConfigurableApplicationContext ac =
|
||||
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
|
||||
MessageHandler handler = mock(MessageHandler.class);
|
||||
channel.subscribe(handler);
|
||||
Bar bar = ac.getBean(Bar.class);
|
||||
assertTrue(bar.equals(ac.getBean(Bar.class)));
|
||||
assertSame(bar, ac.getBean(Bar.class));
|
||||
GatewayProxyFactoryBean fb = new GatewayProxyFactoryBean(Bar.class);
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.registerSingleton("requestChannelBar", channel);
|
||||
@@ -327,15 +337,15 @@ public class GatewayInterfaceTests {
|
||||
bf.registerSingleton("requestChannelFoo", channel);
|
||||
fb.setBeanFactory(bf);
|
||||
fb.afterPropertiesSet();
|
||||
assertFalse(bar.equals(fb.getObject()));
|
||||
assertNotSame(bar, fb.getObject());
|
||||
verify(handler, times(0)).handleMessage(Mockito.any(Message.class));
|
||||
ac.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithServiceGetClass() {
|
||||
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this
|
||||
.getClass());
|
||||
ConfigurableApplicationContext ac =
|
||||
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
|
||||
MessageHandler handler = mock(MessageHandler.class);
|
||||
channel.subscribe(handler);
|
||||
@@ -352,12 +362,12 @@ public class GatewayInterfaceTests {
|
||||
|
||||
@Test
|
||||
public void testWithCustomMapper() {
|
||||
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this
|
||||
.getClass());
|
||||
ConfigurableApplicationContext ac =
|
||||
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
|
||||
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
|
||||
final AtomicBoolean called = new AtomicBoolean();
|
||||
MessageHandler handler = message -> {
|
||||
assertThat((String) message.getPayload(), equalTo("fizbuz"));
|
||||
assertThat(message.getPayload(), equalTo("fizbuz"));
|
||||
called.set(true);
|
||||
};
|
||||
channel.subscribe(handler);
|
||||
@@ -369,8 +379,13 @@ public class GatewayInterfaceTests {
|
||||
|
||||
@Test
|
||||
public void testLateReply() {
|
||||
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml",
|
||||
this.getClass());
|
||||
ConfigurableApplicationContext ac =
|
||||
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
|
||||
|
||||
DelayHandler delayHandler = ac.getBean(DelayHandler.class);
|
||||
delayHandler.setMaxAttempts(2);
|
||||
delayHandler.setRetryDelay(10);
|
||||
|
||||
Bar baz = ac.getBean(Bar.class);
|
||||
String reply = baz.lateReply("hello", 1000, 0);
|
||||
assertNull(reply);
|
||||
@@ -448,14 +463,15 @@ public class GatewayInterfaceTests {
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void testAnnotationGatewayProxyFactoryBean() {
|
||||
assertNotNull(this.gatewayByAnnotationGPFB);
|
||||
assertNull(this.notActivatedByProfileGateway);
|
||||
|
||||
assertSame(this.exec, this.annotationGatewayProxyFactoryBean.getAsyncExecutor());
|
||||
assertEquals(1111L, TestUtils
|
||||
.getPropertyValue(this.annotationGatewayProxyFactoryBean, "defaultRequestTimeout", Expression.class)
|
||||
.getValue());
|
||||
assertEquals(222L, TestUtils
|
||||
.getPropertyValue(this.annotationGatewayProxyFactoryBean, "defaultReplyTimeout", Expression.class)
|
||||
.getValue());
|
||||
assertEquals(1111L,
|
||||
TestUtils.getPropertyValue(this.annotationGatewayProxyFactoryBean,
|
||||
"defaultRequestTimeout", Expression.class).getValue());
|
||||
assertEquals(222L,
|
||||
TestUtils.getPropertyValue(this.annotationGatewayProxyFactoryBean,
|
||||
"defaultReplyTimeout", Expression.class).getValue());
|
||||
|
||||
Collection<MessagingGatewaySupport> messagingGateways =
|
||||
this.annotationGatewayProxyFactoryBean.getGateways().values();
|
||||
@@ -563,7 +579,7 @@ public class GatewayInterfaceTests {
|
||||
public static class BazMapper implements MethodArgsMessageMapper {
|
||||
|
||||
@Override
|
||||
public Message<?> toMessage(MethodArgsHolder object, @Nullable Map<String, Object> headers) throws Exception {
|
||||
public Message<?> toMessage(MethodArgsHolder object, @Nullable Map<String, Object> headers) {
|
||||
return MessageBuilder.withPayload("fizbuz")
|
||||
.copyHeadersIfAbsent(headers)
|
||||
.build();
|
||||
@@ -652,6 +668,7 @@ public class GatewayInterfaceTests {
|
||||
|
||||
@MessagingGateway
|
||||
@TestMessagingGateway
|
||||
@Profile("gatewayTest")
|
||||
public interface Int2634Gateway {
|
||||
|
||||
@Gateway(requestChannel = "gatewayChannel", payloadExpression = "#args[0]")
|
||||
@@ -665,6 +682,15 @@ public class GatewayInterfaceTests {
|
||||
|
||||
}
|
||||
|
||||
@MessagingGateway(defaultRequestChannel = "errorChannel")
|
||||
@TestMessagingGateway
|
||||
@Profile("notActiveProfile")
|
||||
public interface NotActivatedByProfileGateway {
|
||||
|
||||
void send(String payload);
|
||||
|
||||
}
|
||||
|
||||
@MessagingGateway(asyncExecutor = "exec")
|
||||
@TestMessagingGateway
|
||||
public interface ExecGateway {
|
||||
|
||||
@@ -188,7 +188,7 @@ Consider the following example:
|
||||
----
|
||||
public String send1(Object thing1, Map thing2);
|
||||
|
||||
public String send2(Map thing1, Map thing2);=
|
||||
public String send2(Map thing1, Map thing2);
|
||||
----
|
||||
====
|
||||
|
||||
@@ -313,8 +313,9 @@ The standard `@ComponentScan` infrastructure does not deal with interfaces.
|
||||
Consequently, we introduced the custom `@IntegrationComponentScan` logic to fine the `@MessagingGateway` annotation on the interfaces and register `GatewayProxyFactoryBean` instances for them.
|
||||
See also <<annotations>>.
|
||||
|
||||
NOTE: If you have no XML configuration, the `@EnableIntegration` annotation is required on at least one `@Configuration`
|
||||
class.
|
||||
Along with the `@MessagingGateway` annotation you can mark a service interface with the `@Profile` annotation to avoid the bean creation, if such a profile is not active.
|
||||
|
||||
NOTE: If you have no XML configuration, the `@EnableIntegration` annotation is required on at least one `@Configuration` class.
|
||||
See <<configuration-enable-integration>> for more information.
|
||||
|
||||
[[gateway-calling-no-argument-methods]]
|
||||
@@ -460,11 +461,9 @@ Similarly, if the error flow on the `error-channel` returns an `ErrorMessage`, i
|
||||
The same applies to any message with a `Throwable` payload.
|
||||
This can be useful in asynchronous situations when when you need to propagate an `Exception` directly to the caller.
|
||||
To do so, you can either return an `Exception` (as the `reply` from some service) or throw it.
|
||||
Generally, even with an asynchronous flow, the framework takes care of propagating an exception thrown by the
|
||||
downstream flow back to the gateway.
|
||||
Generally, even with an asynchronous flow, the framework takes care of propagating an exception thrown by the downstream flow back to the gateway.
|
||||
The https://github.com/spring-projects/spring-integration-samples/tree/master/intermediate/tcp-client-server-multiplex[TCP Client-Server Multiplex] sample demonstrates both techniques to return the exception to the caller.
|
||||
It emulates a socket IO error to the waiting thread by using an `aggregator` with `group-timeout` (see <<agg-and-group-to>>)
|
||||
and a `MessagingTimeoutException` reply on the discard flow.
|
||||
It emulates a socket IO error to the waiting thread by using an `aggregator` with `group-timeout` (see <<agg-and-group-to>>) and a `MessagingTimeoutException` reply on the discard flow.
|
||||
|
||||
[[gateway-timeouts]]
|
||||
==== Gateway Timeouts
|
||||
@@ -642,8 +641,7 @@ In this scenario, the downstream flow is expected to return a `CompletableFuture
|
||||
|
||||
====== Usage Scenarios
|
||||
|
||||
In the following scenario, the caller thread returns immediately with a `CompletableFuture<Invoice>`, which is completed
|
||||
when the downstream flow replies to the gateway (with an `Invoice` object).
|
||||
In the following scenario, the caller thread returns immediately with a `CompletableFuture<Invoice>`, which is completed when the downstream flow replies to the gateway (with an `Invoice` object).
|
||||
|
||||
====
|
||||
[source, java]
|
||||
@@ -657,8 +655,7 @@ CompletableFuture<Invoice> order(Order order);
|
||||
----
|
||||
====
|
||||
|
||||
In the following scenario, the caller thread returns with a `CompletableFuture<Invoice>` when the downstream flow provides
|
||||
it as the payload of the reply to the gateway.
|
||||
In the following scenario, the caller thread returns with a `CompletableFuture<Invoice>` when the downstream flow provides it as the payload of the reply to the gateway.
|
||||
Some other process must complete the future when the invoice is ready.
|
||||
|
||||
====
|
||||
@@ -674,8 +671,7 @@ CompletableFuture<Invoice> order(Order order);
|
||||
----
|
||||
====
|
||||
|
||||
In the following scenario, the caller thread returns with a `CompletableFuture<Invoice>` when the downstream flow provides
|
||||
it as the payload of the reply to the gateway.
|
||||
In the following scenario, the caller thread returns with a `CompletableFuture<Invoice>` when the downstream flow provides it as the payload of the reply to the gateway.
|
||||
Some other process must complete the future when the invoice is ready.
|
||||
If `DEBUG` logging is enabled, a log entry is emitted, indicating that the async executor cannot be used for this scenario.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user