From 5deca28a9d61edc36f33addce0185251f5389674 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 13 May 2016 11:19:02 +0200 Subject: [PATCH] Improve upgrade path for Spring Session Commit b7e7bcf made `spring.session.store-type` explicit which means that users of Spring Session in 1.3 have to set that property to restore the auto-configuration support in 1.4. This commit implicitly set the store type to redis if redis is present and log a warning inviting the user to actually specify that in configuration. The entry in the auto-configuration report also mentions that such arrangement is deprecated. Closes gh-5838 --- .../session/RedisSessionConfiguration.java | 22 +++++++++++++++++-- .../session/SessionCondition.java | 15 ++++++++++--- .../session/SessionStoreMappings.java | 4 ++-- .../SessionAutoConfigurationRedisTests.java | 18 +++++++++++++++ 4 files changed, 52 insertions(+), 7 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/RedisSessionConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/RedisSessionConfiguration.java index d1f59f902a1..786a6f46e28 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/RedisSessionConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/RedisSessionConfiguration.java @@ -16,6 +16,11 @@ package org.springframework.boot.autoconfigure.session; +import javax.annotation.PostConstruct; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -40,21 +45,34 @@ import org.springframework.session.data.redis.config.annotation.web.http.RedisHt @Conditional(SessionCondition.class) class RedisSessionConfiguration { + private static final Logger logger = LoggerFactory.getLogger(RedisSessionConfiguration.class); + @Configuration public static class SpringBootRedisHttpSessionConfiguration extends RedisHttpSessionConfiguration { + private SessionProperties sessionProperties; + @Autowired public void customize(SessionProperties sessionProperties) { - Integer timeout = sessionProperties.getTimeout(); + this.sessionProperties = sessionProperties; + Integer timeout = this.sessionProperties.getTimeout(); if (timeout != null) { setMaxInactiveIntervalInSeconds(timeout); } - SessionProperties.Redis redis = sessionProperties.getRedis(); + SessionProperties.Redis redis = this.sessionProperties.getRedis(); setRedisNamespace(redis.getNamespace()); setRedisFlushMode(redis.getFlushMode()); } + @PostConstruct + public void validate() { + if (this.sessionProperties.getStoreType() == null) { + logger.warn("Spring Session store type is mandatory: set " + + "'spring.session.store-type=redis' in your configuration"); + } + } + } } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionCondition.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionCondition.java index 13b6f9db5f3..b3f420dbda1 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionCondition.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionCondition.java @@ -22,6 +22,7 @@ import org.springframework.boot.bind.RelaxedPropertyResolver; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.core.type.AnnotationMetadata; +import org.springframework.util.ClassUtils; /** * General condition used with all session configuration classes. @@ -30,16 +31,24 @@ import org.springframework.core.type.AnnotationMetadata; */ class SessionCondition extends SpringBootCondition { + private static final boolean redisPresent = ClassUtils.isPresent( + "org.springframework.data.redis.core.RedisTemplate", SessionCondition.class.getClassLoader()); + @Override public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { RelaxedPropertyResolver resolver = new RelaxedPropertyResolver( context.getEnvironment(), "spring.session."); - if (!resolver.containsProperty("store-type")) { - return ConditionOutcome.noMatch("Session store type not set"); - } StoreType sessionStoreType = SessionStoreMappings .getType(((AnnotationMetadata) metadata).getClassName()); + if (!resolver.containsProperty("store-type")) { + if (sessionStoreType == StoreType.REDIS && redisPresent) { + return ConditionOutcome.match("Session store type default to redis (deprecated)"); + } + else { + return ConditionOutcome.noMatch("Session store type not set"); + } + } String value = resolver.getProperty("store-type").replace("-", "_").toUpperCase(); if (value.equals(sessionStoreType.name())) { return ConditionOutcome.match("Session store type " + sessionStoreType); diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionStoreMappings.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionStoreMappings.java index 81ce310bbfb..b2fa12b417d 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionStoreMappings.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionStoreMappings.java @@ -34,9 +34,9 @@ final class SessionStoreMappings { static { Map> mappings = new HashMap>(); - mappings.put(StoreType.JDBC, JdbcSessionConfiguration.class); - mappings.put(StoreType.MONGO, MongoSessionConfiguration.class); mappings.put(StoreType.REDIS, RedisSessionConfiguration.class); + mappings.put(StoreType.MONGO, MongoSessionConfiguration.class); + mappings.put(StoreType.JDBC, JdbcSessionConfiguration.class); mappings.put(StoreType.HAZELCAST, HazelcastSessionConfiguration.class); mappings.put(StoreType.HASH_MAP, HashMapSessionConfiguration.class); mappings.put(StoreType.NONE, NoOpSessionConfiguration.class); diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationRedisTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationRedisTests.java index 6b6ede83f1e..29c1389f59f 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationRedisTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationRedisTests.java @@ -24,10 +24,13 @@ import org.junit.Test; import org.springframework.beans.DirectFieldAccessor; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.boot.redis.RedisTestServer; +import org.springframework.boot.test.rule.OutputCapture; import org.springframework.session.data.redis.RedisFlushMode; import org.springframework.session.data.redis.RedisOperationsSessionRepository; import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.Matchers.containsString; /** * Redis specific tests for {@link SessionAutoConfiguration}. @@ -37,13 +40,28 @@ import static org.assertj.core.api.Assertions.assertThat; public class SessionAutoConfigurationRedisTests extends AbstractSessionAutoConfigurationTests { + @Rule + public OutputCapture output = new OutputCapture(); + @Rule public final RedisTestServer redis = new RedisTestServer(); + @Test + public void redisSessionStoreIsTheDefault() { + load(Collections.>singletonList(RedisAutoConfiguration.class)); + validateSpringSessionUsesRedis(); + this.output.expect(containsString("Spring Session store type is mandatory: set 'spring.session.store-type=redis' in your configuration")); + } + @Test public void redisSessionStore() { load(Collections.>singletonList(RedisAutoConfiguration.class), "spring.session.store-type=redis"); + validateSpringSessionUsesRedis(); + this.output.expect(not(containsString("Spring Session store type is mandatory: set 'spring.session.store-type=redis' in your configuration"))); + } + + private void validateSpringSessionUsesRedis() { RedisOperationsSessionRepository repository = validateSessionRepository( RedisOperationsSessionRepository.class); assertThat(repository.getSessionCreatedChannelPrefix())