INT-4123: Add Prefix to the Key-Value MSs

Fixes spring-projects/spring-integration#2213
JIRA: https://jira.spring.io/browse/INT-4123

Fully different `MessageStore`s can be configured for the same shared
Key-Value data-base.
Since the retrieval logic is based on the keys, that may cause the
unexpected messages expiration via `MessageGroupStoreReaper`.

* To distinguish store instances on the shared store add `prefix`
option to the `AbstractKeyValueMessageStore`

* Deprecate the `GemfireMessageStore` `Cache`-based configuration - `setIgnoreJta()` and `afterPropertiesSet()`.
The `GemfireMessageStore` relies only on an externally configured `Region`.

**Cherry-pick to 4.3.x**

Doc Polishing
This commit is contained in:
Artem Bilan
2017-09-05 18:23:03 -04:00
committed by Gary Russell
parent df55ac95d8
commit 5263ea6dff
8 changed files with 176 additions and 111 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2007-2016 the original author or authors.
* Copyright 2007-2017 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.
@@ -35,13 +35,34 @@ import org.springframework.util.Assert;
*
* @author Oleg Zhurakousky
* @author Gary Russell
* @author Artem Bilan
*
* @since 2.1
*/
public class RedisMessageStore extends AbstractKeyValueMessageStore {
private final RedisTemplate<Object, Object> redisTemplate;
/**
* Construct {@link RedisMessageStore} based on the provided
* {@link RedisConnectionFactory} and default empty prefix.
* @param connectionFactory the RedisConnectionFactory to use
*/
public RedisMessageStore(RedisConnectionFactory connectionFactory) {
this(connectionFactory, "");
}
/**
* Construct {@link RedisMessageStore} based on the provided
* {@link RedisConnectionFactory} and prefix.
* @param connectionFactory the RedisConnectionFactory to use
* @param prefix the key prefix to use, allowing the same broker to be used for
* multiple stores.
* @since 4.3.12
* @see AbstractKeyValueMessageStore#AbstractKeyValueMessageStore(String)
*/
public RedisMessageStore(RedisConnectionFactory connectionFactory, String prefix) {
super(prefix);
this.redisTemplate = new RedisTemplate<Object, Object>();
this.redisTemplate.setConnectionFactory(connectionFactory);
this.redisTemplate.setKeySerializer(new StringRedisSerializer());
@@ -93,13 +114,6 @@ public class RedisMessageStore extends AbstractKeyValueMessageStore {
}
}
private void rethrowAsIllegalArgumentException(SerializationException e) {
throw new IllegalArgumentException("If relying on the default RedisSerializer " +
"(JdkSerializationRedisSerializer) the Object must be Serializable. " +
"Either make it Serializable or provide your own implementation of " +
"RedisSerializer via 'setValueSerializer(..)'", e);
}
@Override
protected Object doRemove(Object id) {
Assert.notNull(id, "'id' must not be null");
@@ -110,10 +124,17 @@ public class RedisMessageStore extends AbstractKeyValueMessageStore {
return removedObject;
}
@Override
protected Collection<?> doListKeys(String keyPattern) {
Assert.hasText(keyPattern, "'keyPattern' must not be empty");
return this.redisTemplate.keys(keyPattern);
}
private void rethrowAsIllegalArgumentException(SerializationException e) {
throw new IllegalArgumentException("If relying on the default RedisSerializer " +
"(JdkSerializationRedisSerializer) the Object must be Serializable. " +
"Either make it Serializable or provide your own implementation of " +
"RedisSerializer via 'setValueSerializer(..)'", e);
}
}

View File

@@ -32,6 +32,7 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.history.MessageHistory;
@@ -53,7 +54,7 @@ public class RedisMessageStoreTests extends RedisAvailableTests {
@After
public void setUpTearDown() {
StringRedisTemplate template = this.createStringRedisTemplate(this.getConnectionFactoryForTest());
template.delete(template.keys("MESSAGE_*"));
template.delete(template.keys("*MESSAGE_*"));
}
@Test
@@ -122,6 +123,24 @@ public class RedisMessageStoreTests extends RedisAvailableTests {
assertEquals("Hello Redis", retrievedMessage.getPayload());
}
@SuppressWarnings("unchecked")
@Test
@RedisAvailable
public void testAddAndGetWithPrefix() {
RedisConnectionFactory jcf = this.getConnectionFactoryForTest();
RedisMessageStore store = new RedisMessageStore(jcf, "foo");
Message<String> stringMessage = new GenericMessage<String>("Hello Redis");
store.addMessage(stringMessage);
Message<String> retrievedMessage = (Message<String>) store.getMessage(stringMessage.getHeaders().getId());
assertNotNull(retrievedMessage);
assertEquals("Hello Redis", retrievedMessage.getPayload());
StringRedisTemplate template = createStringRedisTemplate(getConnectionFactoryForTest());
BoundValueOperations<String, String> ops =
template.boundValueOps("foo" + "MESSAGE_" + stringMessage.getHeaders().getId());
assertNotNull(ops.get());
}
@SuppressWarnings("unchecked")
@Test
@RedisAvailable