Allow customizations of embedded database connections
This commit allows EmbeddedDatabaseConfigurer instances to be further customized if necessary. EmbeddedDatabaseBuilder has a way now to set a DatabaseConfigurer rather than just a type to provide full control, or customize an existing supported database type using the new EmbeddedDatabaseConfigurers#customizeConfigurer callback. Closes gh-21160
This commit is contained in:
parent
bcccba50c1
commit
18ea43c905
|
|
@ -168,6 +168,74 @@ attribute of the `embedded-database` tag to `DERBY`. If you use the builder API,
|
|||
call the `setType(EmbeddedDatabaseType)` method with `EmbeddedDatabaseType.DERBY`.
|
||||
|
||||
|
||||
[[jdbc-embedded-database-types-custom]]
|
||||
== Customizing the Embedded Database Type
|
||||
|
||||
While each supported type comes with default connection settings, it is possible
|
||||
to customize them if necessary. The following example uses H2 with a custom driver:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
----
|
||||
@Configuration
|
||||
public class DataSourceConfig {
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
return new EmbeddedDatabaseBuilder()
|
||||
.setDatabaseConfigurer(EmbeddedDatabaseConfigurers
|
||||
.customizeConfigurer(H2, this::customize))
|
||||
.addScript("schema.sql")
|
||||
.build();
|
||||
}
|
||||
|
||||
private EmbeddedDatabaseConfigurer customize(EmbeddedDatabaseConfigurer defaultConfigurer) {
|
||||
return new EmbeddedDatabaseConfigurerDelegate(defaultConfigurer) {
|
||||
@Override
|
||||
public void configureConnectionProperties(ConnectionProperties properties, String databaseName) {
|
||||
super.configureConnectionProperties(properties, databaseName);
|
||||
properties.setDriverClass(CustomDriver.class);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
----
|
||||
@Configuration
|
||||
class DataSourceConfig {
|
||||
|
||||
@Bean
|
||||
fun dataSource(): DataSource {
|
||||
return EmbeddedDatabaseBuilder()
|
||||
.setDatabaseConfigurer(EmbeddedDatabaseConfigurers
|
||||
.customizeConfigurer(EmbeddedDatabaseType.H2) { this.customize(it) })
|
||||
.addScript("schema.sql")
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun customize(defaultConfigurer: EmbeddedDatabaseConfigurer): EmbeddedDatabaseConfigurer {
|
||||
return object : EmbeddedDatabaseConfigurerDelegate(defaultConfigurer) {
|
||||
override fun configureConnectionProperties(
|
||||
properties: ConnectionProperties,
|
||||
databaseName: String
|
||||
) {
|
||||
super.configureConnectionProperties(properties, databaseName)
|
||||
properties.setDriverClass(CustomDriver::class.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
|
||||
[[jdbc-embedded-database-dao-testing]]
|
||||
== Testing Data Access Logic with an Embedded Database
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
|
@ -112,7 +112,8 @@ public class EmbeddedDatabaseBuilder {
|
|||
}
|
||||
|
||||
/**
|
||||
* Set the type of embedded database.
|
||||
* Set the type of embedded database. Consider using {@link #setDatabaseConfigurer}
|
||||
* if customization of the connections properties is necessary.
|
||||
* <p>Defaults to HSQL if not called.
|
||||
* @param databaseType the type of embedded database to build
|
||||
* @return {@code this}, to facilitate method chaining
|
||||
|
|
@ -122,6 +123,19 @@ public class EmbeddedDatabaseBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@linkplain EmbeddedDatabaseConfigurer configurer} to use to
|
||||
* configure the embedded database, as an alternative to {@link #setType}.
|
||||
* @param configurer the configurer of the embedded database
|
||||
* @return {@code this}, to facilitate method chaining
|
||||
* @since 6.2
|
||||
* @see EmbeddedDatabaseConfigurers
|
||||
*/
|
||||
public EmbeddedDatabaseBuilder setDatabaseConfigurer(EmbeddedDatabaseConfigurer configurer) {
|
||||
this.databaseFactory.setDatabaseConfigurer(configurer);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the factory to use to create the {@link DataSource} instance that
|
||||
* connects to the embedded database.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2002-2024 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.jdbc.datasource.embedded;
|
||||
|
||||
/**
|
||||
* A {@link EmbeddedDatabaseConfigurer} delegate that can be used to customize
|
||||
* the embedded database.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 6.2
|
||||
*/
|
||||
public class EmbeddedDatabaseConfigurerDelegate extends AbstractEmbeddedDatabaseConfigurer {
|
||||
|
||||
private final EmbeddedDatabaseConfigurer target;
|
||||
|
||||
public EmbeddedDatabaseConfigurerDelegate(EmbeddedDatabaseConfigurer target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureConnectionProperties(ConnectionProperties properties, String databaseName) {
|
||||
this.target.configureConnectionProperties(properties, databaseName);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package org.springframework.jdbc.datasource.embedded;
|
||||
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
|
|
@ -25,28 +27,24 @@ import org.springframework.util.Assert;
|
|||
* @author Keith Donald
|
||||
* @author Oliver Gierke
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
* @author Stephane Nicoll
|
||||
* @since 6.2
|
||||
*/
|
||||
final class EmbeddedDatabaseConfigurerFactory {
|
||||
|
||||
private EmbeddedDatabaseConfigurerFactory() {
|
||||
}
|
||||
|
||||
public abstract class EmbeddedDatabaseConfigurers {
|
||||
|
||||
/**
|
||||
* Return a configurer instance for the given embedded database type.
|
||||
* @param type the embedded database type (HSQL, H2 or Derby)
|
||||
* @param type the {@linkplain EmbeddedDatabaseType embedded database type}
|
||||
* @return the configurer instance
|
||||
* @throws IllegalStateException if the driver for the specified database type is not available
|
||||
*/
|
||||
public static EmbeddedDatabaseConfigurer getConfigurer(EmbeddedDatabaseType type) throws IllegalStateException {
|
||||
public static EmbeddedDatabaseConfigurer getConfigurer(EmbeddedDatabaseType type) {
|
||||
Assert.notNull(type, "EmbeddedDatabaseType is required");
|
||||
try {
|
||||
return switch (type) {
|
||||
case HSQL -> HsqlEmbeddedDatabaseConfigurer.getInstance();
|
||||
case H2 -> H2EmbeddedDatabaseConfigurer.getInstance();
|
||||
case DERBY -> DerbyEmbeddedDatabaseConfigurer.getInstance();
|
||||
default -> throw new UnsupportedOperationException("Embedded database type [" + type + "] is not supported");
|
||||
};
|
||||
}
|
||||
catch (ClassNotFoundException | NoClassDefFoundError ex) {
|
||||
|
|
@ -54,4 +52,20 @@ final class EmbeddedDatabaseConfigurerFactory {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Customize the default configurer for the given embedded database type. The
|
||||
* {@code customizer} operator typically uses
|
||||
* {@link EmbeddedDatabaseConfigurerDelegate} to customize things as necessary.
|
||||
* @param type the {@linkplain EmbeddedDatabaseType embedded database type}
|
||||
* @param customizer the customizer to return based on the default
|
||||
* @return the customized configurer instance
|
||||
* @throws IllegalStateException if the driver for the specified database type is not available
|
||||
*/
|
||||
public static EmbeddedDatabaseConfigurer customizeConfigurer(
|
||||
EmbeddedDatabaseType type, UnaryOperator<EmbeddedDatabaseConfigurer> customizer) {
|
||||
|
||||
EmbeddedDatabaseConfigurer defaultConfigurer = getConfigurer(type);
|
||||
return customizer.apply(defaultConfigurer);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
|
@ -45,9 +45,11 @@ import org.springframework.util.Assert;
|
|||
* for the database.
|
||||
* <li>Call {@link #setDatabaseName} to set an explicit name for the database.
|
||||
* <li>Call {@link #setDatabaseType} to set the database type if you wish to
|
||||
* use one of the supported types.
|
||||
* use one of the supported types with their default settings.
|
||||
* <li>Call {@link #setDatabaseConfigurer} to configure support for a custom
|
||||
* embedded database type.
|
||||
* embedded database type, or
|
||||
* {@linkplain EmbeddedDatabaseConfigurers#customizeConfigurer customize} the
|
||||
* default of a supported types.
|
||||
* <li>Call {@link #setDatabasePopulator} to change the algorithm used to
|
||||
* populate the database.
|
||||
* <li>Call {@link #setDataSourceFactory} to change the type of
|
||||
|
|
@ -60,6 +62,7 @@ import org.springframework.util.Assert;
|
|||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @author Stephane Nicoll
|
||||
* @since 3.0
|
||||
*/
|
||||
public class EmbeddedDatabaseFactory {
|
||||
|
|
@ -124,17 +127,23 @@ public class EmbeddedDatabaseFactory {
|
|||
|
||||
/**
|
||||
* Set the type of embedded database to use.
|
||||
* <p>Call this when you wish to configure one of the pre-supported types.
|
||||
* <p>Call this when you wish to configure one of the pre-supported types
|
||||
* with their default settings.
|
||||
* <p>Defaults to HSQL.
|
||||
* @param type the database type
|
||||
*/
|
||||
public void setDatabaseType(EmbeddedDatabaseType type) {
|
||||
this.databaseConfigurer = EmbeddedDatabaseConfigurerFactory.getConfigurer(type);
|
||||
this.databaseConfigurer = EmbeddedDatabaseConfigurers.getConfigurer(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the strategy that will be used to configure the embedded database instance.
|
||||
* <p>Call this when you wish to use an embedded database type not already supported.
|
||||
* <p>Call this with
|
||||
* {@linkplain EmbeddedDatabaseConfigurers#customizeConfigurer customizeConfigurer}
|
||||
* when you wish to customize the settings of one of the pre-supported types.
|
||||
* Alternatively, use this when you wish to use an embedded database type not
|
||||
* already supported.
|
||||
* @since 6.2
|
||||
*/
|
||||
public void setDatabaseConfigurer(EmbeddedDatabaseConfigurer configurer) {
|
||||
this.databaseConfigurer = configurer;
|
||||
|
|
@ -178,7 +187,7 @@ public class EmbeddedDatabaseFactory {
|
|||
|
||||
// Create the embedded database first
|
||||
if (this.databaseConfigurer == null) {
|
||||
this.databaseConfigurer = EmbeddedDatabaseConfigurerFactory.getConfigurer(EmbeddedDatabaseType.HSQL);
|
||||
this.databaseConfigurer = EmbeddedDatabaseConfigurers.getConfigurer(EmbeddedDatabaseType.HSQL);
|
||||
}
|
||||
this.databaseConfigurer.configureConnectionProperties(
|
||||
this.dataSourceFactory.getConnectionProperties(), this.databaseName);
|
||||
|
|
|
|||
|
|
@ -121,6 +121,23 @@ class EmbeddedDatabaseBuilderTests {
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void setTypeConfigurerToCustomH2() {
|
||||
doTwice(() -> {
|
||||
EmbeddedDatabase db = builder
|
||||
.setDatabaseConfigurer(EmbeddedDatabaseConfigurers.customizeConfigurer(H2, defaultConfigurer ->
|
||||
new EmbeddedDatabaseConfigurerDelegate(defaultConfigurer) {
|
||||
@Override
|
||||
public void configureConnectionProperties(ConnectionProperties properties, String databaseName) {
|
||||
super.configureConnectionProperties(properties, databaseName);
|
||||
}
|
||||
}))
|
||||
.addScripts("db-schema.sql", "db-test-data.sql")//
|
||||
.build();
|
||||
assertDatabaseCreatedAndShutdown(db);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void setTypeToDerbyAndIgnoreFailedDrops() {
|
||||
doTwice(() -> {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.jdbc.datasource.embedded;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
|
@ -25,11 +26,14 @@ import org.springframework.jdbc.datasource.init.DatabasePopulator;
|
|||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link EmbeddedDatabaseFactory}.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class EmbeddedDatabaseFactoryTests {
|
||||
|
||||
private EmbeddedDatabaseFactory factory = new EmbeddedDatabaseFactory();
|
||||
private final EmbeddedDatabaseFactory factory = new EmbeddedDatabaseFactory();
|
||||
|
||||
|
||||
@Test
|
||||
|
|
@ -41,6 +45,45 @@ class EmbeddedDatabaseFactoryTests {
|
|||
db.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
void customizeConfigurerWithAnotherDatabaseName() throws SQLException {
|
||||
this.factory.setDatabaseName("original-db-mame");
|
||||
this.factory.setDatabaseConfigurer(EmbeddedDatabaseConfigurers.customizeConfigurer(
|
||||
EmbeddedDatabaseType.H2, defaultConfigurer ->
|
||||
new EmbeddedDatabaseConfigurerDelegate(defaultConfigurer) {
|
||||
@Override
|
||||
public void configureConnectionProperties(ConnectionProperties properties, String databaseName) {
|
||||
super.configureConnectionProperties(properties, "custom-db-name");
|
||||
}
|
||||
}));
|
||||
EmbeddedDatabase db = this.factory.getDatabase();
|
||||
try (Connection connection = db.getConnection()) {
|
||||
assertThat(connection.getMetaData().getURL()).contains("custom-db-name")
|
||||
.doesNotContain("original-db-mame");
|
||||
}
|
||||
db.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
void customizeConfigurerWithCustomizedUrl() throws SQLException {
|
||||
this.factory.setDatabaseName("original-db-mame");
|
||||
this.factory.setDatabaseConfigurer(EmbeddedDatabaseConfigurers.customizeConfigurer(
|
||||
EmbeddedDatabaseType.H2, defaultConfigurer ->
|
||||
new EmbeddedDatabaseConfigurerDelegate(defaultConfigurer) {
|
||||
@Override
|
||||
public void configureConnectionProperties(ConnectionProperties properties, String databaseName) {
|
||||
super.configureConnectionProperties(properties, databaseName);
|
||||
properties.setUrl("jdbc:h2:mem:custom-db-name;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false;MODE=MariaDB");
|
||||
}
|
||||
}));
|
||||
EmbeddedDatabase db = this.factory.getDatabase();
|
||||
try (Connection connection = db.getConnection()) {
|
||||
assertThat(connection.getMetaData().getURL()).contains("custom-db-name")
|
||||
.doesNotContain("original-db-mame");
|
||||
}
|
||||
db.shutdown();
|
||||
}
|
||||
|
||||
|
||||
private static class StubDatabasePopulator implements DatabasePopulator {
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue