Rework Spring Session auto-configuration to use customizers

This commit reworks Spring Session auto-configuration to avoid
extending Spring Session's configuration classes. Instead, those
configuration classes are now imported and customizations are
applied using dedicated (Reactive)SessionRepositoryCustomizer beans.

See gh-32554
This commit is contained in:
Vedran Pavic 2022-09-26 10:07:29 +02:00 committed by Andy Wilkinson
parent a9c1b4a7c3
commit ad8753923a
8 changed files with 133 additions and 115 deletions

View File

@ -16,18 +16,19 @@
package org.springframework.boot.autoconfigure.session; package org.springframework.boot.autoconfigure.session;
import java.time.Duration;
import com.hazelcast.core.HazelcastInstance; import com.hazelcast.core.HazelcastInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.session.SessionRepository; import org.springframework.session.SessionRepository;
import org.springframework.session.config.SessionRepositoryCustomizer;
import org.springframework.session.hazelcast.HazelcastIndexedSessionRepository; import org.springframework.session.hazelcast.HazelcastIndexedSessionRepository;
import org.springframework.session.hazelcast.config.annotation.web.http.HazelcastHttpSessionConfiguration; import org.springframework.session.hazelcast.config.annotation.web.http.HazelcastHttpSessionConfiguration;
@ -47,19 +48,22 @@ import org.springframework.session.hazelcast.config.annotation.web.http.Hazelcas
class HazelcastSessionConfiguration { class HazelcastSessionConfiguration {
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
public static class SpringBootHazelcastHttpSessionConfiguration extends HazelcastHttpSessionConfiguration { @Import(HazelcastHttpSessionConfiguration.class)
static class SpringBootHazelcastHttpSessionConfiguration {
@Autowired @Bean
public void customize(SessionProperties sessionProperties, SessionRepositoryCustomizer<HazelcastIndexedSessionRepository> springBootSessionRepositoryCustomizer(
HazelcastSessionProperties hazelcastSessionProperties, ServerProperties serverProperties) { SessionProperties sessionProperties, HazelcastSessionProperties hazelcastSessionProperties,
Duration timeout = sessionProperties ServerProperties serverProperties) {
.determineTimeout(() -> serverProperties.getServlet().getSession().getTimeout()); PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
if (timeout != null) { return (sessionRepository) -> {
setMaxInactiveIntervalInSeconds((int) timeout.getSeconds()); map.from(sessionProperties
} .determineTimeout(() -> serverProperties.getServlet().getSession().getTimeout()))
setSessionMapName(hazelcastSessionProperties.getMapName()); .to((timeout) -> sessionRepository.setDefaultMaxInactiveInterval((int) timeout.getSeconds()));
setFlushMode(hazelcastSessionProperties.getFlushMode()); map.from(hazelcastSessionProperties::getMapName).to(sessionRepository::setSessionMapName);
setSaveMode(hazelcastSessionProperties.getSaveMode()); map.from(hazelcastSessionProperties::getFlushMode).to(sessionRepository::setFlushMode);
map.from(hazelcastSessionProperties::getSaveMode).to(sessionRepository::setSaveMode);
};
} }
} }

View File

@ -16,18 +16,16 @@
package org.springframework.boot.autoconfigure.session; package org.springframework.boot.autoconfigure.session;
import java.time.Duration;
import javax.sql.DataSource; import javax.sql.DataSource;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.sql.init.OnDatabaseInitializationCondition; import org.springframework.boot.autoconfigure.sql.init.OnDatabaseInitializationCondition;
import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer; import org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Conditional;
@ -35,6 +33,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.session.SessionRepository; import org.springframework.session.SessionRepository;
import org.springframework.session.config.SessionRepositoryCustomizer;
import org.springframework.session.jdbc.JdbcIndexedSessionRepository; import org.springframework.session.jdbc.JdbcIndexedSessionRepository;
import org.springframework.session.jdbc.config.annotation.SpringSessionDataSource; import org.springframework.session.jdbc.config.annotation.SpringSessionDataSource;
import org.springframework.session.jdbc.config.annotation.web.http.JdbcHttpSessionConfiguration; import org.springframework.session.jdbc.config.annotation.web.http.JdbcHttpSessionConfiguration;
@ -65,20 +64,23 @@ class JdbcSessionConfiguration {
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class SpringBootJdbcHttpSessionConfiguration extends JdbcHttpSessionConfiguration { @Import(JdbcHttpSessionConfiguration.class)
static class SpringBootJdbcHttpSessionConfiguration {
@Autowired @Bean
void customize(SessionProperties sessionProperties, JdbcSessionProperties jdbcSessionProperties, SessionRepositoryCustomizer<JdbcIndexedSessionRepository> springBootSessionRepositoryCustomizer(
SessionProperties sessionProperties, JdbcSessionProperties jdbcSessionProperties,
ServerProperties serverProperties) { ServerProperties serverProperties) {
Duration timeout = sessionProperties PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
.determineTimeout(() -> serverProperties.getServlet().getSession().getTimeout()); return (sessionRepository) -> {
if (timeout != null) { map.from(sessionProperties
setMaxInactiveIntervalInSeconds((int) timeout.getSeconds()); .determineTimeout(() -> serverProperties.getServlet().getSession().getTimeout()))
} .to((timeout) -> sessionRepository.setDefaultMaxInactiveInterval((int) timeout.getSeconds()));
setTableName(jdbcSessionProperties.getTableName()); map.from(jdbcSessionProperties::getTableName).to(sessionRepository::setTableName);
setCleanupCron(jdbcSessionProperties.getCleanupCron()); map.from(jdbcSessionProperties::getFlushMode).to(sessionRepository::setFlushMode);
setFlushMode(jdbcSessionProperties.getFlushMode()); map.from(jdbcSessionProperties::getSaveMode).to(sessionRepository::setSaveMode);
setSaveMode(jdbcSessionProperties.getSaveMode()); map.from(jdbcSessionProperties::getCleanupCron).to(sessionRepository::setCleanupCron);
};
} }
} }

View File

@ -16,17 +16,18 @@
package org.springframework.boot.autoconfigure.session; package org.springframework.boot.autoconfigure.session;
import java.time.Duration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.mongodb.core.ReactiveMongoOperations; import org.springframework.data.mongodb.core.ReactiveMongoOperations;
import org.springframework.session.ReactiveSessionRepository; import org.springframework.session.ReactiveSessionRepository;
import org.springframework.session.config.ReactiveSessionRepositoryCustomizer;
import org.springframework.session.data.mongo.ReactiveMongoSessionRepository; import org.springframework.session.data.mongo.ReactiveMongoSessionRepository;
import org.springframework.session.data.mongo.config.annotation.web.reactive.ReactiveMongoWebSessionConfiguration; import org.springframework.session.data.mongo.config.annotation.web.reactive.ReactiveMongoWebSessionConfiguration;
@ -35,6 +36,7 @@ import org.springframework.session.data.mongo.config.annotation.web.reactive.Rea
* *
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Weix Sun * @author Weix Sun
* @author Vedran Pavic
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ ReactiveMongoOperations.class, ReactiveMongoSessionRepository.class }) @ConditionalOnClass({ ReactiveMongoOperations.class, ReactiveMongoSessionRepository.class })
@ -44,17 +46,20 @@ import org.springframework.session.data.mongo.config.annotation.web.reactive.Rea
class MongoReactiveSessionConfiguration { class MongoReactiveSessionConfiguration {
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class SpringBootReactiveMongoWebSessionConfiguration extends ReactiveMongoWebSessionConfiguration { @Import(ReactiveMongoWebSessionConfiguration.class)
static class SpringBootMongoWebSessionConfiguration {
@Autowired @Bean
void customize(SessionProperties sessionProperties, MongoSessionProperties mongoSessionProperties, ReactiveSessionRepositoryCustomizer<ReactiveMongoSessionRepository> springBootSessionRepositoryCustomizer(
SessionProperties sessionProperties, MongoSessionProperties mongoSessionProperties,
ServerProperties serverProperties) { ServerProperties serverProperties) {
Duration timeout = sessionProperties PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
.determineTimeout(() -> serverProperties.getReactive().getSession().getTimeout()); return (sessionRepository) -> {
if (timeout != null) { map.from(sessionProperties
setMaxInactiveIntervalInSeconds((int) timeout.getSeconds()); .determineTimeout(() -> serverProperties.getReactive().getSession().getTimeout()))
} .to((timeout) -> sessionRepository.setMaxInactiveIntervalInSeconds((int) timeout.getSeconds()));
setCollectionName(mongoSessionProperties.getCollectionName()); map.from(mongoSessionProperties::getCollectionName).to(sessionRepository::setCollectionName);
};
} }
} }

View File

@ -16,17 +16,18 @@
package org.springframework.boot.autoconfigure.session; package org.springframework.boot.autoconfigure.session;
import java.time.Duration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.session.SessionRepository; import org.springframework.session.SessionRepository;
import org.springframework.session.config.SessionRepositoryCustomizer;
import org.springframework.session.data.mongo.MongoIndexedSessionRepository; import org.springframework.session.data.mongo.MongoIndexedSessionRepository;
import org.springframework.session.data.mongo.config.annotation.web.http.MongoHttpSessionConfiguration; import org.springframework.session.data.mongo.config.annotation.web.http.MongoHttpSessionConfiguration;
@ -35,6 +36,7 @@ import org.springframework.session.data.mongo.config.annotation.web.http.MongoHt
* *
* @author Eddú Meléndez * @author Eddú Meléndez
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Vedran Pavic
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ MongoOperations.class, MongoIndexedSessionRepository.class }) @ConditionalOnClass({ MongoOperations.class, MongoIndexedSessionRepository.class })
@ -44,17 +46,20 @@ import org.springframework.session.data.mongo.config.annotation.web.http.MongoHt
class MongoSessionConfiguration { class MongoSessionConfiguration {
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
public static class SpringBootMongoHttpSessionConfiguration extends MongoHttpSessionConfiguration { @Import(MongoHttpSessionConfiguration.class)
static class SpringBootMongoHttpSessionConfiguration {
@Autowired @Bean
public void customize(SessionProperties sessionProperties, MongoSessionProperties mongoSessionProperties, SessionRepositoryCustomizer<MongoIndexedSessionRepository> springBootSessionRepositoryCustomizer(
SessionProperties sessionProperties, MongoSessionProperties mongoSessionProperties,
ServerProperties serverProperties) { ServerProperties serverProperties) {
Duration timeout = sessionProperties PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
.determineTimeout(() -> serverProperties.getServlet().getSession().getTimeout()); return (sessionRepository) -> {
if (timeout != null) { map.from(sessionProperties
setMaxInactiveIntervalInSeconds((int) timeout.getSeconds()); .determineTimeout(() -> serverProperties.getServlet().getSession().getTimeout()))
} .to((timeout) -> sessionRepository.setMaxInactiveIntervalInSeconds((int) timeout.getSeconds()));
setCollectionName(mongoSessionProperties.getCollectionName()); map.from(mongoSessionProperties::getCollectionName).to(sessionRepository::setCollectionName);
};
} }
} }

View File

@ -16,17 +16,18 @@
package org.springframework.boot.autoconfigure.session; package org.springframework.boot.autoconfigure.session;
import java.time.Duration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory; import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
import org.springframework.session.ReactiveSessionRepository; import org.springframework.session.ReactiveSessionRepository;
import org.springframework.session.config.ReactiveSessionRepositoryCustomizer;
import org.springframework.session.data.redis.ReactiveRedisSessionRepository; import org.springframework.session.data.redis.ReactiveRedisSessionRepository;
import org.springframework.session.data.redis.config.annotation.web.server.RedisWebSessionConfiguration; import org.springframework.session.data.redis.config.annotation.web.server.RedisWebSessionConfiguration;
@ -35,6 +36,7 @@ import org.springframework.session.data.redis.config.annotation.web.server.Redis
* *
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Weix Sun * @author Weix Sun
* @author Vedran Pavic
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ ReactiveRedisConnectionFactory.class, ReactiveRedisSessionRepository.class }) @ConditionalOnClass({ ReactiveRedisConnectionFactory.class, ReactiveRedisSessionRepository.class })
@ -44,18 +46,21 @@ import org.springframework.session.data.redis.config.annotation.web.server.Redis
class RedisReactiveSessionConfiguration { class RedisReactiveSessionConfiguration {
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class SpringBootRedisWebSessionConfiguration extends RedisWebSessionConfiguration { @Import(RedisWebSessionConfiguration.class)
static class SpringBootRedisWebSessionConfiguration {
@Autowired @Bean
void customize(SessionProperties sessionProperties, RedisSessionProperties redisSessionProperties, ReactiveSessionRepositoryCustomizer<ReactiveRedisSessionRepository> springBootSessionRepositoryCustomizer(
SessionProperties sessionProperties, RedisSessionProperties redisSessionProperties,
ServerProperties serverProperties) { ServerProperties serverProperties) {
Duration timeout = sessionProperties PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
.determineTimeout(() -> serverProperties.getReactive().getSession().getTimeout()); return (sessionRepository) -> {
if (timeout != null) { map.from(sessionProperties
setMaxInactiveIntervalInSeconds((int) timeout.getSeconds()); .determineTimeout(() -> serverProperties.getReactive().getSession().getTimeout()))
} .to((timeout) -> sessionRepository.setDefaultMaxInactiveInterval((int) timeout.getSeconds()));
setRedisNamespace(redisSessionProperties.getNamespace()); map.from(redisSessionProperties::getNamespace).to(sessionRepository::setRedisKeyNamespace);
setSaveMode(redisSessionProperties.getSaveMode()); map.from(redisSessionProperties::getSaveMode).to(sessionRepository::setSaveMode);
};
} }
} }

View File

@ -16,22 +16,23 @@
package org.springframework.boot.autoconfigure.session; package org.springframework.boot.autoconfigure.session;
import java.time.Duration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException; import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.session.SessionRepository; import org.springframework.session.SessionRepository;
import org.springframework.session.config.SessionRepositoryCustomizer;
import org.springframework.session.data.redis.RedisIndexedSessionRepository; import org.springframework.session.data.redis.RedisIndexedSessionRepository;
import org.springframework.session.data.redis.RedisSessionRepository;
import org.springframework.session.data.redis.config.ConfigureNotifyKeyspaceEventsAction; import org.springframework.session.data.redis.config.ConfigureNotifyKeyspaceEventsAction;
import org.springframework.session.data.redis.config.ConfigureRedisAction; import org.springframework.session.data.redis.config.ConfigureRedisAction;
import org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration; import org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration;
@ -59,10 +60,12 @@ class RedisSessionConfiguration {
static class DefaultRedisSessionConfiguration { static class DefaultRedisSessionConfiguration {
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class SpringBootRedisHttpSessionConfiguration extends RedisHttpSessionConfiguration { @Import(RedisHttpSessionConfiguration.class)
static class SpringBootRedisHttpSessionConfiguration {
@Autowired @Bean
void customize(SessionProperties sessionProperties, RedisSessionProperties redisSessionProperties, SessionRepositoryCustomizer<RedisSessionRepository> springBootSessionRepositoryCustomizer(
SessionProperties sessionProperties, RedisSessionProperties redisSessionProperties,
ServerProperties serverProperties) { ServerProperties serverProperties) {
String cleanupCron = redisSessionProperties.getCleanupCron(); String cleanupCron = redisSessionProperties.getCleanupCron();
if (cleanupCron != null) { if (cleanupCron != null) {
@ -71,14 +74,15 @@ class RedisSessionConfiguration {
"Cron-based cleanup is only supported when spring.session.redis.repository-type is set to " "Cron-based cleanup is only supported when spring.session.redis.repository-type is set to "
+ "indexed."); + "indexed.");
} }
Duration timeout = sessionProperties PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
.determineTimeout(() -> serverProperties.getServlet().getSession().getTimeout()); return (sessionRepository) -> {
if (timeout != null) { map.from(sessionProperties
setMaxInactiveIntervalInSeconds((int) timeout.getSeconds()); .determineTimeout(() -> serverProperties.getServlet().getSession().getTimeout()))
} .to(sessionRepository::setDefaultMaxInactiveInterval);
setRedisNamespace(redisSessionProperties.getNamespace()); map.from(redisSessionProperties::getNamespace).to(sessionRepository::setRedisKeyNamespace);
setFlushMode(redisSessionProperties.getFlushMode()); map.from(redisSessionProperties::getFlushMode).to(sessionRepository::setFlushMode);
setSaveMode(redisSessionProperties.getSaveMode()); map.from(redisSessionProperties::getSaveMode).to(sessionRepository::setSaveMode);
};
} }
} }
@ -99,23 +103,24 @@ class RedisSessionConfiguration {
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class SpringBootRedisIndexedHttpSessionConfiguration extends RedisIndexedHttpSessionConfiguration { @Import(RedisIndexedHttpSessionConfiguration.class)
static class SpringBootRedisIndexedHttpSessionConfiguration {
private static final String DEFAULT_CLEANUP_CRON = "0 * * * * *"; @Bean
SessionRepositoryCustomizer<RedisIndexedSessionRepository> springBootSessionRepositoryCustomizer(
@Autowired SessionProperties sessionProperties, RedisSessionProperties redisSessionProperties,
void customize(SessionProperties sessionProperties, RedisSessionProperties redisSessionProperties,
ServerProperties serverProperties) { ServerProperties serverProperties) {
Duration timeout = sessionProperties PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
.determineTimeout(() -> serverProperties.getServlet().getSession().getTimeout()); return (sessionRepository) -> {
if (timeout != null) { map.from(sessionProperties
setMaxInactiveIntervalInSeconds((int) timeout.getSeconds()); .determineTimeout(() -> serverProperties.getServlet().getSession().getTimeout()))
} .to((timeout) -> sessionRepository
setRedisNamespace(redisSessionProperties.getNamespace()); .setDefaultMaxInactiveInterval((int) timeout.getSeconds()));
setFlushMode(redisSessionProperties.getFlushMode()); map.from(redisSessionProperties::getNamespace).to(sessionRepository::setRedisKeyNamespace);
setSaveMode(redisSessionProperties.getSaveMode()); map.from(redisSessionProperties::getFlushMode).to(sessionRepository::setFlushMode);
String cleanupCron = redisSessionProperties.getCleanupCron(); map.from(redisSessionProperties::getSaveMode).to(sessionRepository::setSaveMode);
setCleanupCron((cleanupCron != null) ? cleanupCron : DEFAULT_CLEANUP_CRON); map.from(redisSessionProperties::getCleanupCron).to(sessionRepository::setCleanupCron);
};
} }
} }

View File

@ -28,7 +28,6 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; 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.autoconfigure.web.ServerProperties;
import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;
import org.springframework.boot.sql.init.DatabaseInitializationMode; import org.springframework.boot.sql.init.DatabaseInitializationMode;
@ -86,12 +85,10 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration
assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval", assertThat(repository).hasFieldOrPropertyWithValue("defaultMaxInactiveInterval",
(int) new ServerProperties().getServlet().getSession().getTimeout().getSeconds()); (int) new ServerProperties().getServlet().getSession().getTimeout().getSeconds());
assertThat(repository).hasFieldOrPropertyWithValue("tableName", "SPRING_SESSION"); assertThat(repository).hasFieldOrPropertyWithValue("tableName", "SPRING_SESSION");
assertThat(repository).hasFieldOrPropertyWithValue("cleanupCron", "0 * * * * *");
assertThat(context.getBean(JdbcSessionProperties.class).getInitializeSchema()) assertThat(context.getBean(JdbcSessionProperties.class).getInitializeSchema())
.isEqualTo(DatabaseInitializationMode.EMBEDDED); .isEqualTo(DatabaseInitializationMode.EMBEDDED);
assertThat(context.getBean(JdbcOperations.class).queryForList("select * from SPRING_SESSION")).isEmpty(); assertThat(context.getBean(JdbcOperations.class).queryForList("select * from SPRING_SESSION")).isEmpty();
SpringBootJdbcHttpSessionConfiguration configuration = context
.getBean(SpringBootJdbcHttpSessionConfiguration.class);
assertThat(configuration).hasFieldOrPropertyWithValue("cleanupCron", "0 * * * * *");
} }
@Test @Test
@ -142,29 +139,27 @@ class SessionAutoConfigurationJdbcTests extends AbstractSessionAutoConfiguration
void customCleanupCron() { void customCleanupCron() {
this.contextRunner.withPropertyValues("spring.session.jdbc.cleanup-cron=0 0 12 * * *").run((context) -> { this.contextRunner.withPropertyValues("spring.session.jdbc.cleanup-cron=0 0 12 * * *").run((context) -> {
assertThat(context.getBean(JdbcSessionProperties.class).getCleanupCron()).isEqualTo("0 0 12 * * *"); assertThat(context.getBean(JdbcSessionProperties.class).getCleanupCron()).isEqualTo("0 0 12 * * *");
SpringBootJdbcHttpSessionConfiguration configuration = context JdbcIndexedSessionRepository repository = validateSessionRepository(context,
.getBean(SpringBootJdbcHttpSessionConfiguration.class); JdbcIndexedSessionRepository.class);
assertThat(configuration).hasFieldOrPropertyWithValue("cleanupCron", "0 0 12 * * *"); assertThat(repository).hasFieldOrPropertyWithValue("cleanupCron", "0 0 12 * * *");
}); });
} }
@Test @Test
void customFlushMode() { void customFlushMode() {
this.contextRunner.withPropertyValues("spring.session.jdbc.flush-mode=immediate").run((context) -> { this.contextRunner.withPropertyValues("spring.session.jdbc.flush-mode=immediate").run((context) -> {
assertThat(context.getBean(JdbcSessionProperties.class).getFlushMode()).isEqualTo(FlushMode.IMMEDIATE); JdbcIndexedSessionRepository repository = validateSessionRepository(context,
SpringBootJdbcHttpSessionConfiguration configuration = context JdbcIndexedSessionRepository.class);
.getBean(SpringBootJdbcHttpSessionConfiguration.class); assertThat(repository).hasFieldOrPropertyWithValue("flushMode", FlushMode.IMMEDIATE);
assertThat(configuration).hasFieldOrPropertyWithValue("flushMode", FlushMode.IMMEDIATE);
}); });
} }
@Test @Test
void customSaveMode() { void customSaveMode() {
this.contextRunner.withPropertyValues("spring.session.jdbc.save-mode=on-get-attribute").run((context) -> { this.contextRunner.withPropertyValues("spring.session.jdbc.save-mode=on-get-attribute").run((context) -> {
assertThat(context.getBean(JdbcSessionProperties.class).getSaveMode()).isEqualTo(SaveMode.ON_GET_ATTRIBUTE); JdbcIndexedSessionRepository repository = validateSessionRepository(context,
SpringBootJdbcHttpSessionConfiguration configuration = context JdbcIndexedSessionRepository.class);
.getBean(SpringBootJdbcHttpSessionConfiguration.class); assertThat(repository).hasFieldOrPropertyWithValue("saveMode", SaveMode.ON_GET_ATTRIBUTE);
assertThat(configuration).hasFieldOrPropertyWithValue("saveMode", SaveMode.ON_GET_ATTRIBUTE);
}); });
} }

View File

@ -25,7 +25,6 @@ import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.session.RedisSessionConfiguration.IndexedRedisSessionConfiguration.SpringBootRedisIndexedHttpSessionConfiguration;
import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException; import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;
import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.FilteredClassLoader;
@ -191,9 +190,7 @@ class SessionAutoConfigurationRedisTests extends AbstractSessionAutoConfiguratio
assertThat(repository).hasFieldOrPropertyWithValue("namespace", keyNamespace); assertThat(repository).hasFieldOrPropertyWithValue("namespace", keyNamespace);
assertThat(repository).hasFieldOrPropertyWithValue("flushMode", flushMode); assertThat(repository).hasFieldOrPropertyWithValue("flushMode", flushMode);
assertThat(repository).hasFieldOrPropertyWithValue("saveMode", saveMode); assertThat(repository).hasFieldOrPropertyWithValue("saveMode", saveMode);
SpringBootRedisIndexedHttpSessionConfiguration configuration = context assertThat(repository).hasFieldOrPropertyWithValue("cleanupCron", cleanupCron);
.getBean(SpringBootRedisIndexedHttpSessionConfiguration.class);
assertThat(configuration).hasFieldOrPropertyWithValue("cleanupCron", cleanupCron);
}; };
} }