Harmonize Redis configurations

This commit improves reactive Redis configuration by adding support for connection factory qualifier and Redis operations resolver annotations.
This commit is contained in:
Vedran Pavic
2017-10-27 10:49:01 +02:00
parent f8583bb02f
commit fe3f40c6f4
10 changed files with 195 additions and 45 deletions

View File

@@ -37,8 +37,8 @@ import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.Session;
import org.springframework.session.data.SessionEventRegistry;
import org.springframework.session.data.redis.RedisOperationsSessionRepository.RedisSession;
import org.springframework.session.data.redis.config.annotation.SpringSessionRedisOperations;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.data.redis.config.annotation.web.http.SpringSessionRedisOperations;
import org.springframework.session.events.SessionCreatedEvent;
import org.springframework.session.events.SessionDestroyedEvent;
import org.springframework.test.context.ContextConfiguration;

View File

@@ -31,8 +31,8 @@ import org.springframework.core.task.TaskExecutor;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.session.data.redis.AbstractRedisITests;
import org.springframework.session.data.redis.config.annotation.SpringSessionRedisOperations;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.data.redis.config.annotation.web.http.SpringSessionRedisOperations;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.session.data.redis.config.annotation.web.http;
package org.springframework.session.data.redis.config.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.session.data.redis.config.annotation.web.http;
package org.springframework.session.data.redis.config.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;

View File

@@ -48,6 +48,7 @@ import org.springframework.session.data.redis.RedisFlushMode;
import org.springframework.session.data.redis.RedisOperationsSessionRepository;
import org.springframework.session.data.redis.config.ConfigureNotifyKeyspaceEventsAction;
import org.springframework.session.data.redis.config.ConfigureRedisAction;
import org.springframework.session.data.redis.config.annotation.SpringSessionRedisConnectionFactory;
import org.springframework.session.web.http.SessionRepositoryFilter;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

View File

@@ -18,6 +18,8 @@ package org.springframework.session.data.redis.config.annotation.web.server;
import java.util.Map;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -33,6 +35,7 @@ import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.session.config.annotation.web.server.SpringWebSessionConfiguration;
import org.springframework.session.data.redis.ReactiveRedisOperationsSessionRepository;
import org.springframework.session.data.redis.RedisFlushMode;
import org.springframework.session.data.redis.config.annotation.SpringSessionRedisConnectionFactory;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.util.StringValueResolver;
@@ -61,20 +64,19 @@ public class RedisWebSessionConfiguration extends SpringWebSessionConfiguration
private RedisFlushMode redisFlushMode = RedisFlushMode.ON_SAVE;
private ReactiveRedisConnectionFactory redisConnectionFactory;
private StringValueResolver embeddedValueResolver;
@Bean
public ReactiveRedisOperationsSessionRepository sessionRepository(
ReactiveRedisConnectionFactory redisConnectionFactory) {
public ReactiveRedisOperationsSessionRepository sessionRepository() {
ReactiveRedisOperationsSessionRepository sessionRepository = new ReactiveRedisOperationsSessionRepository(
createDefaultTemplate(redisConnectionFactory));
createDefaultTemplate(this.redisConnectionFactory));
sessionRepository
.setDefaultMaxInactiveInterval(this.maxInactiveIntervalInSeconds);
String redisNamespace = getRedisNamespace();
if (StringUtils.hasText(redisNamespace)) {
sessionRepository.setRedisKeyNamespace(redisNamespace);
if (StringUtils.hasText(this.redisNamespace)) {
sessionRepository.setRedisKeyNamespace(this.redisNamespace);
}
sessionRepository.setRedisFlushMode(this.redisFlushMode);
@@ -95,6 +97,18 @@ public class RedisWebSessionConfiguration extends SpringWebSessionConfiguration
this.redisFlushMode = redisFlushMode;
}
@Autowired
public void setRedisConnectionFactory(
@SpringSessionRedisConnectionFactory ObjectProvider<ReactiveRedisConnectionFactory> springSessionRedisConnectionFactory,
ObjectProvider<ReactiveRedisConnectionFactory> redisConnectionFactory) {
ReactiveRedisConnectionFactory redisConnectionFactoryToUse = springSessionRedisConnectionFactory
.getIfAvailable();
if (redisConnectionFactoryToUse == null) {
redisConnectionFactoryToUse = redisConnectionFactory.getObject();
}
this.redisConnectionFactory = redisConnectionFactoryToUse;
}
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.embeddedValueResolver = resolver;
@@ -127,12 +141,4 @@ public class RedisWebSessionConfiguration extends SpringWebSessionConfiguration
return new ReactiveRedisTemplate<>(connectionFactory, serializationContext);
}
private String getRedisNamespace() {
if (StringUtils.hasText(this.redisNamespace)) {
return this.redisNamespace;
}
return System.getProperty("spring.session.redis.namespace", "");
}
}

