Skip to content

Commit 7b94b40

Browse files
committed
Ensure that Session JDBC schema is in place before DB is accessed
Fixes gh-27208
1 parent 4b1b2d6 commit 7b94b40

File tree

2 files changed

+86
-9
lines changed

2 files changed

+86
-9
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/JdbcSessionConfiguration.java

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,16 @@
2020

2121
import javax.sql.DataSource;
2222

23+
import liquibase.integration.spring.SpringLiquibase;
24+
import org.flywaydb.core.Flyway;
25+
2326
import org.springframework.beans.factory.ObjectProvider;
2427
import org.springframework.beans.factory.annotation.Autowired;
2528
import org.springframework.boot.autoconfigure.AbstractDependsOnBeanFactoryPostProcessor;
2629
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
2730
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2831
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
32+
import org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializer;
2933
import org.springframework.boot.autoconfigure.web.ServerProperties;
3034
import org.springframework.boot.context.properties.EnableConfigurationProperties;
3135
import org.springframework.context.annotation.Bean;
@@ -81,15 +85,40 @@ void customize(SessionProperties sessionProperties, JdbcSessionProperties jdbcSe
8185

8286
}
8387

88+
@Configuration(proxyBeanMethods = false)
89+
static class JdbcIndexedSessionRepositoryDependencyConfiguration {
90+
91+
@Bean
92+
JdbcIndexedSessionRepositoryDependsOnBeanFactoryPostProcessor dataSourceInitializerJdbcIndexedSessionRepositoryDependsOnBeanFactoryPostProcessor() {
93+
return new JdbcIndexedSessionRepositoryDependsOnBeanFactoryPostProcessor(
94+
JdbcSessionDataSourceInitializer.class);
95+
}
96+
97+
@Bean
98+
@ConditionalOnClass(name = "org.flywaydb.core.Flyway")
99+
JdbcIndexedSessionRepositoryDependsOnBeanFactoryPostProcessor flywayJdbcIndexedSessionRepositoryDependsOnBeanFactoryPostProcessor() {
100+
return new JdbcIndexedSessionRepositoryDependsOnBeanFactoryPostProcessor(FlywayMigrationInitializer.class,
101+
Flyway.class);
102+
}
103+
104+
@Bean
105+
@ConditionalOnClass(name = "liquibase.integration.spring.SpringLiquibase")
106+
JdbcIndexedSessionRepositoryDependsOnBeanFactoryPostProcessor liquibaseJdbcIndexedSessionRepositoryDependsOnBeanFactoryPostProcessor() {
107+
return new JdbcIndexedSessionRepositoryDependsOnBeanFactoryPostProcessor(FlywayMigrationInitializer.class,
108+
SpringLiquibase.class);
109+
}
110+
111+
}
112+
84113
/**
85-
* Post processor to ensure that {@link JdbcIndexedSessionRepository} beans depend on
86-
* any {@link JdbcSessionDataSourceInitializer} beans.
114+
* {@link AbstractDependsOnBeanFactoryPostProcessor} for Spring Session JDBC's
115+
* {@link JdbcIndexedSessionRepository}.
87116
*/
88-
static class DataSourceInitializationJdbcIndexedSessionRepositoryDependencyConfiguration
117+
static class JdbcIndexedSessionRepositoryDependsOnBeanFactoryPostProcessor
89118
extends AbstractDependsOnBeanFactoryPostProcessor {
90119

91-
DataSourceInitializationJdbcIndexedSessionRepositoryDependencyConfiguration() {
92-
super(JdbcIndexedSessionRepository.class, JdbcSessionDataSourceInitializer.class);
120+
JdbcIndexedSessionRepositoryDependsOnBeanFactoryPostProcessor(Class<?>... dependencyTypes) {
121+
super(JdbcIndexedSessionRepository.class, dependencyTypes);
93122
}
94123

95124
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationJdbcTests.java

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,13 @@
2121
import org.apache.commons.dbcp2.BasicDataSource;
2222
import org.junit.jupiter.api.Test;
2323

24+
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
2425
import org.springframework.boot.autoconfigure.AutoConfigurations;
25-
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
26+
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
2627
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
28+
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
2729
import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;
30+
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
2831
import org.springframework.boot.autoconfigure.session.JdbcSessionConfiguration.SpringBootJdbcHttpSessionConfiguration;
2932
import org.springframework.boot.autoconfigure.web.ServerProperties;
3033
import org.springframework.boot.jdbc.DataSourceInitializationMode;
@@ -57,9 +60,9 @@
5760
class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfigurationTests {
5861

5962
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
60-
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,
61-
DataSourceTransactionManagerAutoConfiguration.class, JdbcTemplateAutoConfiguration.class,
62-
SessionAutoConfiguration.class))
63+
.withConfiguration(AutoConfigurations.of(DataSourceTransactionManagerAutoConfiguration.class,
64+
JdbcTemplateAutoConfiguration.class, SessionAutoConfiguration.class))
65+
.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
6366
.withPropertyValues("spring.datasource.generate-unique-name=true");
6467

6568
@Test
@@ -190,6 +193,51 @@ void sessionDataSourceIsUsedWhenAvailable() {
190193
});
191194
}
192195

196+
@Test
197+
void sessionRepositoryBeansDependOnJdbcSessionDataSourceInitializer() {
198+
this.contextRunner.withPropertyValues("spring.session.store-type=jdbc").run((context) -> {
199+
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
200+
String[] sessionRepositoryNames = beanFactory.getBeanNamesForType(JdbcIndexedSessionRepository.class);
201+
assertThat(sessionRepositoryNames).isNotEmpty();
202+
for (String sessionRepositoryName : sessionRepositoryNames) {
203+
assertThat(beanFactory.getBeanDefinition(sessionRepositoryName).getDependsOn())
204+
.contains("jdbcSessionDataSourceInitializer");
205+
}
206+
});
207+
}
208+
209+
@Test
210+
void sessionRepositoryBeansDependOnFlyway() {
211+
this.contextRunner.withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class))
212+
.withPropertyValues("spring.session.store-type=jdbc", "spring.session.jdbc.initialize-schema=never")
213+
.run((context) -> {
214+
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
215+
String[] sessionRepositoryNames = beanFactory
216+
.getBeanNamesForType(JdbcIndexedSessionRepository.class);
217+
assertThat(sessionRepositoryNames).isNotEmpty();
218+
for (String sessionRepositoryName : sessionRepositoryNames) {
219+
assertThat(beanFactory.getBeanDefinition(sessionRepositoryName).getDependsOn())
220+
.contains("flyway", "flywayInitializer");
221+
}
222+
});
223+
}
224+
225+
@Test
226+
void sessionRepositoryBeansDependOnLiquibase() {
227+
this.contextRunner.withConfiguration(AutoConfigurations.of(LiquibaseAutoConfiguration.class))
228+
.withPropertyValues("spring.session.store-type=jdbc", "spring.session.jdbc.initialize-schema=never")
229+
.run((context) -> {
230+
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
231+
String[] sessionRepositoryNames = beanFactory
232+
.getBeanNamesForType(JdbcIndexedSessionRepository.class);
233+
assertThat(sessionRepositoryNames).isNotEmpty();
234+
for (String sessionRepositoryName : sessionRepositoryNames) {
235+
assertThat(beanFactory.getBeanDefinition(sessionRepositoryName).getDependsOn())
236+
.contains("liquibase");
237+
}
238+
});
239+
}
240+
193241
@Configuration
194242
static class SessionDataSourceConfiguration {
195243

0 commit comments

Comments
 (0)