From e30faf4cffe7aa496cedb94f361451903e8cc7df Mon Sep 17 00:00:00 2001 From: root Date: Fri, 26 Jun 2026 11:41:56 +0800 Subject: [PATCH] =?UTF-8?q?fix(stream):=20=E7=BC=BA=20StringRedisTemplate?= =?UTF-8?q?=20Bean=20=E6=97=B6=E8=87=AA=E5=8A=A8=E8=A3=85=E9=85=8D?= =?UTF-8?q?=E4=BC=98=E9=9B=85=E9=80=80=E5=9C=BA,=E5=AF=B9=E9=BD=90=20cache?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit stream 装配此前仅 @ConditionalOnClass,缺 StringRedisTemplate Bean 时 (如 exclude RedisAutoConfiguration)会因构造参数缺依赖而启动失败。加 @ConditionalOnBean(StringRedisTemplate) 使整类 back off,与 cache 一致; 顺带 @Configuration(proxyBeanMethods=false) 对齐风格。补 3 个装配测试。 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../RedisStreamAutoConfiguration.java | 4 +- .../RedisStreamAutoConfigurationTest.java | 71 +++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/njcn/middle/stream/autoconfig/RedisStreamAutoConfigurationTest.java diff --git a/src/main/java/com/njcn/middle/stream/autoconfig/RedisStreamAutoConfiguration.java b/src/main/java/com/njcn/middle/stream/autoconfig/RedisStreamAutoConfiguration.java index 677ba3f..ff814f1 100644 --- a/src/main/java/com/njcn/middle/stream/autoconfig/RedisStreamAutoConfiguration.java +++ b/src/main/java/com/njcn/middle/stream/autoconfig/RedisStreamAutoConfiguration.java @@ -8,6 +8,7 @@ import com.njcn.middle.stream.support.StreamTrimScheduler; import com.njcn.middle.stream.template.RedisStreamEnhanceTemplate; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; @@ -26,8 +27,9 @@ import java.util.stream.Collectors; * Phase 2 由 message-boot 注入 Processor 即生效。装配在 {@link RedisAutoConfiguration} 之后, * 确保 {@link StringRedisTemplate} 已就绪。 */ -@Configuration +@Configuration(proxyBeanMethods = false) @ConditionalOnClass(StringRedisTemplate.class) +@ConditionalOnBean(StringRedisTemplate.class) @AutoConfigureAfter(RedisAutoConfiguration.class) @EnableConfigurationProperties(RedisStreamProperties.class) public class RedisStreamAutoConfiguration { diff --git a/src/test/java/com/njcn/middle/stream/autoconfig/RedisStreamAutoConfigurationTest.java b/src/test/java/com/njcn/middle/stream/autoconfig/RedisStreamAutoConfigurationTest.java new file mode 100644 index 0000000..41dfbef --- /dev/null +++ b/src/test/java/com/njcn/middle/stream/autoconfig/RedisStreamAutoConfigurationTest.java @@ -0,0 +1,71 @@ +package com.njcn.middle.stream.autoconfig; + +import com.njcn.middle.stream.container.StreamAutoClaimer; +import com.njcn.middle.stream.container.StreamListenerContainer; +import com.njcn.middle.stream.support.StreamKeyBuilder; +import com.njcn.middle.stream.support.StreamTrimScheduler; +import com.njcn.middle.stream.template.RedisStreamEnhanceTemplate; +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.StringRedisTemplate; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * 自动装配测试:验证 stream starter 的 Bean 装配、用户自定义回退、以及缺 {@link StringRedisTemplate} + * 时整类优雅退场(与 cache 装配口径对齐,不因缺依赖启动失败)。 + */ +class RedisStreamAutoConfigurationTest { + + private final ApplicationContextRunner runner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + RedisAutoConfiguration.class, RedisStreamAutoConfiguration.class)) + .withPropertyValues("spring.redis.host=127.0.0.1", "spring.redis.port=6379"); + + @Test + void registersStreamBeans() { + runner.run(ctx -> { + assertThat(ctx).hasSingleBean(StreamKeyBuilder.class); + assertThat(ctx).hasSingleBean(RedisStreamEnhanceTemplate.class); + assertThat(ctx).hasSingleBean(StreamListenerContainer.class); + assertThat(ctx).hasSingleBean(StreamAutoClaimer.class); + assertThat(ctx).hasSingleBean(StreamTrimScheduler.class); + }); + } + + @Test + void backsOffWhenUserDefinesOwnTemplate() { + runner.withUserConfiguration(CustomConfig.class).run(ctx -> { + assertThat(ctx).hasSingleBean(RedisStreamEnhanceTemplate.class); + assertThat(ctx.getBean(RedisStreamEnhanceTemplate.class)) + .isSameAs(ctx.getBean("myTemplate")); + }); + } + + @Test + void backsOffWhenNoStringRedisTemplateBean() { + // 不装配 RedisAutoConfiguration,上下文内无 StringRedisTemplate Bean: + // 应整类 back off 优雅退场,而非因缺依赖启动失败(与 cache 装配口径一致)。 + new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(RedisStreamAutoConfiguration.class)) + .run(ctx -> assertThat(ctx) + .hasNotFailed() + .doesNotHaveBean(RedisStreamEnhanceTemplate.class)); + } + + @Configuration + static class CustomConfig { + @Bean + RedisStreamEnhanceTemplate myTemplate() { + return new RedisStreamEnhanceTemplate( + new StringRedisTemplate(mock(RedisConnectionFactory.class)), + new StreamKeyBuilder(false, "")); + } + } +}