From 5bccee3c9c991a61800aba1481306e5d2e23bd65 Mon Sep 17 00:00:00 2001 From: Dongliang Xie Date: Wed, 8 Jul 2026 11:01:13 +0800 Subject: [PATCH] Resolve @RedisListener topic placeholders. Closes #3393 Signed-off-by: Dongliang Xie --- ...isListenerAnnotationBeanPostProcessor.java | 3 +- ...tionBeanPostProcessorIntegrationTests.java | 29 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/springframework/data/redis/annotation/RedisListenerAnnotationBeanPostProcessor.java b/src/main/java/org/springframework/data/redis/annotation/RedisListenerAnnotationBeanPostProcessor.java index 4d336f9553..61d4345218 100644 --- a/src/main/java/org/springframework/data/redis/annotation/RedisListenerAnnotationBeanPostProcessor.java +++ b/src/main/java/org/springframework/data/redis/annotation/RedisListenerAnnotationBeanPostProcessor.java @@ -69,6 +69,7 @@ * @author Ilyass Bougati * @author Mark Paluch * @author Christoph Strobl + * @author Dongliang Xie * @since 4.1 * @see RedisListener */ @@ -248,7 +249,7 @@ public MethodRedisListenerEndpoint createEndpoint(RedisListener redisListener, M MethodRedisListenerEndpoint endpoint = new MethodRedisListenerEndpoint(bean, method); endpoint.setMessageHandlerMethodFactory(this.messageHandlerMethodFactory); endpoint.setId(getEndpointId(redisListener)); - endpoint.setTopic(redisListener.topic()); + endpoint.setTopic(resolve(redisListener.topic())); endpoint.setConsumes(redisListener.consumes()); return endpoint; diff --git a/src/test/java/org/springframework/data/redis/annotation/RedisListenerAnnotationBeanPostProcessorIntegrationTests.java b/src/test/java/org/springframework/data/redis/annotation/RedisListenerAnnotationBeanPostProcessorIntegrationTests.java index 7ea40c5fd3..5c48d236d4 100644 --- a/src/test/java/org/springframework/data/redis/annotation/RedisListenerAnnotationBeanPostProcessorIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/annotation/RedisListenerAnnotationBeanPostProcessorIntegrationTests.java @@ -19,10 +19,12 @@ import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; +import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; @@ -30,6 +32,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.MapPropertySource; import org.springframework.data.redis.config.RedisListenerConfigUtils; import org.springframework.data.redis.config.RedisListenerEndpointRegistry; import org.springframework.data.redis.listener.RedisMessageListenerContainer; @@ -40,6 +43,7 @@ * * @author Ilyass Bougati * @author Mark Paluch + * @author Dongliang Xie */ class RedisListenerAnnotationBeanPostProcessorIntegrationTests { @@ -62,6 +66,24 @@ void registersListenerWithDefaultContainer() { assertThat(registryRef.get().isRunning()).isFalse(); } + @Test // GH-3393 + void resolvesListenerTopicPlaceholder() { + + try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) { + context.getEnvironment().getPropertySources() + .addFirst(new MapPropertySource("redis-listener-test", Map.of("app.my-channel", "my-channel"))); + context.register(DefaultConfig.class, PlaceholderTopicService.class); + context.refresh(); + + RedisMessageListenerContainer container = context.getBean("redisMessageListenerContainer", + RedisMessageListenerContainer.class); + ArgumentCaptor topicCaptor = ArgumentCaptor.forClass(Topic.class); + + verify(container).addMessageListener(any(), topicCaptor.capture()); + assertThat(topicCaptor.getValue().getTopic()).isEqualTo("my-channel"); + } + } + @Test // GH-3340 void registersListenerWithNamedContainer() { @@ -140,6 +162,13 @@ public void handle(String msg) {} } + static class PlaceholderTopicService { + + @RedisListener(topic = "${app.my-channel}") + public void handle(String msg) {} + + } + static class UnnamedContainerService { @RedisListener(topic = "test-topic", container = "")