From 333b640d0e840f2e8722fd5f820a23bc0ac0010c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=84=EC=88=98=ED=98=84?= Date: Tue, 23 Apr 2024 15:19:28 +0900 Subject: [PATCH 1/2] Add Redis ClientOptions Customizer --- .../redis/ClientOptionsBuilderCustomizer.java | 37 +++++++++++++++++++ .../redis/LettuceConnectionConfiguration.java | 30 +++++++++------ .../redis/RedisAutoConfigurationTests.java | 7 ++++ 3 files changed, 62 insertions(+), 12 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/ClientOptionsBuilderCustomizer.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/ClientOptionsBuilderCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/ClientOptionsBuilderCustomizer.java new file mode 100644 index 000000000000..c02ddf58a1cc --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/ClientOptionsBuilderCustomizer.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012-2023 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.data.redis; + +import io.lettuce.core.ClientOptions; + +/** + * Callback interface that can be implemented by beans wishing to customize the + * {@link ClientOptions} through a {@link ClientOptions.Builder} whilst retaining default + * auto-configuration. + * + * @author Soohyun Lim + */ +@FunctionalInterface +public interface ClientOptionsBuilderCustomizer { + + /** + * Customize the {@link ClientOptions.Builder}. + * @param clientOptionsBuilder the builder to customize + */ + void customize(ClientOptions.Builder clientOptionsBuilder); + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java index c987df24b8e7..89a36a491e09 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java @@ -88,18 +88,20 @@ DefaultClientResources lettuceClientResources(ObjectProvider builderCustomizers, + ObjectProvider clientConfigurationBuilderCustomizers, + ObjectProvider clientOptionsBuilderCustomizers, ClientResources clientResources) { - return createConnectionFactory(builderCustomizers, clientResources); + return createConnectionFactory(clientConfigurationBuilderCustomizers, clientOptionsBuilderCustomizers, clientResources); } @Bean @ConditionalOnMissingBean(RedisConnectionFactory.class) @ConditionalOnThreading(Threading.VIRTUAL) LettuceConnectionFactory redisConnectionFactoryVirtualThreads( - ObjectProvider builderCustomizers, + ObjectProvider clientConfigurationBuilderCustomizers, + ObjectProvider clientOptionsBuilderCustomizers, ClientResources clientResources) { - LettuceConnectionFactory factory = createConnectionFactory(builderCustomizers, clientResources); + LettuceConnectionFactory factory = createConnectionFactory(clientConfigurationBuilderCustomizers, clientOptionsBuilderCustomizers, clientResources); SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor("redis-"); executor.setVirtualThreads(true); factory.setExecutor(executor); @@ -107,10 +109,11 @@ LettuceConnectionFactory redisConnectionFactoryVirtualThreads( } private LettuceConnectionFactory createConnectionFactory( - ObjectProvider builderCustomizers, + ObjectProvider clientConfigurationBuilderCustomizers, + ObjectProvider clientOptionsBuilderCustomizers, ClientResources clientResources) { - LettuceClientConfiguration clientConfig = getLettuceClientConfiguration(builderCustomizers, clientResources, - getProperties().getLettuce().getPool()); + LettuceClientConfiguration clientConfig = getLettuceClientConfiguration(clientConfigurationBuilderCustomizers, clientOptionsBuilderCustomizers, + clientResources, getProperties().getLettuce().getPool()); return createLettuceConnectionFactory(clientConfig); } @@ -125,16 +128,17 @@ private LettuceConnectionFactory createLettuceConnectionFactory(LettuceClientCon } private LettuceClientConfiguration getLettuceClientConfiguration( - ObjectProvider builderCustomizers, + ObjectProvider clientConfigurationBuilderCustomizers, + ObjectProvider clientOptionsBuilderCustomizers, ClientResources clientResources, Pool pool) { LettuceClientConfigurationBuilder builder = createBuilder(pool); applyProperties(builder); if (StringUtils.hasText(getProperties().getUrl())) { customizeConfigurationFromUrl(builder); } - builder.clientOptions(createClientOptions()); + builder.clientOptions(createClientOptions(clientOptionsBuilderCustomizers)); builder.clientResources(clientResources); - builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder)); + clientConfigurationBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder)); return builder.build(); } @@ -163,7 +167,7 @@ private void applyProperties(LettuceClientConfiguration.LettuceClientConfigurati } } - private ClientOptions createClientOptions() { + private ClientOptions createClientOptions(ObjectProvider clientConfigurationBuilderCustomizers) { ClientOptions.Builder builder = initializeClientOptionsBuilder(); Duration connectTimeout = getProperties().getConnectTimeout(); if (connectTimeout != null) { @@ -183,7 +187,9 @@ private ClientOptions createClientOptions() { } builder.sslOptions(sslOptionsBuilder.build()); } - return builder.timeoutOptions(TimeoutOptions.enabled()).build(); + builder.timeoutOptions(TimeoutOptions.enabled()); + clientConfigurationBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder)); + return builder.build(); } private ClientOptions.Builder initializeClientOptionsBuilder() { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java index 79d33e99f302..dc1c86b9f62f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java @@ -127,6 +127,8 @@ void testCustomizeRedisConfiguration() { this.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> { LettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class); assertThat(cf.isUseSsl()).isTrue(); + cf.getClientConfiguration().getClientOptions().ifPresent(options -> + assertThat(options.isAutoReconnect()).isFalse()); }); } @@ -633,6 +635,11 @@ LettuceClientConfigurationBuilderCustomizer customizer() { return LettuceClientConfigurationBuilder::useSsl; } + @Bean + ClientOptionsBuilderCustomizer clientOptionsBuilderCustomizer() { + return builder -> builder.autoReconnect(false); + } + } @Configuration(proxyBeanMethods = false) From b649ca9ad3cabb9c9cb05f9189037a10954e5d6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=84=EC=88=98=ED=98=84?= Date: Thu, 2 May 2024 10:15:16 +0900 Subject: [PATCH 2/2] Rename ClientOptionsBuilderCustomizer to LettuceClientOptionsBuilderCustomizer --- ...java => LettuceClientOptionsBuilderCustomizer.java} | 2 +- .../data/redis/LettuceConnectionConfiguration.java | 10 +++++----- .../data/redis/RedisAutoConfigurationTests.java | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) rename spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/{ClientOptionsBuilderCustomizer.java => LettuceClientOptionsBuilderCustomizer.java} (95%) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/ClientOptionsBuilderCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceClientOptionsBuilderCustomizer.java similarity index 95% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/ClientOptionsBuilderCustomizer.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceClientOptionsBuilderCustomizer.java index c02ddf58a1cc..288c50f7d0d4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/ClientOptionsBuilderCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceClientOptionsBuilderCustomizer.java @@ -26,7 +26,7 @@ * @author Soohyun Lim */ @FunctionalInterface -public interface ClientOptionsBuilderCustomizer { +public interface LettuceClientOptionsBuilderCustomizer { /** * Customize the {@link ClientOptions.Builder}. diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java index 89a36a491e09..4354d4cefd88 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java @@ -89,7 +89,7 @@ DefaultClientResources lettuceClientResources(ObjectProvider clientConfigurationBuilderCustomizers, - ObjectProvider clientOptionsBuilderCustomizers, + ObjectProvider clientOptionsBuilderCustomizers, ClientResources clientResources) { return createConnectionFactory(clientConfigurationBuilderCustomizers, clientOptionsBuilderCustomizers, clientResources); } @@ -99,7 +99,7 @@ LettuceConnectionFactory redisConnectionFactory( @ConditionalOnThreading(Threading.VIRTUAL) LettuceConnectionFactory redisConnectionFactoryVirtualThreads( ObjectProvider clientConfigurationBuilderCustomizers, - ObjectProvider clientOptionsBuilderCustomizers, + ObjectProvider clientOptionsBuilderCustomizers, ClientResources clientResources) { LettuceConnectionFactory factory = createConnectionFactory(clientConfigurationBuilderCustomizers, clientOptionsBuilderCustomizers, clientResources); SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor("redis-"); @@ -110,7 +110,7 @@ LettuceConnectionFactory redisConnectionFactoryVirtualThreads( private LettuceConnectionFactory createConnectionFactory( ObjectProvider clientConfigurationBuilderCustomizers, - ObjectProvider clientOptionsBuilderCustomizers, + ObjectProvider clientOptionsBuilderCustomizers, ClientResources clientResources) { LettuceClientConfiguration clientConfig = getLettuceClientConfiguration(clientConfigurationBuilderCustomizers, clientOptionsBuilderCustomizers, clientResources, getProperties().getLettuce().getPool()); @@ -129,7 +129,7 @@ private LettuceConnectionFactory createLettuceConnectionFactory(LettuceClientCon private LettuceClientConfiguration getLettuceClientConfiguration( ObjectProvider clientConfigurationBuilderCustomizers, - ObjectProvider clientOptionsBuilderCustomizers, + ObjectProvider clientOptionsBuilderCustomizers, ClientResources clientResources, Pool pool) { LettuceClientConfigurationBuilder builder = createBuilder(pool); applyProperties(builder); @@ -167,7 +167,7 @@ private void applyProperties(LettuceClientConfiguration.LettuceClientConfigurati } } - private ClientOptions createClientOptions(ObjectProvider clientConfigurationBuilderCustomizers) { + private ClientOptions createClientOptions(ObjectProvider clientConfigurationBuilderCustomizers) { ClientOptions.Builder builder = initializeClientOptionsBuilder(); Duration connectTimeout = getProperties().getConnectTimeout(); if (connectTimeout != null) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java index dc1c86b9f62f..add58f791dd4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java @@ -636,7 +636,7 @@ LettuceClientConfigurationBuilderCustomizer customizer() { } @Bean - ClientOptionsBuilderCustomizer clientOptionsBuilderCustomizer() { + LettuceClientOptionsBuilderCustomizer clientOptionsBuilderCustomizer() { return builder -> builder.autoReconnect(false); }