View File

@@ -28,6 +28,7 @@ import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.session.data.redis.config.annotation.SpringSessionRedisOperations;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

View File

@@ -35,6 +35,7 @@ import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.mock.env.MockEnvironment;
import org.springframework.session.data.redis.RedisOperationsSessionRepository;
import org.springframework.session.data.redis.config.annotation.SpringSessionRedisConnectionFactory;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -18,14 +18,20 @@ package org.springframework.session.data.redis.config.annotation.web.server;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
import org.springframework.data.redis.core.ReactiveRedisOperations;
import org.springframework.session.data.redis.ReactiveRedisOperationsSessionRepository;
import org.springframework.session.data.redis.RedisFlushMode;
import org.springframework.session.data.redis.config.annotation.SpringSessionRedisConnectionFactory;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
@@ -42,6 +48,9 @@ public class RedisWebSessionConfigurationTests {
private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 600;
@Rule
public final ExpectedException thrown = ExpectedException.none();
private AnnotationConfigApplicationContext context;
@Before
@@ -58,7 +67,7 @@ public class RedisWebSessionConfigurationTests {
@Test
public void defaultConfiguration() {
registerAndRefresh(RedisConfiguration.class, DefaultConfiguration.class);
registerAndRefresh(RedisConfig.class, DefaultConfig.class);
ReactiveRedisOperationsSessionRepository repository = this.context
.getBean(ReactiveRedisOperationsSessionRepository.class);
@@ -67,7 +76,7 @@ public class RedisWebSessionConfigurationTests {
@Test
public void customNamespace() {
registerAndRefresh(RedisConfiguration.class, CustomNamespaceConfiguration.class);
registerAndRefresh(RedisConfig.class, CustomNamespaceConfig.class);
ReactiveRedisOperationsSessionRepository repository = this.context
.getBean(ReactiveRedisOperationsSessionRepository.class);
@@ -78,8 +87,7 @@ public class RedisWebSessionConfigurationTests {
@Test
public void customMaxInactiveInterval() {
registerAndRefresh(RedisConfiguration.class,
CustomMaxInactiveIntervalConfiguration.class);
registerAndRefresh(RedisConfig.class, CustomMaxInactiveIntervalConfig.class);
ReactiveRedisOperationsSessionRepository repository = this.context
.getBean(ReactiveRedisOperationsSessionRepository.class);
@@ -90,7 +98,7 @@ public class RedisWebSessionConfigurationTests {
@Test
public void customFlushMode() {
registerAndRefresh(RedisConfiguration.class, CustomFlushModeConfiguration.class);
registerAndRefresh(RedisConfig.class, CustomFlushModeConfig.class);
ReactiveRedisOperationsSessionRepository repository = this.context
.getBean(ReactiveRedisOperationsSessionRepository.class);
@@ -99,13 +107,160 @@ public class RedisWebSessionConfigurationTests {
.isEqualTo(RedisFlushMode.IMMEDIATE);
}
@Test
public void qualifiedConnectionFactoryRedisConfig() {
registerAndRefresh(RedisConfig.class,
QualifiedConnectionFactoryRedisConfig.class);
ReactiveRedisOperationsSessionRepository repository = this.context
.getBean(ReactiveRedisOperationsSessionRepository.class);
ReactiveRedisConnectionFactory redisConnectionFactory = this.context.getBean(
"qualifiedRedisConnectionFactory", ReactiveRedisConnectionFactory.class);
assertThat(repository).isNotNull();
assertThat(redisConnectionFactory).isNotNull();
ReactiveRedisOperations redisOperations = (ReactiveRedisOperations) ReflectionTestUtils
.getField(repository, "sessionRedisOperations");
assertThat(redisOperations).isNotNull();
assertThat(ReflectionTestUtils.getField(redisOperations, "connectionFactory"))
.isEqualTo(redisConnectionFactory);
}
@Test
public void primaryConnectionFactoryRedisConfig() {
registerAndRefresh(RedisConfig.class, PrimaryConnectionFactoryRedisConfig.class);
ReactiveRedisOperationsSessionRepository repository = this.context
.getBean(ReactiveRedisOperationsSessionRepository.class);
ReactiveRedisConnectionFactory redisConnectionFactory = this.context.getBean(
"primaryRedisConnectionFactory", ReactiveRedisConnectionFactory.class);
assertThat(repository).isNotNull();
assertThat(redisConnectionFactory).isNotNull();
ReactiveRedisOperations redisOperations = (ReactiveRedisOperations) ReflectionTestUtils
.getField(repository, "sessionRedisOperations");
assertThat(redisOperations).isNotNull();
assertThat(ReflectionTestUtils.getField(redisOperations, "connectionFactory"))
.isEqualTo(redisConnectionFactory);
}
@Test
public void qualifiedAndPrimaryConnectionFactoryRedisConfig() {
registerAndRefresh(RedisConfig.class,
QualifiedAndPrimaryConnectionFactoryRedisConfig.class);
ReactiveRedisOperationsSessionRepository repository = this.context
.getBean(ReactiveRedisOperationsSessionRepository.class);
ReactiveRedisConnectionFactory redisConnectionFactory = this.context.getBean(
"qualifiedRedisConnectionFactory", ReactiveRedisConnectionFactory.class);
assertThat(repository).isNotNull();
assertThat(redisConnectionFactory).isNotNull();
ReactiveRedisOperations redisOperations = (ReactiveRedisOperations) ReflectionTestUtils
.getField(repository, "sessionRedisOperations");
assertThat(redisOperations).isNotNull();
assertThat(ReflectionTestUtils.getField(redisOperations, "connectionFactory"))
.isEqualTo(redisConnectionFactory);
}
@Test
public void namedConnectionFactoryRedisConfig() {
registerAndRefresh(RedisConfig.class, NamedConnectionFactoryRedisConfig.class);
ReactiveRedisOperationsSessionRepository repository = this.context
.getBean(ReactiveRedisOperationsSessionRepository.class);
ReactiveRedisConnectionFactory redisConnectionFactory = this.context
.getBean("redisConnectionFactory", ReactiveRedisConnectionFactory.class);
assertThat(repository).isNotNull();
assertThat(redisConnectionFactory).isNotNull();
ReactiveRedisOperations redisOperations = (ReactiveRedisOperations) ReflectionTestUtils
.getField(repository, "sessionRedisOperations");
assertThat(redisOperations).isNotNull();
assertThat(ReflectionTestUtils.getField(redisOperations, "connectionFactory"))
.isEqualTo(redisConnectionFactory);
}
@Test
public void multipleConnectionFactoryRedisConfig() {
this.thrown.expect(BeanCreationException.class);
this.thrown.expectMessage("expected single matching bean but found 2");
registerAndRefresh(RedisConfig.class, MultipleConnectionFactoryRedisConfig.class);
}
private void registerAndRefresh(Class<?>... annotatedClasses) {
this.context.register(annotatedClasses);
this.context.refresh();
}
@Configuration
static class RedisConfiguration {
static class RedisConfig {
@Bean
public ReactiveRedisConnectionFactory defaultRedisConnectionFactory() {
return mock(ReactiveRedisConnectionFactory.class);
}
}
@EnableRedisWebSession
static class DefaultConfig {
}
@EnableRedisWebSession(redisNamespace = REDIS_NAMESPACE)
static class CustomNamespaceConfig {
}
@EnableRedisWebSession(maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
static class CustomMaxInactiveIntervalConfig {
}
@EnableRedisWebSession(redisFlushMode = RedisFlushMode.IMMEDIATE)
static class CustomFlushModeConfig {
}
@EnableRedisWebSession
static class QualifiedConnectionFactoryRedisConfig {
@Bean
@SpringSessionRedisConnectionFactory
public ReactiveRedisConnectionFactory qualifiedRedisConnectionFactory() {
return mock(ReactiveRedisConnectionFactory.class);
}
}
@EnableRedisWebSession
static class PrimaryConnectionFactoryRedisConfig {
@Bean
@Primary
public ReactiveRedisConnectionFactory primaryRedisConnectionFactory() {
return mock(ReactiveRedisConnectionFactory.class);
}
}
@EnableRedisWebSession
static class QualifiedAndPrimaryConnectionFactoryRedisConfig {
@Bean
@SpringSessionRedisConnectionFactory
public ReactiveRedisConnectionFactory qualifiedRedisConnectionFactory() {
return mock(ReactiveRedisConnectionFactory.class);
}
@Bean
@Primary
public ReactiveRedisConnectionFactory primaryRedisConnectionFactory() {
return mock(ReactiveRedisConnectionFactory.class);
}
}
@EnableRedisWebSession
static class NamedConnectionFactoryRedisConfig {
@Bean
public ReactiveRedisConnectionFactory redisConnectionFactory() {
@@ -114,27 +269,13 @@ public class RedisWebSessionConfigurationTests {
}
@Configuration
@EnableRedisWebSession
static class DefaultConfiguration {
static class MultipleConnectionFactoryRedisConfig {
}
@Configuration
@EnableRedisWebSession(redisNamespace = REDIS_NAMESPACE)
static class CustomNamespaceConfiguration {
}
@Configuration
@EnableRedisWebSession(maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
static class CustomMaxInactiveIntervalConfiguration {
}
@Configuration
@EnableRedisWebSession(redisFlushMode = RedisFlushMode.IMMEDIATE)
static class CustomFlushModeConfiguration {
@Bean
public ReactiveRedisConnectionFactory secondaryRedisConnectionFactory() {
return mock(ReactiveRedisConnectionFactory.class);
}
}