feat(idempotent): 更新 IdempotentAutoConfiguration 和 IdempotentAutoConfigurationTests

- 移除冗余代码,简化 KeyResolver 和 RedissonClient 的配置
- 增强对 Redis 集群和哨兵模式的支持
- 更新测试用例以验证新的配置逻辑

(cherry picked from commit 0064a36a79cbd17c287eef358def60ea58bc9fbd)
This commit is contained in:
PIGCLOUD committed 2026-11-03 14:49:14 +08:00
1 parent 464c6df5b8
commit 2bc231f1bf
2 files changed
+129 -132

No files matched your search

@@ -29,77 +29,74 @@ import org.springframework.util.StringUtils;
@EnableConfigurationProperties(DataRedisProperties.class)
public class IdempotentAutoConfiguration {
/**
* KEY解析器
* @return {@link KeyResolver }
*/
@Bean
@ConditionalOnMissingBean(KeyResolver.class)
public KeyResolver keyResolver() {
return new ExpressionResolver();
}
/**
* KEY解析器
*
* @return {@link KeyResolver }
*/
@Bean
@ConditionalOnMissingBean(KeyResolver.class)
public KeyResolver keyResolver() {
return new ExpressionResolver();
}
/**
* 幂等 Redis 客户端
* @param redisProperties Redis 连接配置
* @return Redisson 客户端
*/
@Bean
@ConditionalOnMissingBean(RedissonClient.class)
public RedissonClient redissonClient(DataRedisProperties redisProperties) {
Config config = new Config();
BaseConfig<?> serverConfig;
if (redisProperties.getSentinel() != null) {
DataRedisProperties.Sentinel sentinel = redisProperties.getSentinel();
SentinelServersConfig sentinelConfig = config.useSentinelServers()
.setMasterName(sentinel.getMaster())
.setDatabase(redisProperties.getDatabase());
for (String node : sentinel.getNodes()) {
sentinelConfig.addSentinelAddress("redis://" + node);
}
if (StringUtils.hasText(sentinel.getUsername())) {
sentinelConfig.setSentinelUsername(sentinel.getUsername());
}
if (StringUtils.hasText(sentinel.getPassword())) {
sentinelConfig.setSentinelPassword(sentinel.getPassword());
}
serverConfig = sentinelConfig;
}
else if (redisProperties.getCluster() != null) {
ClusterServersConfig clusterConfig = config.useClusterServers();
for (String node : redisProperties.getCluster().getNodes()) {
clusterConfig.addNodeAddress("redis://" + node);
}
serverConfig = clusterConfig;
}
else {
serverConfig = config.useSingleServer()
.setAddress("redis://" + redisProperties.getHost() + ":" + redisProperties.getPort())
.setDatabase(redisProperties.getDatabase());
}
/**
* 幂等 Redis 客户端
*
* @param redisProperties Redis 连接配置
* @return Redisson 客户端
*/
@Bean
@ConditionalOnMissingBean(RedissonClient.class)
public RedissonClient redissonClient(DataRedisProperties redisProperties) {
Config config = new Config();
BaseConfig<?> serverConfig;
if (redisProperties.getSentinel() != null) {
DataRedisProperties.Sentinel sentinel = redisProperties.getSentinel();
SentinelServersConfig sentinelConfig = config.useSentinelServers()
.setMasterName(sentinel.getMaster())
.setDatabase(redisProperties.getDatabase());
for (String node : sentinel.getNodes()) {
sentinelConfig.addSentinelAddress("redis://" + node);
}
if (StringUtils.hasText(sentinel.getUsername())) {
sentinelConfig.setSentinelUsername(sentinel.getUsername());
}
if (StringUtils.hasText(sentinel.getPassword())) {
sentinelConfig.setSentinelPassword(sentinel.getPassword());
}
serverConfig = sentinelConfig;
}
else if (redisProperties.getCluster() != null) {
ClusterServersConfig clusterConfig = config.useClusterServers();
for (String node : redisProperties.getCluster().getNodes()) {
clusterConfig.addNodeAddress("redis://" + node);
}
serverConfig = clusterConfig;
}
else {
serverConfig = config.useSingleServer()
.setAddress("redis://" + redisProperties.getHost() + ":" + redisProperties.getPort())
.setDatabase(redisProperties.getDatabase());
}
if (StringUtils.hasText(redisProperties.getUsername())) {
serverConfig.setUsername(redisProperties.getUsername());
}
if (StringUtils.hasText(redisProperties.getPassword())) {
serverConfig.setPassword(redisProperties.getPassword());
}
if (redisProperties.getConnectTimeout() != null) {
serverConfig.setConnectTimeout((int) redisProperties.getConnectTimeout().toMillis());
}
if (redisProperties.getTimeout() != null) {
serverConfig.setTimeout((int) redisProperties.getTimeout().toMillis());
}
if (StringUtils.hasText(redisProperties.getUsername())) {
serverConfig.setUsername(redisProperties.getUsername());
}
if (StringUtils.hasText(redisProperties.getPassword())) {
serverConfig.setPassword(redisProperties.getPassword());
}
if (redisProperties.getConnectTimeout() != null) {
serverConfig.setConnectTimeout((int) redisProperties.getConnectTimeout().toMillis());
}
if (redisProperties.getTimeout() != null) {
serverConfig.setTimeout((int) redisProperties.getTimeout().toMillis());
}
return Redisson.create(config);
}
return Redisson.create(config);
}
@Bean
public IdempotentAspect idempotentAspect(RedissonClient redisson, KeyResolver keyResolver) {
return new IdempotentAspect(redisson, keyResolver);
}
@Bean
public IdempotentAspect idempotentAspect(RedissonClient redisson, KeyResolver keyResolver) {
return new IdempotentAspect(redisson, keyResolver);
}
}
@@ -20,72 +20,72 @@ import static org.mockito.Mockito.withSettings;
class IdempotentAutoConfigurationTests {
@Test
void usesClusterNodesInsteadOfDefaultSingleServer() {
DataRedisProperties properties = new DataRedisProperties();
properties.setUsername("cluster-user");
properties.setPassword("cluster-password");
properties.setConnectTimeout(Duration.ofSeconds(2));
properties.setTimeout(Duration.ofSeconds(3));
DataRedisProperties.Cluster cluster = new DataRedisProperties.Cluster();
cluster.setNodes(List.of("redis-1:7000", "redis-2:7001", "redis-3:7002"));
properties.setCluster(cluster);
@Test
void usesClusterNodesInsteadOfDefaultSingleServer() {
DataRedisProperties properties = new DataRedisProperties();
properties.setUsername("cluster-user");
properties.setPassword("cluster-password");
properties.setConnectTimeout(Duration.ofSeconds(2));
properties.setTimeout(Duration.ofSeconds(3));
DataRedisProperties.Cluster cluster = new DataRedisProperties.Cluster();
cluster.setNodes(List.of("redis-1:7000", "redis-2:7001", "redis-3:7002"));
properties.setCluster(cluster);
RedissonClient client = mock(RedissonClient.class);
try (MockedStatic<Redisson> redisson = mockStatic(Redisson.class,
withSettings().mockMaker("mock-maker-inline"))) {
redisson.when(() -> Redisson.create(any(Config.class))).thenAnswer(invocation -> {
Config config = invocation.getArgument(0);
assertThat(config.isClusterConfig()).as("必须使用集群模式连接").isTrue();
ClusterServersConfig servers = config.useClusterServers();
assertThat(servers.getNodeAddresses()).containsExactly(
"redis://redis-1:7000", "redis://redis-2:7001", "redis://redis-3:7002");
assertThat(servers.getUsername()).isEqualTo("cluster-user");
assertThat(servers.getPassword()).isEqualTo("cluster-password");
assertThat(servers.getConnectTimeout()).isEqualTo(2000);
assertThat(servers.getTimeout()).isEqualTo(3000);
return client;
});
assertThat(new IdempotentAutoConfiguration().redissonClient(properties)).isSameAs(client);
}
}
RedissonClient client = mock(RedissonClient.class);
try (MockedStatic<Redisson> redisson = mockStatic(Redisson.class,
withSettings().mockMaker("mock-maker-inline"))) {
redisson.when(() -> Redisson.create(any(Config.class))).thenAnswer(invocation -> {
Config config = invocation.getArgument(0);
assertThat(config.isClusterConfig()).as("必须使用集群模式连接").isTrue();
ClusterServersConfig servers = config.useClusterServers();
assertThat(servers.getNodeAddresses()).containsExactly("redis://redis-1:7000", "redis://redis-2:7001",
"redis://redis-3:7002");
assertThat(servers.getUsername()).isEqualTo("cluster-user");
assertThat(servers.getPassword()).isEqualTo("cluster-password");
assertThat(servers.getConnectTimeout()).isEqualTo(2000);
assertThat(servers.getTimeout()).isEqualTo(3000);
return client;
});
assertThat(new IdempotentAutoConfiguration().redissonClient(properties)).isSameAs(client);
}
}
@Test
void usesSentinelConfigurationInsteadOfDefaultSingleServer() {
DataRedisProperties properties = new DataRedisProperties();
properties.setDatabase(2);
properties.setUsername("data-user");
properties.setPassword("data-password");
properties.setConnectTimeout(Duration.ofSeconds(2));
properties.setTimeout(Duration.ofSeconds(3));
DataRedisProperties.Sentinel sentinel = new DataRedisProperties.Sentinel();
sentinel.setMaster("mymaster");
sentinel.setNodes(List.of("sentinel-1:26379", "sentinel-2:26379"));
sentinel.setUsername("sentinel-user");
sentinel.setPassword("sentinel-password");
properties.setSentinel(sentinel);
@Test
void usesSentinelConfigurationInsteadOfDefaultSingleServer() {
DataRedisProperties properties = new DataRedisProperties();
properties.setDatabase(2);
properties.setUsername("data-user");
properties.setPassword("data-password");
properties.setConnectTimeout(Duration.ofSeconds(2));
properties.setTimeout(Duration.ofSeconds(3));
DataRedisProperties.Sentinel sentinel = new DataRedisProperties.Sentinel();
sentinel.setMaster("mymaster");
sentinel.setNodes(List.of("sentinel-1:26379", "sentinel-2:26379"));
sentinel.setUsername("sentinel-user");
sentinel.setPassword("sentinel-password");
properties.setSentinel(sentinel);
RedissonClient client = mock(RedissonClient.class);
try (MockedStatic<Redisson> redisson = mockStatic(Redisson.class,
withSettings().mockMaker("mock-maker-inline"))) {
redisson.when(() -> Redisson.create(any(Config.class))).thenAnswer(invocation -> {
Config config = invocation.getArgument(0);
assertThat(config.isSentinelConfig()).as("必须使用哨兵模式连接").isTrue();
SentinelServersConfig servers = config.useSentinelServers();
assertThat(servers.getMasterName()).isEqualTo("mymaster");
assertThat(servers.getSentinelAddresses())
.containsExactly("redis://sentinel-1:26379", "redis://sentinel-2:26379");
assertThat(servers.getSentinelUsername()).isEqualTo("sentinel-user");
assertThat(servers.getSentinelPassword()).isEqualTo("sentinel-password");
assertThat(servers.getUsername()).isEqualTo("data-user");
assertThat(servers.getPassword()).isEqualTo("data-password");
assertThat(servers.getDatabase()).isEqualTo(2);
assertThat(servers.getConnectTimeout()).isEqualTo(2000);
assertThat(servers.getTimeout()).isEqualTo(3000);
return client;
});
assertThat(new IdempotentAutoConfiguration().redissonClient(properties)).isSameAs(client);
}
}
RedissonClient client = mock(RedissonClient.class);
try (MockedStatic<Redisson> redisson = mockStatic(Redisson.class,
withSettings().mockMaker("mock-maker-inline"))) {
redisson.when(() -> Redisson.create(any(Config.class))).thenAnswer(invocation -> {
Config config = invocation.getArgument(0);
assertThat(config.isSentinelConfig()).as("必须使用哨兵模式连接").isTrue();
SentinelServersConfig servers = config.useSentinelServers();
assertThat(servers.getMasterName()).isEqualTo("mymaster");
assertThat(servers.getSentinelAddresses()).containsExactly("redis://sentinel-1:26379",
"redis://sentinel-2:26379");
assertThat(servers.getSentinelUsername()).isEqualTo("sentinel-user");
assertThat(servers.getSentinelPassword()).isEqualTo("sentinel-password");
assertThat(servers.getUsername()).isEqualTo("data-user");
assertThat(servers.getPassword()).isEqualTo("data-password");
assertThat(servers.getDatabase()).isEqualTo(2);
assertThat(servers.getConnectTimeout()).isEqualTo(2000);
assertThat(servers.getTimeout()).isEqualTo(3000);
return client;
});
assertThat(new IdempotentAutoConfiguration().redissonClient(properties)).isSameAs(client);
}
}
}