diff --git a/binders/kafka-binder/spring-cloud-stream-binder-kafka/src/main/java/org/springframework/cloud/stream/binder/kafka/KafkaMessageChannelBinder.java b/binders/kafka-binder/spring-cloud-stream-binder-kafka/src/main/java/org/springframework/cloud/stream/binder/kafka/KafkaMessageChannelBinder.java index dd31ea5db..455669284 100644 --- a/binders/kafka-binder/spring-cloud-stream-binder-kafka/src/main/java/org/springframework/cloud/stream/binder/kafka/KafkaMessageChannelBinder.java +++ b/binders/kafka-binder/spring-cloud-stream-binder-kafka/src/main/java/org/springframework/cloud/stream/binder/kafka/KafkaMessageChannelBinder.java @@ -374,6 +374,11 @@ public class KafkaMessageChannelBinder extends return this.transactionManager == null ? null : this.transactionManager.getProducerFactory(); } + @Override + public String getBinderIdentity() { + return "kafka-" + super.getBinderIdentity(); + } + @Override protected MessageHandler createProducerMessageHandler( final ProducerDestination destination, diff --git a/binders/kafka-binder/spring-cloud-stream-binder-kafka/src/test/java/org/springframework/cloud/stream/binder/kafka/KafkaBinderTests.java b/binders/kafka-binder/spring-cloud-stream-binder-kafka/src/test/java/org/springframework/cloud/stream/binder/kafka/KafkaBinderTests.java index dc8fd1bfe..408ec8912 100644 --- a/binders/kafka-binder/spring-cloud-stream-binder-kafka/src/test/java/org/springframework/cloud/stream/binder/kafka/KafkaBinderTests.java +++ b/binders/kafka-binder/spring-cloud-stream-binder-kafka/src/test/java/org/springframework/cloud/stream/binder/kafka/KafkaBinderTests.java @@ -1039,6 +1039,7 @@ public class KafkaBinderTests extends consumerProperties.setMultiplex(true); consumerProperties.getExtension().setDlqPartitions(dlqPartitions); consumerProperties.setConcurrency(2); + consumerProperties.populateBindingName("foobar"); DirectChannel moduleInputChannel = createBindableChannel("input", createConsumerBindingProperties(consumerProperties)); @@ -1091,8 +1092,9 @@ public class KafkaBinderTests extends ApplicationContext context = TestUtils.getPropertyValue(binder.getBinder(), "applicationContext", ApplicationContext.class); - SubscribableChannel boundErrorChannel = context - .getBean(consumerDest + ".testGroup.errors-0", SubscribableChannel.class); + SubscribableChannel boundErrorChannel = context.getBean(binder.getBinder().getBinderIdentity() + ".foobar.errors-0", SubscribableChannel.class); +// SubscribableChannel boundErrorChannel = context +// .getBean(consumerDest + ".errors-0", SubscribableChannel.class); SubscribableChannel globalErrorChannel = context.getBean("errorChannel", SubscribableChannel.class); final AtomicReference> boundErrorChannelMessage = new AtomicReference<>(); @@ -2450,12 +2452,12 @@ public class KafkaBinderTests extends new KafkaProducerProperties()); producerProps.setHeaderMode(HeaderMode.none); producerProps.setErrorChannelEnabled(true); + producerProps.populateBindingName("foobar"); Binding producerBinding = binder.bindProducer("ec.0", moduleOutputChannel, producerProps); final Message message = MessageBuilder.withPayload("bad") .setHeader(MessageHeaders.CONTENT_TYPE, "application/json").build(); - SubscribableChannel ec = binder.getApplicationContext().getBean("ec.0.errors", - SubscribableChannel.class); + SubscribableChannel ec = binder.getApplicationContext().getBean(binder.getBinder().getBinderIdentity() + ".foobar.errors", SubscribableChannel.class); final AtomicReference> errorMessage = new AtomicReference<>(); final CountDownLatch latch = new CountDownLatch(2); ec.subscribe(message1 -> { diff --git a/binders/rabbit-binder/spring-cloud-stream-binder-rabbit/src/main/java/org/springframework/cloud/stream/binder/rabbit/RabbitMessageChannelBinder.java b/binders/rabbit-binder/spring-cloud-stream-binder-rabbit/src/main/java/org/springframework/cloud/stream/binder/rabbit/RabbitMessageChannelBinder.java index e37f56a88..6f33e2dae 100644 --- a/binders/rabbit-binder/spring-cloud-stream-binder-rabbit/src/main/java/org/springframework/cloud/stream/binder/rabbit/RabbitMessageChannelBinder.java +++ b/binders/rabbit-binder/spring-cloud-stream-binder-rabbit/src/main/java/org/springframework/cloud/stream/binder/rabbit/RabbitMessageChannelBinder.java @@ -306,6 +306,11 @@ public class RabbitMessageChannelBinder extends return this.extendedBindingProperties.getExtendedPropertiesEntryClass(); } + @Override + public String getBinderIdentity() { + return "rabbit-" + super.getBinderIdentity(); + } + @Override protected MessageHandler createProducerMessageHandler( final ProducerDestination producerDestination, @@ -952,11 +957,11 @@ public class RabbitMessageChannelBinder extends }; } - @Override - protected String errorsBaseName(ConsumerDestination destination, String group, - ExtendedConsumerProperties consumerProperties) { - return destination.getName() + ".errors"; - } +// @Override +// protected String errorsBaseName(ConsumerDestination destination, String group, +// ExtendedConsumerProperties consumerProperties) { +// return destination.getName() + ".errors"; +// } private String deadLetterExchangeName(RabbitCommonProperties properties) { if (properties.getDeadLetterExchange() == null) { diff --git a/binders/rabbit-binder/spring-cloud-stream-binder-rabbit/src/test/java/org/springframework/cloud/stream/binder/rabbit/RabbitBinderTests.java b/binders/rabbit-binder/spring-cloud-stream-binder-rabbit/src/test/java/org/springframework/cloud/stream/binder/rabbit/RabbitBinderTests.java index ff65efdc6..7c9577ba6 100644 --- a/binders/rabbit-binder/spring-cloud-stream-binder-rabbit/src/test/java/org/springframework/cloud/stream/binder/rabbit/RabbitBinderTests.java +++ b/binders/rabbit-binder/spring-cloud-stream-binder-rabbit/src/test/java/org/springframework/cloud/stream/binder/rabbit/RabbitBinderTests.java @@ -260,11 +260,14 @@ public class RabbitBinderTests extends new BindingProperties()); ExtendedProducerProperties producerProps = createProducerProperties(testInfo); producerProps.setErrorChannelEnabled(true); + producerProps.populateBindingName("output"); Binding producerBinding = binder.bindProducer("ec.0", moduleOutputChannel, producerProps); final Message message = MessageBuilder.withPayload("bad".getBytes()) .setHeader(MessageHeaders.CONTENT_TYPE, "foo/bar").build(); - SubscribableChannel ec = binder.getApplicationContext().getBean("ec.0.errors", + String s = testBinder.getBinder().getBinderIdentity() + ".output.errors"; + //return this.getBinderIdentity() + "-" + this.hashCode() + "." + bindingName + ".errors"; + SubscribableChannel ec = binder.getApplicationContext().getBean(s, SubscribableChannel.class); final AtomicReference> errorMessage = new AtomicReference<>(); final CountDownLatch latch = new CountDownLatch(2); @@ -1299,6 +1302,7 @@ public class RabbitBinderTests extends properties.setMaxAttempts(withRetry ? 2 : 1); properties.setPartitioned(true); properties.setInstanceIndex(0); + properties.populateBindingName("blahblah"); DirectChannel input0 = createBindableChannel("input", createConsumerBindingProperties(properties)); input0.setBeanName("test.input0DLQ"); @@ -1355,11 +1359,9 @@ public class RabbitBinderTests extends } }); - ApplicationContext context = TestUtils.getPropertyValue(binder.getBinder(), "applicationContext", ApplicationContext.class); - SubscribableChannel boundErrorChannel = context.getBean( - "bindertest.partPubDLQ.0.dlqPartGrp-0.errors", SubscribableChannel.class); + SubscribableChannel boundErrorChannel = context.getBean(testBinder.getBinder().getBinderIdentity() + ".blahblah.errors", SubscribableChannel.class); SubscribableChannel globalErrorChannel = context.getBean("errorChannel", SubscribableChannel.class); final AtomicReference> boundErrorChannelMessage = new AtomicReference<>(); diff --git a/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/AbstractBinder.java b/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/AbstractBinder.java index 55a7f0cdc..b99da4dbe 100644 --- a/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/AbstractBinder.java +++ b/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/AbstractBinder.java @@ -26,6 +26,7 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.cloud.stream.annotation.StreamRetryTemplate; +import org.springframework.cloud.stream.config.BindingServiceProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.support.AbstractApplicationContext; @@ -166,6 +167,21 @@ public abstract class AbstractBinder errorBridge); } @@ -696,17 +706,19 @@ public abstract class AbstractMessageChannelBinder errorHandler = catalog.lookup(Consumer.class, bp.getErrorHandlerDefinition()); - if (errorHandler == null) { - logger.warn("Failed to retrieve error handling function with definition: " + bp.getErrorHandlerDefinition() + ", for binding: " + bindingName); - } - else { - SubscribableChannel functionErrorChannel = getApplicationContext().getBean(errorChannelName, SubscribableChannel.class); - functionErrorChannel.subscribe(errorMessage -> errorHandler.accept((ErrorMessage) errorMessage)); + BindingServiceProperties bsp = this.getBindingServiceProperties(); + if (bsp != null) { + BindingProperties bp = bsp.getBindingProperties(bindingName); + if (bp != null && StringUtils.hasText(bp.getErrorHandlerDefinition())) { + FunctionCatalog catalog = getApplicationContext().getBean(FunctionCatalog.class); + Consumer errorHandler = catalog.lookup(Consumer.class, bp.getErrorHandlerDefinition()); + if (errorHandler == null) { + logger.warn("Failed to retrieve error handling function with definition: " + bp.getErrorHandlerDefinition() + ", for binding: " + bindingName); + } + else { + SubscribableChannel functionErrorChannel = getApplicationContext().getBean(errorChannelName, SubscribableChannel.class); + functionErrorChannel.subscribe(errorMessage -> errorHandler.accept((ErrorMessage) errorMessage)); + } } } } @@ -841,9 +853,9 @@ public abstract class AbstractMessageChannelBinder doGetExtendedInfo(Object destination, Object properties) { diff --git a/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/Binder.java b/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/Binder.java index 0e8c5ba8a..aef0b6df8 100644 --- a/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/Binder.java +++ b/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/Binder.java @@ -30,10 +30,20 @@ package org.springframework.cloud.stream.binder; * @author Jennifer Hickey * @author Ilayaperumal Gopinathan * @author Marius Bogoevici + * @author Oleg Zhurakousky * @since 1.0 */ public interface Binder { + /** + * Returns instance identity of this binder. + * Individual binders should normally override this method. + * @return instance identity of this binder + */ + default String getBinderIdentity() { + return String.valueOf(this.hashCode()); + } + /** * Bind the target component as a message consumer to the logical entity identified by * the name. diff --git a/core/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/test/TestChannelBinderTests.java b/core/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/test/TestChannelBinderTests.java index 938d29dde..1fb29aac8 100644 --- a/core/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/test/TestChannelBinderTests.java +++ b/core/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/test/TestChannelBinderTests.java @@ -43,7 +43,7 @@ public class TestChannelBinderTests { "--spring.cloud.stream.bindings.function-in-0.destination=input")) { TestChannelBinder binder = context.getBean(TestChannelBinder.class); Method registerErrorInfrastructure = ReflectionUtils - .findMethod(TestChannelBinder.class, "registerErrorInfrastructure", ProducerDestination.class); + .findMethod(TestChannelBinder.class, "registerErrorInfrastructure", ProducerDestination.class, String.class); registerErrorInfrastructure.setAccessible(true); ProducerDestination destination = new ProducerDestination() { @Override @@ -56,7 +56,7 @@ public class TestChannelBinderTests { return "sample"; } }; - registerErrorInfrastructure.invoke(binder, destination); + registerErrorInfrastructure.invoke(binder, destination, "function-in-0"); destination = new ProducerDestination() { @Override public String getNameForPartition(int partition) { @@ -68,7 +68,7 @@ public class TestChannelBinderTests { return "sample"; } }; - registerErrorInfrastructure.invoke(binder, destination); + registerErrorInfrastructure.invoke(binder, destination, "function-in-0"); } }