Commit 1213654c authored by Phillip Webb's avatar Phillip Webb

Merge pull request #17022 from nosan

* pr/17022:
  Polish "Add session property for ConfigureRedisAction"
  Add session property for ConfigureRedisAction

Closes gh-17022
parents 2888ddee 919913ae
...@@ -23,12 +23,15 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; ...@@ -23,12 +23,15 @@ 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.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
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.data.redis.RedisOperationsSessionRepository; 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.web.http.RedisHttpSessionConfiguration; import org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration;
/** /**
...@@ -48,6 +51,19 @@ import org.springframework.session.data.redis.config.annotation.web.http.RedisHt ...@@ -48,6 +51,19 @@ import org.springframework.session.data.redis.config.annotation.web.http.RedisHt
@EnableConfigurationProperties(RedisSessionProperties.class) @EnableConfigurationProperties(RedisSessionProperties.class)
class RedisSessionConfiguration { class RedisSessionConfiguration {
@Bean
@ConditionalOnMissingBean
public ConfigureRedisAction configureRedisAction(RedisSessionProperties redisSessionProperties) {
switch (redisSessionProperties.getConfigurationStrategy()) {
case NOTIFY_KEYSPACE_EVENTS:
return new ConfigureNotifyKeyspaceEventsAction();
case NONE:
return ConfigureRedisAction.NO_OP;
}
throw new IllegalStateException("Unsupported redis configuration strategy '"
+ redisSessionProperties.getConfigurationStrategy() + "'.");
}
@Configuration @Configuration
public static class SpringBootRedisHttpSessionConfiguration extends RedisHttpSessionConfiguration { public static class SpringBootRedisHttpSessionConfiguration extends RedisHttpSessionConfiguration {
......
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -40,6 +40,12 @@ public class RedisSessionProperties { ...@@ -40,6 +40,12 @@ public class RedisSessionProperties {
*/ */
private RedisFlushMode flushMode = RedisFlushMode.ON_SAVE; private RedisFlushMode flushMode = RedisFlushMode.ON_SAVE;
/**
* The configure action to apply when no user defined ConfigureRedisAction bean is
* present.
*/
private ConfigureAction configureAction = ConfigureAction.NOTIFY_KEYSPACE_EVENTS;
/** /**
* Cron expression for expired session cleanup job. * Cron expression for expired session cleanup job.
*/ */
...@@ -69,4 +75,30 @@ public class RedisSessionProperties { ...@@ -69,4 +75,30 @@ public class RedisSessionProperties {
this.cleanupCron = cleanupCron; this.cleanupCron = cleanupCron;
} }
public ConfigureAction getConfigurationStrategy() {
return this.configureAction;
}
public void setConfigurationStrategy(ConfigureAction configurationStrategy) {
this.configureAction = configurationStrategy;
}
/**
* Strategies for configuring and validating Redis.
*/
public enum ConfigureAction {
/**
* Ensure that Redis Keyspace events for Generic commands and Expired events are
* enabled.
*/
NOTIFY_KEYSPACE_EVENTS,
/**
* No not attempt to apply any custom Redis configuration.
*/
NONE
}
} }
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
package org.springframework.boot.autoconfigure.session; package org.springframework.boot.autoconfigure.session;
import java.util.Map;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
...@@ -28,13 +30,18 @@ import org.springframework.boot.test.context.runner.ContextConsumer; ...@@ -28,13 +30,18 @@ import org.springframework.boot.test.context.runner.ContextConsumer;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.testsupport.testcontainers.DisabledWithoutDockerTestcontainers; import org.springframework.boot.testsupport.testcontainers.DisabledWithoutDockerTestcontainers;
import org.springframework.boot.testsupport.testcontainers.RedisContainer; import org.springframework.boot.testsupport.testcontainers.RedisContainer;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.session.data.mongo.MongoOperationsSessionRepository; import org.springframework.session.data.mongo.MongoOperationsSessionRepository;
import org.springframework.session.data.redis.RedisFlushMode; import org.springframework.session.data.redis.RedisFlushMode;
import org.springframework.session.data.redis.RedisOperationsSessionRepository; 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.hazelcast.HazelcastSessionRepository; import org.springframework.session.hazelcast.HazelcastSessionRepository;
import org.springframework.session.jdbc.JdbcOperationsSessionRepository; import org.springframework.session.jdbc.JdbcOperationsSessionRepository;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
/** /**
* Redis specific tests for {@link SessionAutoConfiguration}. * Redis specific tests for {@link SessionAutoConfiguration}.
...@@ -81,6 +88,33 @@ class SessionAutoConfigurationRedisTests extends AbstractSessionAutoConfiguratio ...@@ -81,6 +88,33 @@ class SessionAutoConfigurationRedisTests extends AbstractSessionAutoConfiguratio
.run(validateSpringSessionUsesRedis("foo:event:0:created:", RedisFlushMode.IMMEDIATE, "0 0 12 * * *")); .run(validateSpringSessionUsesRedis("foo:event:0:created:", RedisFlushMode.IMMEDIATE, "0 0 12 * * *"));
} }
@Test
void redisSessionConfigureNoStrategy() {
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
.withPropertyValues("spring.session.store-type=redis", "spring.session.redis.configure-action=none",
"spring.redis.port=" + redis.getFirstMappedPort())
.run(validateStrategy(ConfigureRedisAction.NO_OP.getClass()));
}
@Test
void redisSessionConfigureDefaultStrategy() {
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
.withPropertyValues("spring.session.store-type=redis",
"spring.redis.port=" + redis.getFirstMappedPort())
.run(validateStrategy(ConfigureNotifyKeyspaceEventsAction.class,
entry("notify-keyspace-events", "gxE")));
}
@Test
void redisSessionConfigureCustomStrategy() {
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
.withUserConfiguration(MaxEntriesRedisAction.class)
.withPropertyValues("spring.session.store-type=redis",
"spring.redis.port=" + redis.getFirstMappedPort())
.run(validateStrategy(MaxEntriesRedisAction.class, entry("set-max-intset-entries", "1024")));
}
private ContextConsumer<AssertableWebApplicationContext> validateSpringSessionUsesRedis( private ContextConsumer<AssertableWebApplicationContext> validateSpringSessionUsesRedis(
String sessionCreatedChannelPrefix, RedisFlushMode flushMode, String cleanupCron) { String sessionCreatedChannelPrefix, RedisFlushMode flushMode, String cleanupCron) {
return (context) -> { return (context) -> {
...@@ -94,4 +128,26 @@ class SessionAutoConfigurationRedisTests extends AbstractSessionAutoConfiguratio ...@@ -94,4 +128,26 @@ class SessionAutoConfigurationRedisTests extends AbstractSessionAutoConfiguratio
}; };
} }
private ContextConsumer<AssertableWebApplicationContext> validateStrategy(
Class<? extends ConfigureRedisAction> expectedConfigureRedisActionType, Map.Entry<?, ?>... expectedConfig) {
return (context) -> {
assertThat(context).hasSingleBean(ConfigureRedisAction.class);
assertThat(context).hasSingleBean(RedisConnectionFactory.class);
assertThat(context.getBean(ConfigureRedisAction.class)).isInstanceOf(expectedConfigureRedisActionType);
RedisConnection connection = context.getBean(RedisConnectionFactory.class).getConnection();
if (expectedConfig.length > 0) {
assertThat(connection.getConfig("*")).contains(expectedConfig);
}
};
}
static class MaxEntriesRedisAction implements ConfigureRedisAction {
@Override
public void configure(RedisConnection connection) {
connection.setConfig("set-max-intset-entries", "1024");
}
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment