diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/DefaultConfiguringBeanFactoryPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/config/DefaultConfiguringBeanFactoryPostProcessor.java index 83fb6708d9..5178becb79 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/DefaultConfiguringBeanFactoryPostProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/DefaultConfiguringBeanFactoryPostProcessor.java @@ -36,12 +36,14 @@ import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.core.Ordered; import org.springframework.core.log.LogAccessor; import org.springframework.integration.channel.ChannelUtils; import org.springframework.integration.channel.DefaultHeaderChannelRegistry; import org.springframework.integration.channel.MessagePublishingErrorHandler; import org.springframework.integration.channel.NullChannel; import org.springframework.integration.channel.PublishSubscribeChannel; +import org.springframework.integration.config.xml.IntegrationNamespaceUtils; import org.springframework.integration.context.IntegrationContextUtils; import org.springframework.integration.context.IntegrationProperties; import org.springframework.integration.handler.LoggingHandler; @@ -221,6 +223,7 @@ public class DefaultConfiguringBeanFactoryPostProcessor BeanDefinitionBuilder.genericBeanDefinition(LoggingHandler.class, () -> new LoggingHandler(LoggingHandler.Level.ERROR)) .addConstructorArgValue(LoggingHandler.Level.ERROR) + .addPropertyValue(IntegrationNamespaceUtils.ORDER, Ordered.LOWEST_PRECEDENCE - 100) .getBeanDefinition()); BeanDefinitionBuilder loggingEndpointBuilder = diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ErrorChannelAutoCreationTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ErrorChannelAutoCreationTests.java index 325da3d448..7ebd0c8738 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ErrorChannelAutoCreationTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ErrorChannelAutoCreationTests.java @@ -16,12 +16,17 @@ package org.springframework.integration.config.xml; +import java.util.Set; + import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.Ordered; import org.springframework.integration.channel.PublishSubscribeChannel; +import org.springframework.integration.handler.LoggingHandler; import org.springframework.integration.test.util.TestUtils; import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.MessageHandler; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; import static org.assertj.core.api.Assertions.assertThat; @@ -43,6 +48,15 @@ public class ErrorChannelAutoCreationTests { .isTrue(); assertThat(TestUtils.getPropertyValue(this.errorChannel, "dispatcher.ignoreFailures", Boolean.class)) .isTrue(); + + @SuppressWarnings("unchecked") + Set handlers = + TestUtils.getPropertyValue(this.errorChannel, "dispatcher.handlers", Set.class); + + assertThat(handlers).first() + .isInstanceOf(LoggingHandler.class) + .extracting("order") + .isEqualTo(Ordered.LOWEST_PRECEDENCE - 100); } } diff --git a/src/reference/asciidoc/error-handling.adoc b/src/reference/asciidoc/error-handling.adoc index 2553094628..80d9a48fd8 100644 --- a/src/reference/asciidoc/error-handling.adoc +++ b/src/reference/asciidoc/error-handling.adoc @@ -52,6 +52,8 @@ QueueChannel errorChannel() { ==== NOTE: The default error channel is a `PublishSubscribeChannel`. +By default, it has a `LoggingHandler` as a subscriber with an `ERROR` logging level and subscription order as `Ordered.LOWEST_PRECEDENCE - 100`. +If you subscribe additional consuming endpoints, that might throw an exception, and you don't want to preempt the logging, ensure that the additional handlers have a higher order. 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).