diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/ConnectionFactoryConfigurations.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/ConnectionFactoryConfigurations.java index d918470ba6..3f80c5f81a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/ConnectionFactoryConfigurations.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/ConnectionFactoryConfigurations.java @@ -29,6 +29,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; @@ -43,6 +44,7 @@ import org.springframework.util.StringUtils; * * @author Mark Paluch * @author Stephane Nicoll + * @author Rodolpho S. Couto */ abstract class ConnectionFactoryConfigurations { @@ -68,11 +70,16 @@ abstract class ConnectionFactoryConfigurations { ConnectionFactory connectionFactory = createConnectionFactory(properties, resourceLoader.getClassLoader(), customizers.orderedStream().collect(Collectors.toList())); R2dbcProperties.Pool pool = properties.getPool(); - ConnectionPoolConfiguration.Builder builder = ConnectionPoolConfiguration.builder(connectionFactory) - .maxSize(pool.getMaxSize()).initialSize(pool.getInitialSize()).maxIdleTime(pool.getMaxIdleTime()); - if (StringUtils.hasText(pool.getValidationQuery())) { - builder.validationQuery(pool.getValidationQuery()); - } + PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); + ConnectionPoolConfiguration.Builder builder = ConnectionPoolConfiguration.builder(connectionFactory); + map.from(pool.getMaxIdleTime()).to(builder::maxIdleTime); + map.from(pool.getMaxLifeTime()).to(builder::maxLifeTime); + map.from(pool.getMaxAcquireTime()).to(builder::maxAcquireTime); + map.from(pool.getMaxCreateConnectionTime()).to(builder::maxCreateConnectionTime); + map.from(pool.getInitialSize()).to(builder::initialSize); + map.from(pool.getMaxSize()).to(builder::maxSize); + map.from(pool.getValidationQuery()).whenHasText().to(builder::validationQuery); + map.from(pool.getValidationDepth()).to(builder::validationDepth); return new ConnectionPool(builder.build()); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcProperties.java index 7792e67392..dfbcc9b7a7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcProperties.java @@ -21,6 +21,8 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.UUID; +import io.r2dbc.spi.ValidationDepth; + import org.springframework.boot.context.properties.ConfigurationProperties; /** @@ -29,6 +31,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * @author Mark Paluch * @author Andreas Killaitis * @author Stephane Nicoll + * @author Rodolpho S. Couto * @since 2.3.0 */ @ConfigurationProperties(prefix = "spring.r2dbc") @@ -138,6 +141,23 @@ public class R2dbcProperties { */ private Duration maxIdleTime = Duration.ofMinutes(30); + /** + * Maximum lifetime of a connection in the pool. By default, connections have an + * infinite lifetime. + */ + private Duration maxLifeTime; + + /** + * Maximum time to acquire a connection from the pool. By default, wait + * indefinitely. + */ + private Duration maxAcquireTime; + + /** + * Maximum time to wait to create a new connection. By default, wait indefinitely. + */ + private Duration maxCreateConnectionTime; + /** * Initial connection pool size. */ @@ -153,6 +173,11 @@ public class R2dbcProperties { */ private String validationQuery; + /** + * Validation depth. + */ + private ValidationDepth validationDepth = ValidationDepth.LOCAL; + public Duration getMaxIdleTime() { return this.maxIdleTime; } @@ -161,6 +186,30 @@ public class R2dbcProperties { this.maxIdleTime = maxIdleTime; } + public Duration getMaxLifeTime() { + return this.maxLifeTime; + } + + public void setMaxLifeTime(Duration maxLifeTime) { + this.maxLifeTime = maxLifeTime; + } + + public Duration getMaxAcquireTime() { + return this.maxAcquireTime; + } + + public void setMaxAcquireTime(Duration maxAcquireTime) { + this.maxAcquireTime = maxAcquireTime; + } + + public Duration getMaxCreateConnectionTime() { + return this.maxCreateConnectionTime; + } + + public void setMaxCreateConnectionTime(Duration maxCreateConnectionTime) { + this.maxCreateConnectionTime = maxCreateConnectionTime; + } + public int getInitialSize() { return this.initialSize; } @@ -185,6 +234,14 @@ public class R2dbcProperties { this.validationQuery = validationQuery; } + public ValidationDepth getValidationDepth() { + return this.validationDepth; + } + + public void setValidationDepth(ValidationDepth validationDepth) { + this.validationDepth = validationDepth; + } + } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 7e215490bd..194db53153 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1468,6 +1468,10 @@ "type": "java.lang.Boolean", "description": "Whether pooling is enabled. Enabled automatically if \"r2dbc-pool\" is on the classpath." }, + { + "name": "spring.r2dbc.pool.validation-depth", + "defaultValue": "local" + }, { "name": "spring.rabbitmq.cache.connection.mode", "defaultValue": "channel" diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcAutoConfigurationTests.java index 5e8a3f5998..f8734fde94 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/r2dbc/R2dbcAutoConfigurationTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.r2dbc; import java.net.URL; import java.net.URLClassLoader; +import java.time.Duration; import java.util.UUID; import java.util.function.Function; @@ -62,10 +63,24 @@ class R2dbcAutoConfigurationTests { @Test void configureWithUrlAndPoolPropertiesApplyProperties() { this.contextRunner.withPropertyValues("spring.r2dbc.url:r2dbc:h2:mem:///" + randomDatabaseName(), - "spring.r2dbc.pool.max-size=15").run((context) -> { - assertThat(context).hasSingleBean(ConnectionFactory.class).hasSingleBean(ConnectionPool.class); - PoolMetrics poolMetrics = context.getBean(ConnectionPool.class).getMetrics().get(); + "spring.r2dbc.pool.max-size=15", "spring.r2dbc.pool.max-acquire-time=3m").run((context) -> { + assertThat(context).hasSingleBean(ConnectionFactory.class).hasSingleBean(ConnectionPool.class) + .hasSingleBean(R2dbcProperties.class); + ConnectionPool connectionPool = context.getBean(ConnectionPool.class); + PoolMetrics poolMetrics = connectionPool.getMetrics().get(); assertThat(poolMetrics.getMaxAllocatedSize()).isEqualTo(15); + assertThat(connectionPool).hasFieldOrPropertyWithValue("maxAcquireTime", Duration.ofMinutes(3)); + }); + } + + @Test + void configureWithUrlAndDefaultDoNotOverrideDefaultTimeouts() { + this.contextRunner.withPropertyValues("spring.r2dbc.url:r2dbc:h2:mem:///" + randomDatabaseName()) + .run((context) -> { + assertThat(context).hasSingleBean(ConnectionFactory.class).hasSingleBean(ConnectionPool.class) + .hasSingleBean(R2dbcProperties.class); + ConnectionPool connectionPool = context.getBean(ConnectionPool.class); + assertThat(connectionPool).hasFieldOrPropertyWithValue("maxAcquireTime", Duration.ZERO); }); }