From 95fae5a982778096acff85f97ee9f2b4d44c82ca Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Fri, 7 Mar 2025 15:54:15 +0800 Subject: [PATCH] Introduce PollerMetadataCustomizer for Spring Integration Fix GH-44534 Signed-off-by: Yanming Zhou --- .../IntegrationAutoConfiguration.java | 6 ++- .../integration/PollerMetadataCustomizer.java | 37 +++++++++++++++++++ .../IntegrationAutoConfigurationTests.java | 16 ++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/PollerMetadataCustomizer.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java index 3abe6c4c411b..0f19e1db2bf8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java @@ -24,6 +24,7 @@ import io.rsocket.transport.netty.server.TcpServerTransport; import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; @@ -85,6 +86,7 @@ * @author Vedran Pavic * @author Madhura Bhave * @author Yong-Hyun Kim + * @author Yanming Zhou * @since 1.1.0 */ @AutoConfiguration(after = { DataSourceAutoConfiguration.class, JmxAutoConfiguration.class, @@ -130,7 +132,8 @@ protected static class IntegrationConfiguration { @Bean(PollerMetadata.DEFAULT_POLLER) @ConditionalOnMissingBean(name = PollerMetadata.DEFAULT_POLLER) - public PollerMetadata defaultPollerMetadata(IntegrationProperties integrationProperties) { + public PollerMetadata defaultPollerMetadata(IntegrationProperties integrationProperties, + ObjectProvider customizers) { IntegrationProperties.Poller poller = integrationProperties.getPoller(); MutuallyExclusiveConfigurationPropertiesException.throwIfMultipleNonNullValuesIn((entries) -> { entries.put("spring.integration.poller.cron", @@ -143,6 +146,7 @@ public PollerMetadata defaultPollerMetadata(IntegrationProperties integrationPro map.from(poller::getMaxMessagesPerPoll).to(pollerMetadata::setMaxMessagesPerPoll); map.from(poller::getReceiveTimeout).as(Duration::toMillis).to(pollerMetadata::setReceiveTimeout); map.from(poller).as(this::asTrigger).to(pollerMetadata::setTrigger); + customizers.orderedStream().forEach((customizer) -> customizer.customize(pollerMetadata)); return pollerMetadata; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/PollerMetadataCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/PollerMetadataCustomizer.java new file mode 100644 index 000000000000..d669faa5b991 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/PollerMetadataCustomizer.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.integration; + +import org.springframework.integration.scheduling.PollerMetadata; + +/** + * Callback interface that can be implemented by beans wishing to customize the + * {@link PollerMetadata} whilst retaining default auto-configuration. + * + * @author Yanming Zhou + * @since 3.5.0 + */ +@FunctionalInterface +public interface PollerMetadataCustomizer { + + /** + * Customize the {@link PollerMetadata}. + * @param pollerMetadata the {@code PollerMetadata} to customize + */ + void customize(PollerMetadata pollerMetadata); + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java index 8ab1525fd768..95ea34deac33 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java @@ -62,6 +62,8 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.core.task.SyncTaskExecutor; +import org.springframework.core.task.TaskExecutor; import org.springframework.integration.annotation.IntegrationComponentScan; import org.springframework.integration.annotation.MessagingGateway; import org.springframework.integration.annotation.ServiceActivator; @@ -105,6 +107,7 @@ * @author Stephane Nicoll * @author Vedran Pavic * @author Yong-Hyun Kim + * @author Yanming Zhou */ class IntegrationAutoConfigurationTests { @@ -543,6 +546,19 @@ void integrationVirtualThreadsEnabled() { .usesVirtualThreads())); } + @Test + void pollerMetadataCanBeCustomizedViaPollerMetadataCustomizer() { + TaskExecutor taskExecutor = new SyncTaskExecutor(); + this.contextRunner.withUserConfiguration(PollingConsumerConfiguration.class) + .withBean(PollerMetadataCustomizer.class, + () -> (pollerMetadata) -> pollerMetadata.setTaskExecutor(taskExecutor)) + .run((context) -> { + assertThat(context).hasSingleBean(PollerMetadata.class); + PollerMetadata metadata = context.getBean(PollerMetadata.DEFAULT_POLLER, PollerMetadata.class); + assertThat(metadata.getTaskExecutor()).isSameAs(taskExecutor); + }); + } + @Configuration(proxyBeanMethods = false) static class CustomMBeanExporter {