From 3de58c2340032e4b7e2a9f7e7fb27d1b7afe004e Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 9 Jul 2021 14:17:23 +0100 Subject: [PATCH] Detect JdbcIndexedSessionRepository as depending on DB init Fixes gh-27220 --- ...pendsOnDatabaseInitializationDetector.java | 41 ++++++++++++++++ .../session/JdbcSessionConfiguration.java | 3 ++ .../main/resources/META-INF/spring.factories | 3 +- .../SessionAutoConfigurationJdbcTests.java | 48 +++++++++++++++++++ 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcIndexedSessionRepositoryDependsOnDatabaseInitializationDetector.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcIndexedSessionRepositoryDependsOnDatabaseInitializationDetector.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcIndexedSessionRepositoryDependsOnDatabaseInitializationDetector.java new file mode 100644 index 0000000000..c227a5849d --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcIndexedSessionRepositoryDependsOnDatabaseInitializationDetector.java @@ -0,0 +1,41 @@ +/* + * 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.session; + +import java.util.Collections; +import java.util.Set; + +import org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDependsOnDatabaseInitializationDetector; +import org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector; +import org.springframework.session.jdbc.JdbcIndexedSessionRepository; + +/** + * + * {@link DependsOnDatabaseInitializationDetector} for + * {@link JdbcIndexedSessionRepository}. + * + * @author Andy Wilkinson + */ +class JdbcIndexedSessionRepositoryDependsOnDatabaseInitializationDetector + extends AbstractBeansOfTypeDependsOnDatabaseInitializationDetector { + + @Override + protected Set> getDependsOnDatabaseInitializationBeanTypes() { + return Collections.singleton(JdbcIndexedSessionRepository.class); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionConfiguration.java index aa9e79002b..934b85e76c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionConfiguration.java @@ -27,9 +27,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.core.io.ResourceLoader; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.session.SessionRepository; @@ -50,6 +52,7 @@ import org.springframework.session.jdbc.config.annotation.web.http.JdbcHttpSessi @ConditionalOnBean(DataSource.class) @Conditional(ServletSessionCondition.class) @EnableConfigurationProperties(JdbcSessionProperties.class) +@Import(DatabaseInitializationDependencyConfigurer.class) class JdbcSessionConfiguration { @Bean diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 54df138891..22f1deac6e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -179,4 +179,5 @@ org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializerDatabase # Depends on database initialization detectors org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector=\ -org.springframework.boot.autoconfigure.batch.JobRepositoryDependsOnDatabaseInitializationDetector +org.springframework.boot.autoconfigure.batch.JobRepositoryDependsOnDatabaseInitializationDetector,\ +org.springframework.boot.autoconfigure.session.JdbcIndexedSessionRepositoryDependsOnDatabaseInitializationDetector diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationJdbcTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationJdbcTests.java index de6e62d29e..487a224ea6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationJdbcTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationJdbcTests.java @@ -21,10 +21,13 @@ import javax.sql.DataSource; import org.apache.commons.dbcp2.BasicDataSource; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; +import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; import org.springframework.boot.autoconfigure.session.JdbcSessionConfiguration.SpringBootJdbcHttpSessionConfiguration; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.jdbc.DataSourceInitializationMode; @@ -190,6 +193,51 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration }); } + @Test + void sessionRepositoryBeansDependOnJdbcSessionDataSourceInitializer() { + this.contextRunner.withPropertyValues("spring.session.store-type=jdbc").run((context) -> { + ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); + String[] sessionRepositoryNames = beanFactory.getBeanNamesForType(JdbcIndexedSessionRepository.class); + assertThat(sessionRepositoryNames).isNotEmpty(); + for (String sessionRepositoryName : sessionRepositoryNames) { + assertThat(beanFactory.getBeanDefinition(sessionRepositoryName).getDependsOn()) + .contains("jdbcSessionDataSourceInitializer"); + } + }); + } + + @Test + void sessionRepositoryBeansDependOnFlyway() { + this.contextRunner.withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class)) + .withPropertyValues("spring.session.store-type=jdbc", "spring.session.jdbc.initialize-schema=never") + .run((context) -> { + ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); + String[] sessionRepositoryNames = beanFactory + .getBeanNamesForType(JdbcIndexedSessionRepository.class); + assertThat(sessionRepositoryNames).isNotEmpty(); + for (String sessionRepositoryName : sessionRepositoryNames) { + assertThat(beanFactory.getBeanDefinition(sessionRepositoryName).getDependsOn()) + .contains("flyway", "flywayInitializer"); + } + }); + } + + @Test + void sessionRepositoryBeansDependOnLiquibase() { + this.contextRunner.withConfiguration(AutoConfigurations.of(LiquibaseAutoConfiguration.class)) + .withPropertyValues("spring.session.store-type=jdbc", "spring.session.jdbc.initialize-schema=never") + .run((context) -> { + ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); + String[] sessionRepositoryNames = beanFactory + .getBeanNamesForType(JdbcIndexedSessionRepository.class); + assertThat(sessionRepositoryNames).isNotEmpty(); + for (String sessionRepositoryName : sessionRepositoryNames) { + assertThat(beanFactory.getBeanDefinition(sessionRepositoryName).getDependsOn()) + .contains("liquibase"); + } + }); + } + @Configuration static class SessionDataSourceConfiguration {