From 446c271e83530a5133bb158725afbc123641836c Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Tue, 6 May 2025 12:28:46 -0700 Subject: [PATCH] Introduce a shared abstraction for database initialization Currently used by Spring Batch, Spring Integration, Spring Session and Quartz. Signed-off-by: Yanming Zhou --- ...chDataSourceScriptDatabaseInitializer.java | 49 +------- .../autoconfigure/batch/BatchProperties.java | 45 +------- ...onDataSourceScriptDatabaseInitializer.java | 52 ++------- .../integration/IntegrationProperties.java | 46 +------- .../quartz/QuartzAutoConfiguration.java | 3 +- ...tzDataSourceScriptDatabaseInitializer.java | 67 ++--------- .../quartz/QuartzProperties.java | 52 ++------- ...onDataSourceScriptDatabaseInitializer.java | 52 ++------- .../session/JdbcSessionProperties.java | 50 ++------ .../quartz/QuartzAutoConfigurationTests.java | 3 +- ...aSourceScriptDatabaseInitializerTests.java | 7 +- .../DatabaseInitializationProperties.java | 85 ++++++++++++++ ...edDataSourceScriptDatabaseInitializer.java | 107 ++++++++++++++++++ 13 files changed, 259 insertions(+), 359 deletions(-) create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/DatabaseInitializationProperties.java create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/PropertiesBasedDataSourceScriptDatabaseInitializer.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchDataSourceScriptDatabaseInitializer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchDataSourceScriptDatabaseInitializer.java index c45b5e9a0f5a..4486fc2ae7fa 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchDataSourceScriptDatabaseInitializer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchDataSourceScriptDatabaseInitializer.java @@ -16,14 +16,10 @@ package org.springframework.boot.autoconfigure.batch; -import java.util.List; - import javax.sql.DataSource; import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; -import org.springframework.boot.jdbc.init.PlatformPlaceholderDatabaseDriverResolver; -import org.springframework.boot.sql.init.DatabaseInitializationSettings; -import org.springframework.util.StringUtils; +import org.springframework.boot.jdbc.init.PropertiesBasedDataSourceScriptDatabaseInitializer; /** * {@link DataSourceScriptDatabaseInitializer} for the Spring Batch database. May be @@ -33,54 +29,19 @@ * @author Vedran Pavic * @author Andy Wilkinson * @author Phillip Webb + * @author Yanming Zhou * @since 2.6.0 */ -public class BatchDataSourceScriptDatabaseInitializer extends DataSourceScriptDatabaseInitializer { +public class BatchDataSourceScriptDatabaseInitializer + extends PropertiesBasedDataSourceScriptDatabaseInitializer { /** * Create a new {@link BatchDataSourceScriptDatabaseInitializer} instance. * @param dataSource the Spring Batch data source * @param properties the Spring Batch JDBC properties - * @see #getSettings */ public BatchDataSourceScriptDatabaseInitializer(DataSource dataSource, BatchProperties.Jdbc properties) { - this(dataSource, getSettings(dataSource, properties)); - } - - /** - * Create a new {@link BatchDataSourceScriptDatabaseInitializer} instance. - * @param dataSource the Spring Batch data source - * @param settings the database initialization settings - * @see #getSettings - */ - public BatchDataSourceScriptDatabaseInitializer(DataSource dataSource, DatabaseInitializationSettings settings) { - super(dataSource, settings); - } - - /** - * Adapts {@link BatchProperties.Jdbc Spring Batch JDBC properties} to - * {@link DatabaseInitializationSettings} replacing any {@literal @@platform@@} - * placeholders. - * @param dataSource the Spring Batch data source - * @param properties batch JDBC properties - * @return a new {@link DatabaseInitializationSettings} instance - * @see #BatchDataSourceScriptDatabaseInitializer(DataSource, - * DatabaseInitializationSettings) - */ - public static DatabaseInitializationSettings getSettings(DataSource dataSource, BatchProperties.Jdbc properties) { - DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); - settings.setSchemaLocations(resolveSchemaLocations(dataSource, properties)); - settings.setMode(properties.getInitializeSchema()); - settings.setContinueOnError(true); - return settings; - } - - private static List resolveSchemaLocations(DataSource dataSource, BatchProperties.Jdbc properties) { - PlatformPlaceholderDatabaseDriverResolver platformResolver = new PlatformPlaceholderDatabaseDriverResolver(); - if (StringUtils.hasText(properties.getPlatform())) { - return platformResolver.resolveAll(properties.getPlatform(), properties.getSchema()); - } - return platformResolver.resolveAll(dataSource, properties.getSchema()); + super(dataSource, properties); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchProperties.java index e12e4717560d..06af4b5dbb41 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/BatchProperties.java @@ -17,7 +17,7 @@ package org.springframework.boot.autoconfigure.batch; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.sql.init.DatabaseInitializationMode; +import org.springframework.boot.jdbc.init.DatabaseInitializationProperties; import org.springframework.transaction.annotation.Isolation; /** @@ -63,7 +63,7 @@ public void setName(String name) { } - public static class Jdbc { + public static class Jdbc extends DatabaseInitializationProperties { private static final String DEFAULT_SCHEMA_LOCATION = "classpath:org/springframework/" + "batch/core/schema-@@platform@@.sql"; @@ -78,27 +78,11 @@ public static class Jdbc { */ private Isolation isolationLevelForCreate; - /** - * Path to the SQL file to use to initialize the database schema. - */ - private String schema = DEFAULT_SCHEMA_LOCATION; - - /** - * Platform to use in initialization scripts if the @@platform@@ placeholder is - * used. Auto-detected by default. - */ - private String platform; - /** * Table prefix for all the batch meta-data tables. */ private String tablePrefix; - /** - * Database schema initialization mode. - */ - private DatabaseInitializationMode initializeSchema = DatabaseInitializationMode.EMBEDDED; - public boolean isValidateTransactionState() { return this.validateTransactionState; } @@ -115,22 +99,6 @@ public void setIsolationLevelForCreate(Isolation isolationLevelForCreate) { this.isolationLevelForCreate = isolationLevelForCreate; } - public String getSchema() { - return this.schema; - } - - public void setSchema(String schema) { - this.schema = schema; - } - - public String getPlatform() { - return this.platform; - } - - public void setPlatform(String platform) { - this.platform = platform; - } - public String getTablePrefix() { return this.tablePrefix; } @@ -139,12 +107,9 @@ public void setTablePrefix(String tablePrefix) { this.tablePrefix = tablePrefix; } - public DatabaseInitializationMode getInitializeSchema() { - return this.initializeSchema; - } - - public void setInitializeSchema(DatabaseInitializationMode initializeSchema) { - this.initializeSchema = initializeSchema; + @Override + public String getDefaultSchemaLocation() { + return DEFAULT_SCHEMA_LOCATION; } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationDataSourceScriptDatabaseInitializer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationDataSourceScriptDatabaseInitializer.java index 41ec7c79a945..9ac32555dd6b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationDataSourceScriptDatabaseInitializer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationDataSourceScriptDatabaseInitializer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2025 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,15 +16,13 @@ package org.springframework.boot.autoconfigure.integration; -import java.util.List; +import java.util.Map; import javax.sql.DataSource; import org.springframework.boot.jdbc.DatabaseDriver; import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; -import org.springframework.boot.jdbc.init.PlatformPlaceholderDatabaseDriverResolver; -import org.springframework.boot.sql.init.DatabaseInitializationSettings; -import org.springframework.util.StringUtils; +import org.springframework.boot.jdbc.init.PropertiesBasedDataSourceScriptDatabaseInitializer; /** * {@link DataSourceScriptDatabaseInitializer} for the Spring Integration database. May be @@ -32,9 +30,11 @@ * * @author Vedran Pavic * @author Andy Wilkinson + * @author Yanming Zhou * @since 2.6.0 */ -public class IntegrationDataSourceScriptDatabaseInitializer extends DataSourceScriptDatabaseInitializer { +public class IntegrationDataSourceScriptDatabaseInitializer + extends PropertiesBasedDataSourceScriptDatabaseInitializer { /** * Create a new {@link IntegrationDataSourceScriptDatabaseInitializer} instance. @@ -44,45 +44,7 @@ public class IntegrationDataSourceScriptDatabaseInitializer extends DataSourceSc */ public IntegrationDataSourceScriptDatabaseInitializer(DataSource dataSource, IntegrationProperties.Jdbc properties) { - this(dataSource, getSettings(dataSource, properties)); - } - - /** - * Create a new {@link IntegrationDataSourceScriptDatabaseInitializer} instance. - * @param dataSource the Spring Integration data source - * @param settings the database initialization settings - * @see #getSettings - */ - public IntegrationDataSourceScriptDatabaseInitializer(DataSource dataSource, - DatabaseInitializationSettings settings) { - super(dataSource, settings); - } - - /** - * Adapts {@link IntegrationProperties.Jdbc Spring Integration JDBC properties} to - * {@link DatabaseInitializationSettings} replacing any {@literal @@platform@@} - * placeholders. - * @param dataSource the Spring Integration data source - * @param properties the Spring Integration JDBC properties - * @return a new {@link DatabaseInitializationSettings} instance - * @see #IntegrationDataSourceScriptDatabaseInitializer(DataSource, - * DatabaseInitializationSettings) - */ - static DatabaseInitializationSettings getSettings(DataSource dataSource, IntegrationProperties.Jdbc properties) { - DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); - settings.setSchemaLocations(resolveSchemaLocations(dataSource, properties)); - settings.setMode(properties.getInitializeSchema()); - settings.setContinueOnError(true); - return settings; - } - - private static List resolveSchemaLocations(DataSource dataSource, IntegrationProperties.Jdbc properties) { - PlatformPlaceholderDatabaseDriverResolver platformResolver = new PlatformPlaceholderDatabaseDriverResolver(); - platformResolver = platformResolver.withDriverPlatform(DatabaseDriver.MARIADB, "mysql"); - if (StringUtils.hasText(properties.getPlatform())) { - return platformResolver.resolveAll(properties.getPlatform(), properties.getSchema()); - } - return platformResolver.resolveAll(dataSource, properties.getSchema()); + super(dataSource, properties, Map.of(DatabaseDriver.MARIADB, "mysql")); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationProperties.java index a7c6fdd4babe..482d00806bc9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationProperties.java @@ -22,7 +22,7 @@ import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.sql.init.DatabaseInitializationMode; +import org.springframework.boot.jdbc.init.DatabaseInitializationProperties; /** * Configuration properties for Spring Integration. @@ -30,6 +30,7 @@ * @author Vedran Pavic * @author Stephane Nicoll * @author Artem Bilan + * @author Yanming Zhou * @since 2.0.0 */ @ConfigurationProperties("spring.integration") @@ -212,49 +213,14 @@ public void setIgnoreFailures(boolean ignoreFailures) { } - public static class Jdbc { + public static class Jdbc extends DatabaseInitializationProperties { private static final String DEFAULT_SCHEMA_LOCATION = "classpath:org/springframework/" + "integration/jdbc/schema-@@platform@@.sql"; - /** - * Path to the SQL file to use to initialize the database schema. - */ - private String schema = DEFAULT_SCHEMA_LOCATION; - - /** - * Platform to use in initialization scripts if the @@platform@@ placeholder is - * used. Auto-detected by default. - */ - private String platform; - - /** - * Database schema initialization mode. - */ - private DatabaseInitializationMode initializeSchema = DatabaseInitializationMode.EMBEDDED; - - public String getSchema() { - return this.schema; - } - - public void setSchema(String schema) { - this.schema = schema; - } - - public String getPlatform() { - return this.platform; - } - - public void setPlatform(String platform) { - this.platform = platform; - } - - public DatabaseInitializationMode getInitializeSchema() { - return this.initializeSchema; - } - - public void setInitializeSchema(DatabaseInitializationMode initializeSchema) { - this.initializeSchema = initializeSchema; + @Override + public String getDefaultSchemaLocation() { + return DEFAULT_SCHEMA_LOCATION; } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java index a9c5f4202bfb..6c2dc414df49 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java @@ -55,6 +55,7 @@ * * @author Vedran Pavic * @author Stephane Nicoll + * @author Yanming Zhou * @since 2.0.0 */ @AutoConfiguration(after = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, @@ -138,7 +139,7 @@ public QuartzDataSourceScriptDatabaseInitializer quartzDataSourceScriptDatabaseI DataSource dataSource, @QuartzDataSource ObjectProvider quartzDataSource, QuartzProperties properties) { DataSource dataSourceToUse = getDataSource(dataSource, quartzDataSource); - return new QuartzDataSourceScriptDatabaseInitializer(dataSourceToUse, properties); + return new QuartzDataSourceScriptDatabaseInitializer(dataSourceToUse, properties.getJdbc()); } static class OnQuartzDatasourceInitializationCondition extends OnDatabaseInitializationCondition { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzDataSourceScriptDatabaseInitializer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzDataSourceScriptDatabaseInitializer.java index 23f46d677c1f..e7ef11c5514a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzDataSourceScriptDatabaseInitializer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzDataSourceScriptDatabaseInitializer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2025 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. @@ -17,16 +17,15 @@ package org.springframework.boot.autoconfigure.quartz; import java.util.List; +import java.util.Map; import javax.sql.DataSource; import org.springframework.boot.jdbc.DatabaseDriver; import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; -import org.springframework.boot.jdbc.init.PlatformPlaceholderDatabaseDriverResolver; -import org.springframework.boot.sql.init.DatabaseInitializationSettings; +import org.springframework.boot.jdbc.init.PropertiesBasedDataSourceScriptDatabaseInitializer; import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; /** * {@link DataSourceScriptDatabaseInitializer} for the Quartz Scheduler database. May be @@ -35,36 +34,25 @@ * @author Vedran Pavic * @author Andy Wilkinson * @author Phillip Webb + * @author Yanming Zhou * @since 2.6.0 */ -public class QuartzDataSourceScriptDatabaseInitializer extends DataSourceScriptDatabaseInitializer { +public class QuartzDataSourceScriptDatabaseInitializer + extends PropertiesBasedDataSourceScriptDatabaseInitializer { private final List commentPrefixes; /** * Create a new {@link QuartzDataSourceScriptDatabaseInitializer} instance. * @param dataSource the Quartz Scheduler data source - * @param properties the Quartz properties + * @param properties the Quartz jdbc properties * @see #getSettings */ - public QuartzDataSourceScriptDatabaseInitializer(DataSource dataSource, QuartzProperties properties) { - this(dataSource, getSettings(dataSource, properties), properties.getJdbc().getCommentPrefix()); - } - - /** - * Create a new {@link QuartzDataSourceScriptDatabaseInitializer} instance. - * @param dataSource the Quartz Scheduler data source - * @param settings the database initialization settings - * @see #getSettings - */ - public QuartzDataSourceScriptDatabaseInitializer(DataSource dataSource, DatabaseInitializationSettings settings) { - this(dataSource, settings, null); - } - - private QuartzDataSourceScriptDatabaseInitializer(DataSource dataSource, DatabaseInitializationSettings settings, - List commentPrefixes) { - super(dataSource, settings); - this.commentPrefixes = commentPrefixes; + public QuartzDataSourceScriptDatabaseInitializer(DataSource dataSource, QuartzProperties.Jdbc properties) { + super(dataSource, properties, + Map.of(DatabaseDriver.DB2, "db2_v95", DatabaseDriver.MYSQL, "mysql_innodb", DatabaseDriver.MARIADB, + "mysql_innodb", DatabaseDriver.POSTGRESQL, "postgres", DatabaseDriver.SQLSERVER, "sqlServer")); + this.commentPrefixes = properties.getCommentPrefix(); } @Override @@ -74,35 +62,4 @@ protected void customize(ResourceDatabasePopulator populator) { } } - /** - * Adapts {@link QuartzProperties Quartz properties} to - * {@link DatabaseInitializationSettings} replacing any {@literal @@platform@@} - * placeholders. - * @param dataSource the Quartz Scheduler data source - * @param properties the Quartz properties - * @return a new {@link DatabaseInitializationSettings} instance - * @see #QuartzDataSourceScriptDatabaseInitializer(DataSource, - * DatabaseInitializationSettings) - */ - public static DatabaseInitializationSettings getSettings(DataSource dataSource, QuartzProperties properties) { - DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); - settings.setSchemaLocations(resolveSchemaLocations(dataSource, properties.getJdbc())); - settings.setMode(properties.getJdbc().getInitializeSchema()); - settings.setContinueOnError(true); - return settings; - } - - private static List resolveSchemaLocations(DataSource dataSource, QuartzProperties.Jdbc properties) { - PlatformPlaceholderDatabaseDriverResolver platformResolver = new PlatformPlaceholderDatabaseDriverResolver(); - platformResolver = platformResolver.withDriverPlatform(DatabaseDriver.DB2, "db2_v95"); - platformResolver = platformResolver.withDriverPlatform(DatabaseDriver.MYSQL, "mysql_innodb"); - platformResolver = platformResolver.withDriverPlatform(DatabaseDriver.MARIADB, "mysql_innodb"); - platformResolver = platformResolver.withDriverPlatform(DatabaseDriver.POSTGRESQL, "postgres"); - platformResolver = platformResolver.withDriverPlatform(DatabaseDriver.SQLSERVER, "sqlServer"); - if (StringUtils.hasText(properties.getPlatform())) { - return platformResolver.resolveAll(properties.getPlatform(), properties.getSchema()); - } - return platformResolver.resolveAll(dataSource, properties.getSchema()); - } - } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java index cc2ebaf5e56b..d19e7d817ef6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2025 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. @@ -24,13 +24,14 @@ import java.util.Map; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.sql.init.DatabaseInitializationMode; +import org.springframework.boot.jdbc.init.DatabaseInitializationProperties; /** * Configuration properties for the Quartz Scheduler integration. * * @author Vedran Pavic * @author Stephane Nicoll + * @author Yanming Zhou * @since 2.0.0 */ @ConfigurationProperties("spring.quartz") @@ -131,56 +132,16 @@ public Jdbc getJdbc() { return this.jdbc; } - public static class Jdbc { + public static class Jdbc extends DatabaseInitializationProperties { private static final String DEFAULT_SCHEMA_LOCATION = "classpath:org/quartz/impl/" + "jdbcjobstore/tables_@@platform@@.sql"; - /** - * Path to the SQL file to use to initialize the database schema. - */ - private String schema = DEFAULT_SCHEMA_LOCATION; - - /** - * Platform to use in initialization scripts if the @@platform@@ placeholder is - * used. Auto-detected by default. - */ - private String platform; - - /** - * Database schema initialization mode. - */ - private DatabaseInitializationMode initializeSchema = DatabaseInitializationMode.EMBEDDED; - /** * Prefixes for single-line comments in SQL initialization scripts. */ private List commentPrefix = new ArrayList<>(Arrays.asList("#", "--")); - public String getSchema() { - return this.schema; - } - - public void setSchema(String schema) { - this.schema = schema; - } - - public String getPlatform() { - return this.platform; - } - - public void setPlatform(String platform) { - this.platform = platform; - } - - public DatabaseInitializationMode getInitializeSchema() { - return this.initializeSchema; - } - - public void setInitializeSchema(DatabaseInitializationMode initializeSchema) { - this.initializeSchema = initializeSchema; - } - public List getCommentPrefix() { return this.commentPrefix; } @@ -189,6 +150,11 @@ public void setCommentPrefix(List commentPrefix) { this.commentPrefix = commentPrefix; } + @Override + public String getDefaultSchemaLocation() { + return DEFAULT_SCHEMA_LOCATION; + } + } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionDataSourceScriptDatabaseInitializer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionDataSourceScriptDatabaseInitializer.java index a5279ecb45bd..b1918496dba9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionDataSourceScriptDatabaseInitializer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionDataSourceScriptDatabaseInitializer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2025 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,15 +16,13 @@ package org.springframework.boot.autoconfigure.session; -import java.util.List; +import java.util.Map; import javax.sql.DataSource; import org.springframework.boot.jdbc.DatabaseDriver; import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; -import org.springframework.boot.jdbc.init.PlatformPlaceholderDatabaseDriverResolver; -import org.springframework.boot.sql.init.DatabaseInitializationSettings; -import org.springframework.util.StringUtils; +import org.springframework.boot.jdbc.init.PropertiesBasedDataSourceScriptDatabaseInitializer; /** * {@link DataSourceScriptDatabaseInitializer} for the Spring Session JDBC database. May @@ -34,9 +32,11 @@ * @author Vedran Pavic * @author Andy Wilkinson * @author Phillip Webb + * @author Yanming Zhou * @since 2.6.0 */ -public class JdbcSessionDataSourceScriptDatabaseInitializer extends DataSourceScriptDatabaseInitializer { +public class JdbcSessionDataSourceScriptDatabaseInitializer + extends PropertiesBasedDataSourceScriptDatabaseInitializer { /** * Create a new {@link JdbcSessionDataSourceScriptDatabaseInitializer} instance. @@ -45,45 +45,7 @@ public class JdbcSessionDataSourceScriptDatabaseInitializer extends DataSourceSc * @see #getSettings */ public JdbcSessionDataSourceScriptDatabaseInitializer(DataSource dataSource, JdbcSessionProperties properties) { - this(dataSource, getSettings(dataSource, properties)); - } - - /** - * Create a new {@link JdbcSessionDataSourceScriptDatabaseInitializer} instance. - * @param dataSource the Spring Session JDBC data source - * @param settings the database initialization settings - * @see #getSettings - */ - public JdbcSessionDataSourceScriptDatabaseInitializer(DataSource dataSource, - DatabaseInitializationSettings settings) { - super(dataSource, settings); - } - - /** - * Adapts {@link JdbcSessionProperties Spring Session JDBC properties} to - * {@link DatabaseInitializationSettings} replacing any {@literal @@platform@@} - * placeholders. - * @param dataSource the Spring Session JDBC data source - * @param properties the Spring Session JDBC properties - * @return a new {@link DatabaseInitializationSettings} instance - * @see #JdbcSessionDataSourceScriptDatabaseInitializer(DataSource, - * DatabaseInitializationSettings) - */ - static DatabaseInitializationSettings getSettings(DataSource dataSource, JdbcSessionProperties properties) { - DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); - settings.setSchemaLocations(resolveSchemaLocations(dataSource, properties)); - settings.setMode(properties.getInitializeSchema()); - settings.setContinueOnError(true); - return settings; - } - - private static List resolveSchemaLocations(DataSource dataSource, JdbcSessionProperties properties) { - PlatformPlaceholderDatabaseDriverResolver platformResolver = new PlatformPlaceholderDatabaseDriverResolver(); - platformResolver = platformResolver.withDriverPlatform(DatabaseDriver.MARIADB, "mysql"); - if (StringUtils.hasText(properties.getPlatform())) { - return platformResolver.resolveAll(properties.getPlatform(), properties.getSchema()); - } - return platformResolver.resolveAll(dataSource, properties.getSchema()); + super(dataSource, properties, Map.of(DatabaseDriver.MARIADB, "mysql")); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionProperties.java index 07c15888f5dc..58dd949bb36d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionProperties.java @@ -17,7 +17,7 @@ package org.springframework.boot.autoconfigure.session; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.sql.init.DatabaseInitializationMode; +import org.springframework.boot.jdbc.init.DatabaseInitializationProperties; import org.springframework.session.FlushMode; import org.springframework.session.SaveMode; @@ -25,10 +25,11 @@ * Configuration properties for JDBC backed Spring Session. * * @author Vedran Pavic + * @author Yanming Zhou * @since 2.0.0 */ @ConfigurationProperties("spring.session.jdbc") -public class JdbcSessionProperties { +public class JdbcSessionProperties extends DatabaseInitializationProperties { private static final String DEFAULT_SCHEMA_LOCATION = "classpath:org/springframework/" + "session/jdbc/schema-@@platform@@.sql"; @@ -37,17 +38,6 @@ public class JdbcSessionProperties { private static final String DEFAULT_CLEANUP_CRON = "0 * * * * *"; - /** - * Path to the SQL file to use to initialize the database schema. - */ - private String schema = DEFAULT_SCHEMA_LOCATION; - - /** - * Platform to use in initialization scripts if the @@platform@@ placeholder is used. - * Auto-detected by default. - */ - private String platform; - /** * Name of the database table used to store sessions. */ @@ -58,11 +48,6 @@ public class JdbcSessionProperties { */ private String cleanupCron = DEFAULT_CLEANUP_CRON; - /** - * Database schema initialization mode. - */ - private DatabaseInitializationMode initializeSchema = DatabaseInitializationMode.EMBEDDED; - /** * Sessions flush mode. Determines when session changes are written to the session * store. @@ -75,22 +60,6 @@ public class JdbcSessionProperties { */ private SaveMode saveMode = SaveMode.ON_SET_ATTRIBUTE; - public String getSchema() { - return this.schema; - } - - public void setSchema(String schema) { - this.schema = schema; - } - - public String getPlatform() { - return this.platform; - } - - public void setPlatform(String platform) { - this.platform = platform; - } - public String getTableName() { return this.tableName; } @@ -107,14 +76,6 @@ public void setCleanupCron(String cleanupCron) { this.cleanupCron = cleanupCron; } - public DatabaseInitializationMode getInitializeSchema() { - return this.initializeSchema; - } - - public void setInitializeSchema(DatabaseInitializationMode initializeSchema) { - this.initializeSchema = initializeSchema; - } - public FlushMode getFlushMode() { return this.flushMode; } @@ -131,4 +92,9 @@ public void setSaveMode(SaveMode saveMode) { this.saveMode = saveMode; } + @Override + public String getDefaultSchemaLocation() { + return DEFAULT_SCHEMA_LOCATION; + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java index 1b97cc0c4c1d..f5617d8a2363 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java @@ -81,6 +81,7 @@ * @author Vedran Pavic * @author Stephane Nicoll * @author Andy Wilkinson + * @author Yanming Zhou */ @ExtendWith(OutputCaptureExtension.class) class QuartzAutoConfigurationTests { @@ -556,7 +557,7 @@ static class CustomQuartzDatabaseInitializerConfiguration { @Bean QuartzDataSourceScriptDatabaseInitializer customInitializer(DataSource dataSource, QuartzProperties properties) { - return new QuartzDataSourceScriptDatabaseInitializer(dataSource, properties); + return new QuartzDataSourceScriptDatabaseInitializer(dataSource, properties.getJdbc()); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzDataSourceScriptDatabaseInitializerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzDataSourceScriptDatabaseInitializerTests.java index 6ed299543d03..1de124abc74b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzDataSourceScriptDatabaseInitializerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzDataSourceScriptDatabaseInitializerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2025 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. @@ -33,6 +33,7 @@ * Tests for {@link QuartzDataSourceScriptDatabaseInitializer}. * * @author Stephane Nicoll + * @author Yanming Zhou */ class QuartzDataSourceScriptDatabaseInitializerTests { @@ -42,7 +43,7 @@ void getSettingsWithPlatformDoesNotTouchDataSource() { QuartzProperties properties = new QuartzProperties(); properties.getJdbc().setPlatform("test"); DatabaseInitializationSettings settings = QuartzDataSourceScriptDatabaseInitializer.getSettings(dataSource, - properties); + properties.getJdbc()); assertThat(settings.getSchemaLocations()) .containsOnly("classpath:org/quartz/impl/jdbcjobstore/tables_test.sql"); then(dataSource).shouldHaveNoInteractions(); @@ -54,7 +55,7 @@ void customizeSetCommentPrefixes() { properties.getJdbc().setPlatform("test"); properties.getJdbc().setCommentPrefix(Arrays.asList("##", "--")); QuartzDataSourceScriptDatabaseInitializer initializer = new QuartzDataSourceScriptDatabaseInitializer( - mock(DataSource.class), properties); + mock(DataSource.class), properties.getJdbc()); ResourceDatabasePopulator populator = mock(ResourceDatabasePopulator.class); initializer.customize(populator); then(populator).should().setCommentPrefixes("##", "--"); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/DatabaseInitializationProperties.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/DatabaseInitializationProperties.java new file mode 100644 index 000000000000..126d13fdbf54 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/DatabaseInitializationProperties.java @@ -0,0 +1,85 @@ +/* + * Copyright 2012-2025 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.jdbc.init; + +import org.springframework.boot.sql.init.DatabaseInitializationMode; + +/** + * Base configuration properties class for performing SQL database initialization. + * + * @author Yanming Zhou + * @since 4.0.0 + */ +public abstract class DatabaseInitializationProperties { + + /** + * Path to the SQL file to use to initialize the database schema. + */ + private String schema = getDefaultSchemaLocation(); + + /** + * Platform to use in initialization scripts if the @@platform@@ placeholder is used. + * Auto-detected by default. + */ + private String platform; + + /** + * Database schema initialization mode. + */ + private DatabaseInitializationMode initializeSchema = DatabaseInitializationMode.EMBEDDED; + + /** + * Whether initialization should continue when an error occurs when applying a schema + * script. + */ + private boolean continueOnError = true; + + public String getSchema() { + return this.schema; + } + + public void setSchema(String schema) { + this.schema = schema; + } + + public String getPlatform() { + return this.platform; + } + + public void setPlatform(String platform) { + this.platform = platform; + } + + public DatabaseInitializationMode getInitializeSchema() { + return this.initializeSchema; + } + + public void setInitializeSchema(DatabaseInitializationMode initializeSchema) { + this.initializeSchema = initializeSchema; + } + + public boolean isContinueOnError() { + return this.continueOnError; + } + + public void setContinueOnError(boolean continueOnError) { + this.continueOnError = continueOnError; + } + + public abstract String getDefaultSchemaLocation(); + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/PropertiesBasedDataSourceScriptDatabaseInitializer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/PropertiesBasedDataSourceScriptDatabaseInitializer.java new file mode 100644 index 000000000000..957787de8c78 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/init/PropertiesBasedDataSourceScriptDatabaseInitializer.java @@ -0,0 +1,107 @@ +/* + * Copyright 2012-2025 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.jdbc.init; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.boot.jdbc.DatabaseDriver; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; +import org.springframework.util.StringUtils; + +/** + * Convenience class for construct {@link DataSourceScriptDatabaseInitializer} base on + * {@link DatabaseInitializationProperties}. + * + * @param the {@link DatabaseInitializationProperties} type being used + * @author Yanming Zhou + * @since 4.0.0 + */ +public class PropertiesBasedDataSourceScriptDatabaseInitializer + extends DataSourceScriptDatabaseInitializer { + + /** + * Create a new {@link PropertiesBasedDataSourceScriptDatabaseInitializer} instance. + * @param dataSource the data source + * @param properties the configuration properties + * @see #getSettings + */ + public PropertiesBasedDataSourceScriptDatabaseInitializer(DataSource dataSource, T properties) { + this(dataSource, properties, Collections.emptyMap()); + } + + /** + * Create a new {@link PropertiesBasedDataSourceScriptDatabaseInitializer} instance. + * @param dataSource the data source + * @param properties the configuration properties + * @param driverMappings the driver mappings + * @see #getSettings + */ + public PropertiesBasedDataSourceScriptDatabaseInitializer(DataSource dataSource, T properties, + Map driverMappings) { + super(dataSource, getSettings(dataSource, properties, driverMappings)); + } + + /** + * Adapts {@link DatabaseInitializationProperties configuration properties} to + * {@link DatabaseInitializationSettings} replacing any {@literal @@platform@@} + * placeholders. + * @param dataSource the data source + * @param properties the configuration properties + * @param the {@link DatabaseInitializationProperties} type being used + * @return a new {@link DatabaseInitializationSettings} instance + */ + public static DatabaseInitializationSettings getSettings( + DataSource dataSource, T properties) { + return getSettings(dataSource, properties, Collections.emptyMap()); + } + + /** + * Adapts {@link DatabaseInitializationProperties configuration properties} to + * {@link DatabaseInitializationSettings} replacing any {@literal @@platform@@} + * placeholders. + * @param dataSource the data source + * @param properties the configuration properties + * @param driverMappings the driver mappings + * @param the {@link DatabaseInitializationProperties} type being used + * @return a new {@link DatabaseInitializationSettings} instance + */ + public static DatabaseInitializationSettings getSettings( + DataSource dataSource, T properties, Map driverMappings) { + DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); + settings.setSchemaLocations(resolveSchemaLocations(dataSource, properties, driverMappings)); + settings.setMode(properties.getInitializeSchema()); + settings.setContinueOnError(properties.isContinueOnError()); + return settings; + } + + private static List resolveSchemaLocations( + DataSource dataSource, T properties, Map driverMappings) { + PlatformPlaceholderDatabaseDriverResolver platformResolver = new PlatformPlaceholderDatabaseDriverResolver(); + for (Map.Entry entry : driverMappings.entrySet()) { + platformResolver = platformResolver.withDriverPlatform(entry.getKey(), entry.getValue()); + } + if (StringUtils.hasText(properties.getPlatform())) { + return platformResolver.resolveAll(properties.getPlatform(), properties.getSchema()); + } + return platformResolver.resolveAll(dataSource, properties.getSchema()); + } + +}