DATAREDIS-491 - Add configuration option to tune KeyspaceEventMessageListener usage.
We now allow more fine grained setup for usage of Redis keyspace events. This can be done programmatically via the RedisKeyValueAdapter or using `@EnableRedisRepositories.enableKeyspaceEvents`. Original pull request: #193.
This commit is contained in:
committed by
Mark Paluch
parent
f0a611ac62
commit
669b83c388
@@ -21,12 +21,16 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.ConverterNotFoundException;
|
||||
@@ -50,13 +54,14 @@ import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||
import org.springframework.data.redis.util.ByteUtils;
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Redis specific {@link KeyValueAdapter} implementation. Uses binary codec to read/write data from/to Redis. Objects
|
||||
* are stored in a Redis Hash using the value of {@link RedisHash}, the {@link KeyspaceConfiguration} or just
|
||||
* {@link Class#getName()} as a prefix. <br />
|
||||
* <strong>Example</strong>
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* @RedisHash("persons")
|
||||
@@ -64,8 +69,8 @@ import org.springframework.util.Assert;
|
||||
* @Id String id;
|
||||
* String name;
|
||||
* }
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* prefix ID
|
||||
* | |
|
||||
* V V
|
||||
@@ -76,29 +81,33 @@ import org.springframework.util.Assert;
|
||||
* 4) Rand al'Thor
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* <br />
|
||||
* The {@link KeyValueAdapter} is <strong>not</strong> intended to store simple types such as {@link String} values.
|
||||
* Please use {@link RedisTemplate} for this purpose.
|
||||
*
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @since 1.7
|
||||
*/
|
||||
public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
|
||||
implements ApplicationContextAware, ApplicationListener<RedisKeyspaceEvent> {
|
||||
implements InitializingBean, ApplicationContextAware, ApplicationListener<RedisKeyspaceEvent> {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RedisKeyValueAdapter.class);
|
||||
|
||||
private RedisOperations<?, ?> redisOps;
|
||||
private RedisConverter converter;
|
||||
private RedisMessageListenerContainer messageListenerContainer;
|
||||
private KeyExpirationEventMessageListener expirationListener;
|
||||
private AtomicReference<KeyExpirationEventMessageListener> expirationListener = new AtomicReference<KeyExpirationEventMessageListener>(
|
||||
null);
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
private EnableKeyspaceEvents enableKeyspaceEvents = EnableKeyspaceEvents.ON_STARTUP;
|
||||
|
||||
/**
|
||||
* Creates new {@link RedisKeyValueAdapter} with default {@link RedisMappingContext} and default
|
||||
* {@link CustomConversions}.
|
||||
*
|
||||
*
|
||||
* @param redisOps must not be {@literal null}.
|
||||
*/
|
||||
public RedisKeyValueAdapter(RedisOperations<?, ?> redisOps) {
|
||||
@@ -107,7 +116,7 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
|
||||
|
||||
/**
|
||||
* Creates new {@link RedisKeyValueAdapter} with default {@link CustomConversions}.
|
||||
*
|
||||
*
|
||||
* @param redisOps must not be {@literal null}.
|
||||
* @param mappingContext must not be {@literal null}.
|
||||
*/
|
||||
@@ -117,7 +126,7 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
|
||||
|
||||
/**
|
||||
* Creates new {@link RedisKeyValueAdapter}.
|
||||
*
|
||||
*
|
||||
* @param redisOps must not be {@literal null}.
|
||||
* @param mappingContext must not be {@literal null}.
|
||||
* @param customConversions can be {@literal null}.
|
||||
@@ -138,12 +147,12 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
|
||||
converter = mappingConverter;
|
||||
this.redisOps = redisOps;
|
||||
|
||||
initKeyExpirationListener();
|
||||
intiMessageListenerContainer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link RedisKeyValueAdapter} with specific {@link RedisConverter}.
|
||||
*
|
||||
*
|
||||
* @param redisOps must not be {@literal null}.
|
||||
* @param mappingContext must not be {@literal null}.
|
||||
*/
|
||||
@@ -156,7 +165,7 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
|
||||
converter = redisConverter;
|
||||
this.redisOps = redisOps;
|
||||
|
||||
initKeyExpirationListener();
|
||||
intiMessageListenerContainer();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,6 +184,14 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
|
||||
converter.write(item, rdo);
|
||||
}
|
||||
|
||||
if (ObjectUtils.nullSafeEquals(EnableKeyspaceEvents.ON_DEMAND, enableKeyspaceEvents)
|
||||
&& this.expirationListener.get() == null) {
|
||||
|
||||
if (rdo.getTimeToLive() != null && rdo.getTimeToLive().longValue() > 0) {
|
||||
initKeyExpirationListener();
|
||||
}
|
||||
}
|
||||
|
||||
if (rdo.getId() == null) {
|
||||
|
||||
rdo.setId(converter.getConversionService().convert(id, String.class));
|
||||
@@ -397,7 +414,7 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
|
||||
|
||||
/**
|
||||
* Execute {@link RedisCallback} via underlying {@link RedisOperations}.
|
||||
*
|
||||
*
|
||||
* @param callback must not be {@literal null}.
|
||||
* @see RedisOperations#execute(RedisCallback)
|
||||
* @return
|
||||
@@ -408,7 +425,7 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
|
||||
|
||||
/**
|
||||
* Get the {@link RedisConverter} in use.
|
||||
*
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
public RedisConverter getConverter() {
|
||||
@@ -430,7 +447,7 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
|
||||
|
||||
/**
|
||||
* Convert given source to binary representation using the underlying {@link ConversionService}.
|
||||
*
|
||||
*
|
||||
* @param source
|
||||
* @return
|
||||
* @throws ConverterNotFoundException
|
||||
@@ -444,13 +461,38 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
|
||||
return converter.getConversionService().convert(source, byte[].class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure usage of {@link KeyExpirationEventMessageListener}.
|
||||
*
|
||||
* @param enableKeyspaceEvents
|
||||
* @since 1.8
|
||||
*/
|
||||
public void setEnableKeyspaceEvents(EnableKeyspaceEvents enableKeyspaceEvents) {
|
||||
this.enableKeyspaceEvents = enableKeyspaceEvents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
* @since 1.8
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
|
||||
if (ObjectUtils.nullSafeEquals(EnableKeyspaceEvents.ON_STARTUP, this.enableKeyspaceEvents)) {
|
||||
initKeyExpirationListener();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.DisposableBean#destroy()
|
||||
*/
|
||||
public void destroy() throws Exception {
|
||||
|
||||
this.expirationListener.destroy();
|
||||
if (this.expirationListener.get() != null) {
|
||||
this.expirationListener.get().destroy();
|
||||
}
|
||||
|
||||
this.messageListenerContainer.destroy();
|
||||
}
|
||||
|
||||
@@ -490,26 +532,39 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
|
||||
*/
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.expirationListener.setApplicationEventPublisher(applicationContext);
|
||||
this.eventPublisher = applicationContext;
|
||||
}
|
||||
|
||||
private void initKeyExpirationListener() {
|
||||
private void intiMessageListenerContainer() {
|
||||
|
||||
this.messageListenerContainer = new RedisMessageListenerContainer();
|
||||
messageListenerContainer.setConnectionFactory(((RedisTemplate<?, ?>) redisOps).getConnectionFactory());
|
||||
messageListenerContainer.afterPropertiesSet();
|
||||
messageListenerContainer.start();
|
||||
}
|
||||
|
||||
this.expirationListener = new MappingExpirationListener(this.messageListenerContainer, this.redisOps,
|
||||
this.converter);
|
||||
this.expirationListener.init();
|
||||
private void initKeyExpirationListener() {
|
||||
|
||||
if (this.expirationListener.get() == null) {
|
||||
|
||||
MappingExpirationListener listener = new MappingExpirationListener(this.messageListenerContainer, this.redisOps,
|
||||
this.converter);
|
||||
|
||||
if (this.eventPublisher != null) {
|
||||
listener.setApplicationEventPublisher(this.eventPublisher);
|
||||
}
|
||||
|
||||
if (this.expirationListener.compareAndSet(null, listener)) {
|
||||
listener.init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link MessageListener} implementation used to capture Redis keypspace notifications. Tries to read a previously
|
||||
* created phantom key {@code keyspace:id:phantom} to provide the expired object as part of the published
|
||||
* {@link RedisKeyExpiredEvent}.
|
||||
*
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
@@ -520,7 +575,7 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
|
||||
|
||||
/**
|
||||
* Creates new {@link MappingExpirationListener}.
|
||||
*
|
||||
*
|
||||
* @param listenerContainer
|
||||
* @param ops
|
||||
* @param converter
|
||||
@@ -582,4 +637,26 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.8
|
||||
*/
|
||||
public static enum EnableKeyspaceEvents {
|
||||
|
||||
/**
|
||||
* Initializes the {@link KeyExpirationEventMessageListener} on startup.
|
||||
*/
|
||||
ON_STARTUP,
|
||||
|
||||
/**
|
||||
* Initializes the {@link KeyExpirationEventMessageListener} on first insert having expiration time set.
|
||||
*/
|
||||
ON_DEMAND,
|
||||
|
||||
/**
|
||||
* Turn {@link KeyExpirationEventMessageListener} usage off. No expiration events will be received.
|
||||
*/
|
||||
OFF
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2016 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.
|
||||
@@ -27,9 +27,11 @@ import org.springframework.context.annotation.ComponentScan.Filter;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.keyvalue.core.KeyValueOperations;
|
||||
import org.springframework.data.keyvalue.repository.config.QueryCreatorType;
|
||||
import org.springframework.data.redis.core.RedisKeyValueAdapter.EnableKeyspaceEvents;
|
||||
import org.springframework.data.redis.core.RedisOperations;
|
||||
import org.springframework.data.redis.core.convert.KeyspaceConfiguration;
|
||||
import org.springframework.data.redis.core.index.IndexConfiguration;
|
||||
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
|
||||
import org.springframework.data.redis.repository.query.RedisQueryCreator;
|
||||
import org.springframework.data.redis.repository.support.RedisRepositoryFactoryBean;
|
||||
import org.springframework.data.repository.config.DefaultRepositoryBaseClass;
|
||||
@@ -53,7 +55,8 @@ public @interface EnableRedisRepositories {
|
||||
|
||||
/**
|
||||
* Alias for the {@link #basePackages()} attribute. Allows for more concise annotation declarations e.g.:
|
||||
* {@code @EnableRedisRepositories("org.my.pkg")} instead of {@code @EnableRedisRepositories(basePackages="org.my.pkg")}.
|
||||
* {@code @EnableRedisRepositories("org.my.pkg")} instead of
|
||||
* {@code @EnableRedisRepositories(basePackages="org.my.pkg")}.
|
||||
*/
|
||||
String[] value() default {};
|
||||
|
||||
@@ -154,4 +157,12 @@ public @interface EnableRedisRepositories {
|
||||
*/
|
||||
Class<? extends KeyspaceConfiguration> keyspaceConfiguration() default KeyspaceConfiguration.class;
|
||||
|
||||
/**
|
||||
* Configure usage of {@link KeyExpirationEventMessageListener}.
|
||||
*
|
||||
* @return
|
||||
* @since 1.8
|
||||
*/
|
||||
EnableKeyspaceEvents enableKeyspaceEvents() default EnableKeyspaceEvents.ON_DEMAND;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2016 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.
|
||||
@@ -122,6 +122,11 @@ public class RedisRepositoryConfigurationExtension extends KeyValueRepositoryCon
|
||||
new RuntimeBeanReference(REDIS_CONVERTER_BEAN_NAME));
|
||||
|
||||
redisKeyValueAdapterDefinition.setConstructorArgumentValues(constructorArgumentValuesForRedisKeyValueAdapter);
|
||||
|
||||
DirectFieldAccessor dfa = new DirectFieldAccessor(configurationSource);
|
||||
AnnotationAttributes aa = (AnnotationAttributes) dfa.getPropertyValue("attributes");
|
||||
redisKeyValueAdapterDefinition.setAttribute("enableKeyspaceEvents", aa.getEnum("enableKeyspaceEvents"));
|
||||
|
||||
registerIfNotAlreadyRegistered(redisKeyValueAdapterDefinition, registry, REDIS_ADAPTER_BEAN_NAME,
|
||||
configurationSource);
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@ public class RedisKeyValueAdapterTests {
|
||||
mappingContext.afterPropertiesSet();
|
||||
|
||||
adapter = new RedisKeyValueAdapter(template, mappingContext);
|
||||
adapter.afterPropertiesSet();
|
||||
|
||||
template.execute(new RedisCallback<Void>() {
|
||||
|
||||
|
||||
@@ -16,51 +16,73 @@
|
||||
|
||||
package org.springframework.data.redis.core;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.test.util.ReflectionTestUtils.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisKeyValueAdapter.EnableKeyspaceEvents;
|
||||
import org.springframework.data.redis.core.convert.Bucket;
|
||||
import org.springframework.data.redis.core.convert.KeyspaceConfiguration;
|
||||
import org.springframework.data.redis.core.convert.MappingConfiguration;
|
||||
import org.springframework.data.redis.core.convert.RedisData;
|
||||
import org.springframework.data.redis.core.convert.SimpleIndexedPropertyValue;
|
||||
import org.springframework.data.redis.core.index.IndexConfiguration;
|
||||
import org.springframework.data.redis.core.mapping.RedisMappingContext;
|
||||
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link RedisKeyValueAdapter}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class RedisKeyValueAdapterUnitTests {
|
||||
|
||||
RedisTemplate<?, ?> redisTemplate;
|
||||
RedisKeyValueAdapter redisKeyValueAdapter;
|
||||
|
||||
RedisKeyValueAdapter adapter;
|
||||
RedisTemplate<?, ?> template;
|
||||
RedisMappingContext context;
|
||||
@Mock JedisConnectionFactory jedisConnectionFactoryMock;
|
||||
@Mock RedisConnection redisConnectionMock;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
redisTemplate = new RedisTemplate<Object, Object>();
|
||||
redisTemplate.setConnectionFactory(jedisConnectionFactoryMock);
|
||||
redisTemplate.afterPropertiesSet();
|
||||
template = new RedisTemplate<Object, Object>();
|
||||
template.setConnectionFactory(jedisConnectionFactoryMock);
|
||||
template.afterPropertiesSet();
|
||||
|
||||
when(jedisConnectionFactoryMock.getConnection()).thenReturn(redisConnectionMock);
|
||||
when(redisConnectionMock.getConfig("notify-keyspace-events"))
|
||||
.thenReturn(Arrays.asList("notify-keyspace-events", "KEA"));
|
||||
|
||||
redisKeyValueAdapter = new RedisKeyValueAdapter(redisTemplate);
|
||||
context = new RedisMappingContext(new MappingConfiguration(new IndexConfiguration(), new KeyspaceConfiguration()));
|
||||
context.afterPropertiesSet();
|
||||
|
||||
adapter = new RedisKeyValueAdapter(template, context);
|
||||
adapter.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
adapter.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,7 +91,7 @@ public class RedisKeyValueAdapterUnitTests {
|
||||
@Test
|
||||
public void destroyShouldNotDestroyConnectionFactory() throws Exception {
|
||||
|
||||
redisKeyValueAdapter.destroy();
|
||||
adapter.destroy();
|
||||
|
||||
verify(jedisConnectionFactoryMock, never()).destroy();
|
||||
}
|
||||
@@ -87,7 +109,7 @@ public class RedisKeyValueAdapterUnitTests {
|
||||
.thenReturn(new LinkedHashSet<byte[]>(Arrays.asList("persons:firstname:rand".getBytes())));
|
||||
when(redisConnectionMock.del((byte[][]) anyVararg())).thenReturn(1L);
|
||||
|
||||
redisKeyValueAdapter.put("1", rd, "persons");
|
||||
adapter.put("1", rd, "persons");
|
||||
|
||||
verify(redisConnectionMock, times(1)).sRem(any(byte[].class), any(byte[].class));
|
||||
}
|
||||
@@ -105,8 +127,88 @@ public class RedisKeyValueAdapterUnitTests {
|
||||
.thenReturn(new LinkedHashSet<byte[]>(Arrays.asList("persons:firstname:rand".getBytes())));
|
||||
when(redisConnectionMock.del((byte[][]) anyVararg())).thenReturn(0L);
|
||||
|
||||
redisKeyValueAdapter.put("1", rd, "persons");
|
||||
adapter.put("1", rd, "persons");
|
||||
|
||||
verify(redisConnectionMock, never()).sRem(any(byte[].class), (byte[][]) anyVararg());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-491
|
||||
*/
|
||||
@Test
|
||||
public void shouldInitKeyExpirationListenerOnStartup() throws Exception{
|
||||
|
||||
adapter.destroy();
|
||||
|
||||
adapter = new RedisKeyValueAdapter(template, context);
|
||||
adapter.setEnableKeyspaceEvents(EnableKeyspaceEvents.ON_STARTUP);
|
||||
adapter.afterPropertiesSet();
|
||||
|
||||
KeyExpirationEventMessageListener listener = ((AtomicReference<KeyExpirationEventMessageListener>) getField(adapter,
|
||||
"expirationListener")).get();
|
||||
assertThat(listener, notNullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-491
|
||||
*/
|
||||
@Test
|
||||
public void shouldInitKeyExpirationListenerOnFirstPutWithTtl() throws Exception {
|
||||
|
||||
adapter.destroy();
|
||||
|
||||
adapter = new RedisKeyValueAdapter(template, context);
|
||||
adapter.setEnableKeyspaceEvents(EnableKeyspaceEvents.ON_DEMAND);
|
||||
adapter.afterPropertiesSet();
|
||||
|
||||
KeyExpirationEventMessageListener listener = ((AtomicReference<KeyExpirationEventMessageListener>) getField(adapter,
|
||||
"expirationListener")).get();
|
||||
assertThat(listener, nullValue());
|
||||
|
||||
adapter.put("should-NOT-start-listener", new WithoutTimeToLive(), "keyspace");
|
||||
|
||||
listener = ((AtomicReference<KeyExpirationEventMessageListener>) getField(adapter, "expirationListener")).get();
|
||||
assertThat(listener, nullValue());
|
||||
|
||||
adapter.put("should-start-listener", new WithTimeToLive(), "keyspace");
|
||||
|
||||
listener = ((AtomicReference<KeyExpirationEventMessageListener>) getField(adapter, "expirationListener")).get();
|
||||
assertThat(listener, notNullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-491
|
||||
*/
|
||||
@Test
|
||||
public void shouldNeverInitKeyExpirationListener() throws Exception {
|
||||
|
||||
adapter.destroy();
|
||||
|
||||
adapter = new RedisKeyValueAdapter(template, context);
|
||||
adapter.setEnableKeyspaceEvents(EnableKeyspaceEvents.OFF);
|
||||
adapter.afterPropertiesSet();
|
||||
|
||||
KeyExpirationEventMessageListener listener = ((AtomicReference<KeyExpirationEventMessageListener>) getField(adapter,
|
||||
"expirationListener")).get();
|
||||
assertThat(listener, nullValue());
|
||||
|
||||
adapter.put("should-NOT-start-listener", new WithoutTimeToLive(), "keyspace");
|
||||
|
||||
listener = ((AtomicReference<KeyExpirationEventMessageListener>) getField(adapter, "expirationListener")).get();
|
||||
assertThat(listener, nullValue());
|
||||
|
||||
adapter.put("should-start-listener", new WithTimeToLive(), "keyspace");
|
||||
|
||||
listener = ((AtomicReference<KeyExpirationEventMessageListener>) getField(adapter, "expirationListener")).get();
|
||||
assertThat(listener, nullValue());
|
||||
}
|
||||
|
||||
static class WithoutTimeToLive {
|
||||
@Id String id;
|
||||
}
|
||||
|
||||
@RedisHash(timeToLive = 10)
|
||||
static class WithTimeToLive {
|
||||
@Id String id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,11 @@ import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.hamcrest.core.IsEqual.*;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
@@ -29,6 +32,7 @@ import org.springframework.core.type.StandardAnnotationMetadata;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.keyvalue.repository.KeyValueRepository;
|
||||
import org.springframework.data.redis.core.RedisHash;
|
||||
import org.springframework.data.redis.core.RedisKeyValueAdapter.EnableKeyspaceEvents;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
|
||||
import org.springframework.data.repository.config.RepositoryConfiguration;
|
||||
@@ -78,6 +82,25 @@ public class RedisRepositoryConfigurationExtensionUnitTests {
|
||||
extension.getRepositoryConfigurations(configurationSource, loader, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREDIS-491
|
||||
*/
|
||||
@Test
|
||||
public void picksUpEnableKeyspaceEventsCorrectly() {
|
||||
|
||||
metadata = new StandardAnnotationMetadata(ConfigWithKeyspaceEventsDisabled.class, true);
|
||||
configurationSource = new AnnotationRepositoryConfigurationSource(metadata, EnableRedisRepositories.class, loader,
|
||||
environment);
|
||||
|
||||
RedisRepositoryConfigurationExtension extension = new RedisRepositoryConfigurationExtension();
|
||||
|
||||
BeanDefinitionRegistry beanDefintionRegistry = new SimpleBeanDefinitionRegistry();
|
||||
extension.registerBeansForRoot(beanDefintionRegistry, configurationSource);
|
||||
|
||||
assertThat(beanDefintionRegistry.getBeanDefinition("redisKeyValueAdapter").getAttribute("enableKeyspaceEvents"),
|
||||
equalTo((Object) EnableKeyspaceEvents.OFF));
|
||||
}
|
||||
|
||||
private static void assertDoesNotHaveRepo(Class<?> repositoryInterface,
|
||||
Collection<RepositoryConfiguration<RepositoryConfigurationSource>> configs) {
|
||||
|
||||
@@ -108,6 +131,11 @@ public class RedisRepositoryConfigurationExtensionUnitTests {
|
||||
|
||||
}
|
||||
|
||||
@EnableRedisRepositories(considerNestedRepositories = true, enableKeyspaceEvents = EnableKeyspaceEvents.OFF)
|
||||
static class ConfigWithKeyspaceEventsDisabled {
|
||||
|
||||
}
|
||||
|
||||
@RedisHash
|
||||
static class Sample {
|
||||
@Id String id;
|
||||
|
||||
Reference in New Issue
Block a user