Make URL- and property-based pooling config mutually exclusive
Closes gh-28144
This commit is contained in:
@@ -29,15 +29,21 @@ 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.autoconfigure.r2dbc.R2dbcProperties.Pool;
|
||||
import org.springframework.boot.context.properties.PropertyMapper;
|
||||
import org.springframework.boot.context.properties.bind.BindResult;
|
||||
import org.springframework.boot.context.properties.bind.Bindable;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.boot.r2dbc.EmbeddedDatabaseConnection;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -51,39 +57,54 @@ abstract class ConnectionFactoryConfigurations {
|
||||
|
||||
protected static ConnectionFactory createConnectionFactory(R2dbcProperties properties, ClassLoader classLoader,
|
||||
List<ConnectionFactoryOptionsBuilderCustomizer> optionsCustomizers) {
|
||||
return org.springframework.boot.r2dbc.ConnectionFactoryBuilder
|
||||
.withOptions(new ConnectionFactoryOptionsInitializer().initialize(properties,
|
||||
() -> EmbeddedDatabaseConnection.get(classLoader)))
|
||||
.configure((options) -> {
|
||||
for (ConnectionFactoryOptionsBuilderCustomizer optionsCustomizer : optionsCustomizers) {
|
||||
optionsCustomizer.customize(options);
|
||||
}
|
||||
}).build();
|
||||
try {
|
||||
return org.springframework.boot.r2dbc.ConnectionFactoryBuilder
|
||||
.withOptions(new ConnectionFactoryOptionsInitializer().initialize(properties,
|
||||
() -> EmbeddedDatabaseConnection.get(classLoader)))
|
||||
.configure((options) -> {
|
||||
for (ConnectionFactoryOptionsBuilderCustomizer optionsCustomizer : optionsCustomizers) {
|
||||
optionsCustomizer.customize(options);
|
||||
}
|
||||
}).build();
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
String message = ex.getMessage();
|
||||
if (message != null && message.contains("driver=pool")
|
||||
&& !ClassUtils.isPresent("io.r2dbc.pool.ConnectionPool", classLoader)) {
|
||||
throw new MissingR2dbcPoolDependencyException();
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(ConnectionPool.class)
|
||||
@Conditional(PooledConnectionFactoryCondition.class)
|
||||
@ConditionalOnMissingBean(ConnectionFactory.class)
|
||||
static class Pool {
|
||||
static class PoolConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(ConnectionPool.class)
|
||||
static class PooledConnectionFactoryConfiguration {
|
||||
|
||||
@Bean(destroyMethod = "dispose")
|
||||
ConnectionPool connectionFactory(R2dbcProperties properties, ResourceLoader resourceLoader,
|
||||
ObjectProvider<ConnectionFactoryOptionsBuilderCustomizer> customizers) {
|
||||
ConnectionFactory connectionFactory = createConnectionFactory(properties,
|
||||
resourceLoader.getClassLoader(), customizers.orderedStream().collect(Collectors.toList()));
|
||||
R2dbcProperties.Pool pool = properties.getPool();
|
||||
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());
|
||||
}
|
||||
|
||||
@Bean(destroyMethod = "dispose")
|
||||
ConnectionPool connectionFactory(R2dbcProperties properties, ResourceLoader resourceLoader,
|
||||
ObjectProvider<ConnectionFactoryOptionsBuilderCustomizer> customizers) {
|
||||
ConnectionFactory connectionFactory = createConnectionFactory(properties, resourceLoader.getClassLoader(),
|
||||
customizers.orderedStream().collect(Collectors.toList()));
|
||||
R2dbcProperties.Pool pool = properties.getPool();
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -92,7 +113,7 @@ abstract class ConnectionFactoryConfigurations {
|
||||
@ConditionalOnProperty(prefix = "spring.r2dbc.pool", value = "enabled", havingValue = "false",
|
||||
matchIfMissing = true)
|
||||
@ConditionalOnMissingBean(ConnectionFactory.class)
|
||||
static class Generic {
|
||||
static class GenericConfiguration {
|
||||
|
||||
@Bean
|
||||
ConnectionFactory connectionFactory(R2dbcProperties properties, ResourceLoader resourceLoader,
|
||||
@@ -105,26 +126,35 @@ abstract class ConnectionFactoryConfigurations {
|
||||
|
||||
/**
|
||||
* {@link Condition} that checks that a {@link ConnectionPool} is requested. The
|
||||
* condition matches if pooling was opt-in via configuration and the r2dbc url does
|
||||
* not contain pooling-related options.
|
||||
* condition matches if pooling was opt-in via configuration. If any of the
|
||||
* spring.r2dbc.pool.* properties have been configured, an exception is thrown if the
|
||||
* URL also contains pooling-related options or io.r2dbc.pool.ConnectionPool is not on
|
||||
* the class path.
|
||||
*/
|
||||
static class PooledConnectionFactoryCondition extends SpringBootCondition {
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
boolean poolEnabled = context.getEnvironment().getProperty("spring.r2dbc.pool.enabled", Boolean.class,
|
||||
true);
|
||||
if (poolEnabled) {
|
||||
// Make sure the URL does not have pool options
|
||||
String url = context.getEnvironment().getProperty("spring.r2dbc.url");
|
||||
boolean pooledUrl = StringUtils.hasText(url) && url.contains(":pool:");
|
||||
if (pooledUrl) {
|
||||
return ConditionOutcome.noMatch("R2DBC Connection URL contains pooling-related options");
|
||||
BindResult<Pool> pool = Binder.get(context.getEnvironment()).bind("spring.r2dbc.pool",
|
||||
Bindable.of(Pool.class));
|
||||
if (hasPoolUrl(context.getEnvironment())) {
|
||||
if (pool.isBound()) {
|
||||
throw new MultipleConnectionPoolConfigurationsException();
|
||||
}
|
||||
return ConditionOutcome
|
||||
.match("Pooling is enabled and R2DBC Connection URL does not contain pooling-related options");
|
||||
return ConditionOutcome.noMatch("URL-based pooling has been configured");
|
||||
}
|
||||
return ConditionOutcome.noMatch("Pooling is disabled");
|
||||
if (pool.isBound() && !ClassUtils.isPresent("io.r2dbc.pool.ConnectionPool", context.getClassLoader())) {
|
||||
throw new MissingR2dbcPoolDependencyException();
|
||||
}
|
||||
if (pool.orElseGet(Pool::new).isEnabled()) {
|
||||
return ConditionOutcome.match("Property-based pooling is enabled");
|
||||
}
|
||||
return ConditionOutcome.noMatch("Property-based pooling is disabled");
|
||||
}
|
||||
|
||||
private boolean hasPoolUrl(Environment environment) {
|
||||
String url = environment.getProperty("spring.r2dbc.url");
|
||||
return StringUtils.hasText(url) && url.contains(":pool:");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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.r2dbc;
|
||||
|
||||
/**
|
||||
* Exception thrown when R2DBC connection pooling has been configured but the
|
||||
* {@code io.r2dbc:r2dbc-pool} dependency is missing.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class MissingR2dbcPoolDependencyException extends RuntimeException {
|
||||
|
||||
MissingR2dbcPoolDependencyException() {
|
||||
super("R2DBC connection pooling has been configured but the io.r2dbc.pool.ConnectionPool class is not "
|
||||
+ "present.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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.r2dbc;
|
||||
|
||||
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
|
||||
import org.springframework.boot.diagnostics.FailureAnalysis;
|
||||
import org.springframework.boot.diagnostics.FailureAnalyzer;
|
||||
|
||||
/**
|
||||
* {@link FailureAnalyzer} for {@link MissingR2dbcPoolDependencyException}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class MissingR2dbcPoolDependencyFailureAnalyzer extends AbstractFailureAnalyzer<MissingR2dbcPoolDependencyException> {
|
||||
|
||||
@Override
|
||||
protected FailureAnalysis analyze(Throwable rootFailure, MissingR2dbcPoolDependencyException cause) {
|
||||
return new FailureAnalysis(cause.getMessage(),
|
||||
"Update your application's build to depend on io.r2dbc:r2dbc-pool or your application's configuration "
|
||||
+ "to disable R2DBC connection pooling.",
|
||||
cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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.r2dbc;
|
||||
|
||||
/**
|
||||
* Exception thrown when R2DBC connection pooling has been configured both by the URL
|
||||
* ({@code spring.r2dbc.url}) and the pool properties ({@code spring.r2dbc.pool.*}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class MultipleConnectionPoolConfigurationsException extends RuntimeException {
|
||||
|
||||
MultipleConnectionPoolConfigurationsException() {
|
||||
super("R2DBC connection pooling configuration should be provided by either the spring.r2dbc.pool.* "
|
||||
+ "properties or the spring.r2dbc.url property but both have been used.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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.r2dbc;
|
||||
|
||||
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
|
||||
import org.springframework.boot.diagnostics.FailureAnalysis;
|
||||
import org.springframework.boot.diagnostics.FailureAnalyzer;
|
||||
|
||||
/**
|
||||
* {@link FailureAnalyzer} for {@link MultipleConnectionPoolConfigurationsException}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class MultipleConnectionPoolConfigurationsFailureAnalzyer
|
||||
extends AbstractFailureAnalyzer<MultipleConnectionPoolConfigurationsException> {
|
||||
|
||||
@Override
|
||||
protected FailureAnalysis analyze(Throwable rootFailure, MultipleConnectionPoolConfigurationsException cause) {
|
||||
return new FailureAnalysis(cause.getMessage(),
|
||||
"Update your configuration so that R2DBC connection pooling is configured using either the "
|
||||
+ "spring.r2dbc.url property or the spring.r2dbc.pool.* properties",
|
||||
cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -40,8 +40,8 @@ import org.springframework.context.annotation.Import;
|
||||
@ConditionalOnResource(resources = "classpath:META-INF/services/io.r2dbc.spi.ConnectionFactoryProvider")
|
||||
@AutoConfigureBefore({ DataSourceAutoConfiguration.class, SqlInitializationAutoConfiguration.class })
|
||||
@EnableConfigurationProperties(R2dbcProperties.class)
|
||||
@Import({ ConnectionFactoryConfigurations.Pool.class, ConnectionFactoryConfigurations.Generic.class,
|
||||
ConnectionFactoryDependentConfiguration.class })
|
||||
@Import({ ConnectionFactoryConfigurations.PoolConfiguration.class,
|
||||
ConnectionFactoryConfigurations.GenericConfiguration.class, ConnectionFactoryDependentConfiguration.class })
|
||||
public class R2dbcAutoConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@@ -178,6 +178,11 @@ public class R2dbcProperties {
|
||||
*/
|
||||
private ValidationDepth validationDepth = ValidationDepth.LOCAL;
|
||||
|
||||
/**
|
||||
* Whether pooling is enabled. Requires r2dbc-pool.
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
public Duration getMaxIdleTime() {
|
||||
return this.maxIdleTime;
|
||||
}
|
||||
@@ -242,6 +247,14 @@ public class R2dbcProperties {
|
||||
this.validationDepth = validationDepth;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1688,11 +1688,6 @@
|
||||
"name": "spring.quartz.scheduler-name",
|
||||
"defaultValue": "quartzScheduler"
|
||||
},
|
||||
{
|
||||
"name": "spring.r2dbc.pool.enabled",
|
||||
"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"
|
||||
|
||||
@@ -165,6 +165,8 @@ org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyze
|
||||
org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\
|
||||
org.springframework.boot.autoconfigure.jooq.NoDslContextBeanFailureAnalyzer,\
|
||||
org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryBeanCreationFailureAnalyzer,\
|
||||
org.springframework.boot.autoconfigure.r2dbc.MissingR2dbcPoolDependencyFailureAnalyzer,\
|
||||
org.springframework.boot.autoconfigure.r2dbc.MultipleConnectionPoolConfigurationsFailureAnalzyer,\
|
||||
org.springframework.boot.autoconfigure.r2dbc.NoConnectionFactoryBeanFailureAnalyzer,\
|
||||
org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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.r2dbc;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link MissingR2dbcPoolDependencyFailureAnalyzer}
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class MissingR2dbcPoolDependencyFailureAnalyzerTests {
|
||||
|
||||
private final MissingR2dbcPoolDependencyFailureAnalyzer failureAnalyzer = new MissingR2dbcPoolDependencyFailureAnalyzer();
|
||||
|
||||
@Test
|
||||
void analyzeWhenDifferentFailureShouldReturnNull() {
|
||||
assertThat(this.failureAnalyzer.analyze(new Exception())).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void analyzeWhenMissingR2dbcPoolDependencyShouldReturnAnalysis() {
|
||||
assertThat(this.failureAnalyzer.analyze(new MissingR2dbcPoolDependencyException())).isNotNull();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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.r2dbc;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link MultipleConnectionPoolConfigurationsFailureAnalzyer}
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class MultipleConnectionPoolConfigurationsFailureAnalzyerTests {
|
||||
|
||||
private final MultipleConnectionPoolConfigurationsFailureAnalzyer failureAnalyzer = new MultipleConnectionPoolConfigurationsFailureAnalzyer();
|
||||
|
||||
@Test
|
||||
void analyzeWhenDifferentFailureShouldReturnNull() {
|
||||
assertThat(this.failureAnalyzer.analyze(new Exception())).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void analyzeWhenMultipleConnectionPoolConfigurationsShouldReturnAnalysis() {
|
||||
assertThat(this.failureAnalyzer.analyze(new MultipleConnectionPoolConfigurationsException())).isNotNull();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,7 +20,6 @@ import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.time.Duration;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@@ -99,14 +98,31 @@ class R2dbcAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureWithUrlPoolAndPoolPropertiesApplyUrlPoolOptions() {
|
||||
void configureWithUrlPoolAndPoolPropertiesFails() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.r2dbc.url:r2dbc:pool:h2:mem:///" + randomDatabaseName() + "?maxSize=12",
|
||||
"spring.r2dbc.pool.max-size=15")
|
||||
.run((context) -> assertThat(context).getFailure().getRootCause()
|
||||
.isInstanceOf(MultipleConnectionPoolConfigurationsException.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureWithUrlPoolAndPropertyBasedPoolingDisabledFails() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.r2dbc.url:r2dbc:pool:h2:mem:///" + randomDatabaseName() + "?maxSize=12",
|
||||
"spring.r2dbc.pool.enabled=false")
|
||||
.run((context) -> assertThat(context).getFailure().getRootCause()
|
||||
.isInstanceOf(MultipleConnectionPoolConfigurationsException.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureWithUrlPoolAndNoPoolPropertiesCreatesPool() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.r2dbc.url:r2dbc:pool:h2:mem:///" + randomDatabaseName() + "?maxSize=12")
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(ConnectionFactory.class).hasSingleBean(ConnectionPool.class);
|
||||
PoolMetrics poolMetrics = context.getBean(ConnectionPool.class).getMetrics().get();
|
||||
assertThat(poolMetrics.getMaxAllocatedSize()).isEqualTo(12);
|
||||
ConnectionPool connectionPool = context.getBean(ConnectionPool.class);
|
||||
assertThat(connectionPool.getMetrics().get().getMaxAllocatedSize()).isEqualTo(12);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -132,27 +148,6 @@ class R2dbcAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureWithoutR2dbcPoolCreateGenericConnectionFactory() {
|
||||
this.contextRunner.with(hideConnectionPool()).withPropertyValues("spring.r2dbc.url:r2dbc:h2:mem:///"
|
||||
+ randomDatabaseName() + "?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE").run((context) -> {
|
||||
assertThat(context).hasSingleBean(ConnectionFactory.class);
|
||||
assertThat(context.getBean(ConnectionFactory.class))
|
||||
.asInstanceOf(type(OptionsCapableConnectionFactory.class))
|
||||
.extracting(Wrapped<ConnectionFactory>::unwrap)
|
||||
.isExactlyInstanceOf(H2ConnectionFactory.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureWithoutR2dbcPoolAndPoolEnabledDoesNotCreateConnectionFactory() {
|
||||
this.contextRunner.with(hideConnectionPool())
|
||||
.withPropertyValues("spring.r2dbc.pool.enabled=true",
|
||||
"spring.r2dbc.url:r2dbc:h2:mem:///" + randomDatabaseName()
|
||||
+ "?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE")
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(ConnectionFactory.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureWithoutPoolInvokeOptionCustomizer() {
|
||||
this.contextRunner
|
||||
@@ -297,10 +292,6 @@ class R2dbcAutoConfigurationTests {
|
||||
return "testdb-" + UUID.randomUUID();
|
||||
}
|
||||
|
||||
private Function<ApplicationContextRunner, ApplicationContextRunner> hideConnectionPool() {
|
||||
return (runner) -> runner.withClassLoader(new FilteredClassLoader("io.r2dbc.pool"));
|
||||
}
|
||||
|
||||
private static class DisableEmbeddedDatabaseClassLoader extends URLClassLoader {
|
||||
|
||||
DisableEmbeddedDatabaseClassLoader() {
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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.r2dbc;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import io.r2dbc.h2.H2ConnectionFactory;
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import io.r2dbc.spi.Wrapped;
|
||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||
import org.assertj.core.api.InstanceOfAssertFactory;
|
||||
import org.assertj.core.api.ObjectAssert;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.r2dbc.OptionsCapableConnectionFactory;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link R2dbcAutoConfiguration} without the {@code io.r2dbc:r2dbc-pool}
|
||||
* dependency.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@ClassPathExclusions("r2dbc-pool-*.jar")
|
||||
class R2dbcAutoConfigurationWithoutConnectionPoolTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void configureWithoutR2dbcPoolCreateGenericConnectionFactory() {
|
||||
this.contextRunner.withPropertyValues("spring.r2dbc.url:r2dbc:h2:mem:///" + randomDatabaseName()
|
||||
+ "?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE").run((context) -> {
|
||||
assertThat(context).hasSingleBean(ConnectionFactory.class);
|
||||
assertThat(context.getBean(ConnectionFactory.class))
|
||||
.asInstanceOf(type(OptionsCapableConnectionFactory.class))
|
||||
.extracting(Wrapped<ConnectionFactory>::unwrap)
|
||||
.isExactlyInstanceOf(H2ConnectionFactory.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureWithoutR2dbcPoolAndPoolEnabledShouldFail() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.r2dbc.pool.enabled=true",
|
||||
"spring.r2dbc.url:r2dbc:h2:mem:///" + randomDatabaseName()
|
||||
+ "?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE")
|
||||
.run((context) -> assertThat(context).getFailure().getRootCause()
|
||||
.isInstanceOf(MissingR2dbcPoolDependencyException.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void configureWithoutR2dbcPoolAndPoolUrlShouldFail() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.r2dbc.url:r2dbc:pool:h2:mem:///" + randomDatabaseName()
|
||||
+ "?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE")
|
||||
.run((context) -> assertThat(context).getFailure().getRootCause()
|
||||
.isInstanceOf(MissingR2dbcPoolDependencyException.class));
|
||||
}
|
||||
|
||||
private <T> InstanceOfAssertFactory<T, ObjectAssert<T>> type(Class<T> type) {
|
||||
return InstanceOfAssertFactories.type(type);
|
||||
}
|
||||
|
||||
private String randomDatabaseName() {
|
||||
return "testdb-" + UUID.randomUUID();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user