Create spring-boot-session modules
This commit is contained in:
committed by
Phillip Webb
parent
014240d576
commit
e288c81b7b
@@ -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.session.jdbc.autoconfigure;
|
||||
|
||||
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<Class<?>> getDependsOnDatabaseInitializationBeanTypes() {
|
||||
return Collections.singleton(JdbcIndexedSessionRepository.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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.session.jdbc.autoconfigure;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||
import org.springframework.boot.autoconfigure.sql.init.OnDatabaseInitializationCondition;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.PropertyMapper;
|
||||
import org.springframework.boot.session.autoconfigure.SessionAutoConfiguration;
|
||||
import org.springframework.boot.session.autoconfigure.SessionProperties;
|
||||
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.Import;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.session.SessionRepository;
|
||||
import org.springframework.session.config.SessionRepositoryCustomizer;
|
||||
import org.springframework.session.jdbc.JdbcIndexedSessionRepository;
|
||||
import org.springframework.session.jdbc.config.annotation.SpringSessionDataSource;
|
||||
import org.springframework.session.jdbc.config.annotation.web.http.JdbcHttpSessionConfiguration;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuraion} for Spring Session JDBC.
|
||||
*
|
||||
* @author Eddú Meléndez
|
||||
* @author Stephane Nicoll
|
||||
* @author Vedran Pavic
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@AutoConfiguration(before = SessionAutoConfiguration.class)
|
||||
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||
@ConditionalOnClass({ JdbcTemplate.class, JdbcIndexedSessionRepository.class })
|
||||
@ConditionalOnMissingBean(SessionRepository.class)
|
||||
@ConditionalOnBean(DataSource.class)
|
||||
@EnableConfigurationProperties({ JdbcSessionProperties.class, SessionProperties.class })
|
||||
@Import({ DatabaseInitializationDependencyConfigurer.class, JdbcHttpSessionConfiguration.class })
|
||||
public class JdbcSessionAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@Conditional(OnJdbcSessionDatasourceInitializationCondition.class)
|
||||
JdbcSessionDataSourceScriptDatabaseInitializer jdbcSessionDataSourceScriptDatabaseInitializer(
|
||||
@SpringSessionDataSource ObjectProvider<DataSource> sessionDataSource,
|
||||
ObjectProvider<DataSource> dataSource, JdbcSessionProperties properties) {
|
||||
DataSource dataSourceToInitialize = sessionDataSource.getIfAvailable(dataSource::getObject);
|
||||
return new JdbcSessionDataSourceScriptDatabaseInitializer(dataSourceToInitialize, properties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
SessionRepositoryCustomizer<JdbcIndexedSessionRepository> springBootSessionRepositoryCustomizer(
|
||||
SessionProperties sessionProperties, JdbcSessionProperties jdbcSessionProperties,
|
||||
ServerProperties serverProperties) {
|
||||
return (sessionRepository) -> {
|
||||
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
|
||||
map.from(sessionProperties.determineTimeout(() -> serverProperties.getServlet().getSession().getTimeout()))
|
||||
.to(sessionRepository::setDefaultMaxInactiveInterval);
|
||||
map.from(jdbcSessionProperties::getTableName).to(sessionRepository::setTableName);
|
||||
map.from(jdbcSessionProperties::getFlushMode).to(sessionRepository::setFlushMode);
|
||||
map.from(jdbcSessionProperties::getSaveMode).to(sessionRepository::setSaveMode);
|
||||
map.from(jdbcSessionProperties::getCleanupCron).to(sessionRepository::setCleanupCron);
|
||||
};
|
||||
}
|
||||
|
||||
static class OnJdbcSessionDatasourceInitializationCondition extends OnDatabaseInitializationCondition {
|
||||
|
||||
OnJdbcSessionDatasourceInitializationCondition() {
|
||||
super("Jdbc Session", "spring.session.jdbc.initialize-schema");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.session.jdbc.autoconfigure;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* {@link DataSourceScriptDatabaseInitializer} for the Spring Session JDBC database. May
|
||||
* be registered as a bean to override auto-configuration.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Vedran Pavic
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public class JdbcSessionDataSourceScriptDatabaseInitializer extends DataSourceScriptDatabaseInitializer {
|
||||
|
||||
/**
|
||||
* Create a new {@link JdbcSessionDataSourceScriptDatabaseInitializer} instance.
|
||||
* @param dataSource the Spring Session JDBC data source
|
||||
* @param properties the Spring Session JDBC properties
|
||||
* @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<String> 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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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.session.jdbc.autoconfigure;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.sql.init.DatabaseInitializationMode;
|
||||
import org.springframework.session.FlushMode;
|
||||
import org.springframework.session.SaveMode;
|
||||
|
||||
/**
|
||||
* Configuration properties for JDBC-backed Spring Session.
|
||||
*
|
||||
* @author Vedran Pavic
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@ConfigurationProperties("spring.session.jdbc")
|
||||
public class JdbcSessionProperties {
|
||||
|
||||
private static final String DEFAULT_SCHEMA_LOCATION = "classpath:org/springframework/"
|
||||
+ "session/jdbc/schema-@@platform@@.sql";
|
||||
|
||||
private static final String DEFAULT_TABLE_NAME = "SPRING_SESSION";
|
||||
|
||||
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.
|
||||
*/
|
||||
private String tableName = DEFAULT_TABLE_NAME;
|
||||
|
||||
/**
|
||||
* Cron expression for expired session cleanup job.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
private FlushMode flushMode = FlushMode.ON_SAVE;
|
||||
|
||||
/**
|
||||
* Sessions save mode. Determines how session changes are tracked and saved to the
|
||||
* session store.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
public void setTableName(String tableName) {
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
public String getCleanupCron() {
|
||||
return this.cleanupCron;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public void setFlushMode(FlushMode flushMode) {
|
||||
this.flushMode = flushMode;
|
||||
}
|
||||
|
||||
public SaveMode getSaveMode() {
|
||||
return this.saveMode;
|
||||
}
|
||||
|
||||
public void setSaveMode(SaveMode saveMode) {
|
||||
this.saveMode = saveMode;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Auto-configuration for Spring Session JDBC.
|
||||
*/
|
||||
package org.springframework.boot.session.jdbc.autoconfigure;
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"groups": [],
|
||||
"properties": []
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# Depends on Database Initialization Detectors
|
||||
org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector=\
|
||||
org.springframework.boot.session.jdbc.autoconfigure.JdbcIndexedSessionRepositoryDependsOnDatabaseInitializationDetector
|
||||
@@ -0,0 +1 @@
|
||||
org.springframework.boot.session.jdbc.autoconfigure.JdbcSessionAutoConfiguration
|
||||
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* 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.session.jdbc.autoconfigure;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration;
|
||||
import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration;
|
||||
import org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration;
|
||||
import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;
|
||||
import org.springframework.boot.liquibase.autoconfigure.LiquibaseAutoConfiguration;
|
||||
import org.springframework.boot.session.autoconfigure.AbstractSessionAutoConfigurationTests;
|
||||
import org.springframework.boot.session.autoconfigure.SessionAutoConfiguration;
|
||||
import org.springframework.boot.sql.init.DatabaseInitializationMode;
|
||||
import org.springframework.boot.sql.init.DatabaseInitializationSettings;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.classpath.resources.WithResource;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.jdbc.BadSqlGrammarException;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.session.FlushMode;
|
||||
import org.springframework.session.SaveMode;
|
||||
import org.springframework.session.jdbc.JdbcIndexedSessionRepository;
|
||||
import org.springframework.session.jdbc.PostgreSqlJdbcIndexedSessionRepositoryCustomizer;
|
||||
import org.springframework.session.jdbc.config.annotation.SpringSessionDataSource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
* Tests for {@link JdbcSessionAutoConfiguration}.
|
||||
*
|
||||
* @author Vedran Pavic
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class JdbcSessionAutoConfigurationTests extends AbstractSessionAutoConfigurationTests {
|
||||
|
||||
@BeforeEach
|
||||
void prepareRunner() {
|
||||
this.contextRunner = new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,
|
||||
DataSourceTransactionManagerAutoConfiguration.class, JdbcTemplateAutoConfiguration.class,
|
||||
SessionAutoConfiguration.class, JdbcSessionAutoConfiguration.class))
|
||||
.withPropertyValues("spring.datasource.generate-unique-name=true");
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultConfig() {
|
||||
this.contextRunner.run((context) -> {
|
||||
JdbcIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
JdbcIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval",
|
||||
new ServerProperties().getServlet().getSession().getTimeout());
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("tableName", "SPRING_SESSION");
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("cleanupCron", "0 * * * * *");
|
||||
assertThat(context.getBean(JdbcSessionProperties.class).getInitializeSchema())
|
||||
.isEqualTo(DatabaseInitializationMode.EMBEDDED);
|
||||
assertThat(context.getBean(JdbcOperations.class).queryForList("select * from SPRING_SESSION")).isEmpty();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void disableDataSourceInitializer() {
|
||||
this.contextRunner.withPropertyValues("spring.session.jdbc.initialize-schema=never").run((context) -> {
|
||||
assertThat(context).doesNotHaveBean(JdbcSessionDataSourceScriptDatabaseInitializer.class);
|
||||
JdbcIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
JdbcIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("tableName", "SPRING_SESSION");
|
||||
assertThat(context.getBean(JdbcSessionProperties.class).getInitializeSchema())
|
||||
.isEqualTo(DatabaseInitializationMode.NEVER);
|
||||
assertThatExceptionOfType(BadSqlGrammarException.class)
|
||||
.isThrownBy(() -> context.getBean(JdbcOperations.class).queryForList("select * from SPRING_SESSION"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void customTimeout() {
|
||||
this.contextRunner.withPropertyValues("spring.session.timeout=1m").run((context) -> {
|
||||
JdbcIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
JdbcIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", Duration.ofMinutes(1));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void customTableName() {
|
||||
this.contextRunner.withPropertyValues("spring.session.jdbc.table-name=FOO_BAR",
|
||||
"spring.session.jdbc.schema=classpath:org/springframework/boot/session/jdbc/autoconfigure/custom-schema-h2.sql")
|
||||
.run((context) -> {
|
||||
JdbcIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
JdbcIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("tableName", "FOO_BAR");
|
||||
assertThat(context.getBean(JdbcSessionProperties.class).getInitializeSchema())
|
||||
.isEqualTo(DatabaseInitializationMode.EMBEDDED);
|
||||
assertThat(context.getBean(JdbcOperations.class).queryForList("select * from FOO_BAR")).isEmpty();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void customCleanupCron() {
|
||||
this.contextRunner.withPropertyValues("spring.session.jdbc.cleanup-cron=0 0 12 * * *").run((context) -> {
|
||||
assertThat(context.getBean(JdbcSessionProperties.class).getCleanupCron()).isEqualTo("0 0 12 * * *");
|
||||
JdbcIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
JdbcIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("cleanupCron", "0 0 12 * * *");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void customFlushMode() {
|
||||
this.contextRunner.withPropertyValues("spring.session.jdbc.flush-mode=immediate").run((context) -> {
|
||||
JdbcIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
JdbcIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("flushMode", FlushMode.IMMEDIATE);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void customSaveMode() {
|
||||
this.contextRunner.withPropertyValues("spring.session.jdbc.save-mode=on-get-attribute").run((context) -> {
|
||||
JdbcIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
JdbcIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("saveMode", SaveMode.ON_GET_ATTRIBUTE);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void sessionDataSourceIsUsedWhenAvailable() {
|
||||
this.contextRunner.withUserConfiguration(SessionDataSourceConfiguration.class).run((context) -> {
|
||||
JdbcIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
JdbcIndexedSessionRepository.class);
|
||||
DataSource sessionDataSource = context.getBean("sessionDataSource", DataSource.class);
|
||||
assertThat(repository).extracting("jdbcOperations.dataSource").isEqualTo(sessionDataSource);
|
||||
assertThat(context.getBean(JdbcSessionDataSourceScriptDatabaseInitializer.class))
|
||||
.hasFieldOrPropertyWithValue("dataSource", sessionDataSource);
|
||||
assertThatExceptionOfType(BadSqlGrammarException.class)
|
||||
.isThrownBy(() -> context.getBean(JdbcOperations.class).queryForList("select * from SPRING_SESSION"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void sessionRepositoryBeansDependOnJdbcSessionDataSourceInitializer() {
|
||||
this.contextRunner.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("jdbcSessionDataSourceScriptDatabaseInitializer");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void sessionRepositoryBeansDependOnFlyway() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class))
|
||||
.withPropertyValues("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
|
||||
@WithResource(name = "db/changelog/db.changelog-master.yaml", content = "databaseChangeLog:")
|
||||
void sessionRepositoryBeansDependOnLiquibase() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(LiquibaseAutoConfiguration.class))
|
||||
.withPropertyValues("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");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenTheUserDefinesTheirOwnJdbcSessionDatabaseInitializerThenTheAutoConfiguredInitializerBacksOff() {
|
||||
this.contextRunner.withUserConfiguration(CustomJdbcSessionDatabaseInitializerConfiguration.class)
|
||||
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,
|
||||
DataSourceTransactionManagerAutoConfiguration.class))
|
||||
.run((context) -> assertThat(context).hasSingleBean(JdbcSessionDataSourceScriptDatabaseInitializer.class)
|
||||
.doesNotHaveBean("jdbcSessionDataSourceScriptDatabaseInitializer")
|
||||
.hasBean("customInitializer"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenTheUserDefinesTheirOwnDatabaseInitializerThenTheAutoConfiguredJdbcSessionInitializerRemains() {
|
||||
this.contextRunner.withUserConfiguration(CustomDatabaseInitializerConfiguration.class)
|
||||
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,
|
||||
DataSourceTransactionManagerAutoConfiguration.class))
|
||||
.run((context) -> assertThat(context).hasSingleBean(JdbcSessionDataSourceScriptDatabaseInitializer.class)
|
||||
.hasBean("customInitializer"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenTheUserDefinesTheirOwnJdbcIndexedSessionRepositoryCustomizerThenDefaultConfigurationIsOverwritten() {
|
||||
String expectedCreateSessionAttributeQuery = """
|
||||
INSERT INTO SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES)
|
||||
VALUES (?, ?, ?)
|
||||
ON CONFLICT (SESSION_PRIMARY_ID, ATTRIBUTE_NAME)
|
||||
DO UPDATE SET ATTRIBUTE_BYTES = EXCLUDED.ATTRIBUTE_BYTES
|
||||
""";
|
||||
this.contextRunner.withUserConfiguration(CustomJdbcIndexedSessionRepositoryCustomizerConfiguration.class)
|
||||
.withConfiguration(AutoConfigurations.of(SessionAutoConfiguration.class))
|
||||
.run((context) -> {
|
||||
JdbcIndexedSessionRepository repository = validateSessionRepository(context,
|
||||
JdbcIndexedSessionRepository.class);
|
||||
assertThat(repository).hasFieldOrPropertyWithValue("createSessionAttributeQuery",
|
||||
expectedCreateSessionAttributeQuery);
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class SessionDataSourceConfiguration {
|
||||
|
||||
@Bean
|
||||
@SpringSessionDataSource
|
||||
DataSource sessionDataSource() {
|
||||
BasicDataSource dataSource = new BasicDataSource();
|
||||
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||
dataSource.setUrl("jdbc:hsqldb:mem:sessiondb");
|
||||
dataSource.setUsername("sa");
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
DataSource mainDataSource() {
|
||||
BasicDataSource dataSource = new BasicDataSource();
|
||||
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||
dataSource.setUrl("jdbc:hsqldb:mem:maindb");
|
||||
dataSource.setUsername("sa");
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CustomJdbcSessionDatabaseInitializerConfiguration {
|
||||
|
||||
@Bean
|
||||
JdbcSessionDataSourceScriptDatabaseInitializer customInitializer(DataSource dataSource,
|
||||
JdbcSessionProperties properties) {
|
||||
return new JdbcSessionDataSourceScriptDatabaseInitializer(dataSource, properties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CustomDatabaseInitializerConfiguration {
|
||||
|
||||
@Bean
|
||||
DataSourceScriptDatabaseInitializer customInitializer(DataSource dataSource) {
|
||||
return new DataSourceScriptDatabaseInitializer(dataSource, new DatabaseInitializationSettings());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomJdbcIndexedSessionRepositoryCustomizerConfiguration {
|
||||
|
||||
@Bean
|
||||
PostgreSqlJdbcIndexedSessionRepositoryCustomizer postgreSqlJdbcIndexedSessionRepositoryCustomizer() {
|
||||
return new PostgreSqlJdbcIndexedSessionRepositoryCustomizer();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2012-2023 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.session.jdbc.autoconfigure;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.sql.init.DatabaseInitializationSettings;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link JdbcSessionDataSourceScriptDatabaseInitializer}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class JdbcSessionDataSourceScriptDatabaseInitializerTests {
|
||||
|
||||
@Test
|
||||
void getSettingsWithPlatformDoesNotTouchDataSource() {
|
||||
DataSource dataSource = mock(DataSource.class);
|
||||
JdbcSessionProperties properties = new JdbcSessionProperties();
|
||||
properties.setPlatform("test");
|
||||
DatabaseInitializationSettings settings = JdbcSessionDataSourceScriptDatabaseInitializer.getSettings(dataSource,
|
||||
properties);
|
||||
assertThat(settings.getSchemaLocations())
|
||||
.containsOnly("classpath:org/springframework/session/jdbc/schema-test.sql");
|
||||
then(dataSource).shouldHaveNoInteractions();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
CREATE TABLE FOO_BAR (
|
||||
SESSION_ID CHAR(36),
|
||||
CREATION_TIME BIGINT NOT NULL,
|
||||
LAST_ACCESS_TIME BIGINT NOT NULL,
|
||||
MAX_INACTIVE_INTERVAL INT NOT NULL,
|
||||
PRINCIPAL_NAME VARCHAR(100),
|
||||
CONSTRAINT FOO_BAR_PK PRIMARY KEY (SESSION_ID)
|
||||
);
|
||||
|
||||
CREATE INDEX FOO_BAR_IX1 ON FOO_BAR (LAST_ACCESS_TIME);
|
||||
|
||||
CREATE TABLE FOO_BAR_ATTRIBUTES (
|
||||
SESSION_ID CHAR(36),
|
||||
ATTRIBUTE_NAME VARCHAR(100),
|
||||
ATTRIBUTE_BYTES LONGVARBINARY,
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME),
|
||||
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES FOO_BAR(SESSION_ID) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX FOO_BAR_ATTRIBUTES_IX1 ON FOO_BAR_ATTRIBUTES (SESSION_ID);
|
||||
Reference in New Issue
Block a user