Reorder methods.

See: #2273
Original Pull Request: #2276
This commit is contained in:
Mark Paluch
2022-02-24 14:50:19 +01:00
committed by Christoph Strobl
parent f5af2cf468
commit 19d1f52f0a
2 changed files with 402 additions and 374 deletions

View File

@@ -95,7 +95,7 @@ public interface RedisOperations<K, V> {
* values are hashes, this serializer will be used to deserialize both the key and value
* @return list of objects returned by the pipeline
*/
List<Object> executePipelined(final RedisCallback<?> action, final RedisSerializer<?> resultSerializer);
List<Object> executePipelined(RedisCallback<?> action, RedisSerializer<?> resultSerializer);
/**
* Executes the given Redis session on a pipelined connection. Allows transactions to be pipelined. Note that the
@@ -104,7 +104,7 @@ public interface RedisOperations<K, V> {
* @param session Session callback
* @return list of objects returned by the pipeline
*/
List<Object> executePipelined(final SessionCallback<?> session);
List<Object> executePipelined(SessionCallback<?> session);
/**
* Executes the given Redis session on a pipelined connection, returning the results using a dedicated serializer.
@@ -115,7 +115,7 @@ public interface RedisOperations<K, V> {
* @param resultSerializer
* @return list of objects returned by the pipeline
*/
List<Object> executePipelined(final SessionCallback<?> session, final RedisSerializer<?> resultSerializer);
List<Object> executePipelined(SessionCallback<?> session, RedisSerializer<?> resultSerializer);
/**
* Executes the given {@link RedisScript}

View File

@@ -165,6 +165,192 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
initialized = true;
}
/**
* Returns whether to expose the native Redis connection to RedisCallback code, or rather a connection proxy (the
* default).
*
* @return whether to expose the native Redis connection or not
*/
public boolean isExposeConnection() {
return exposeConnection;
}
/**
* Sets whether to expose the Redis connection to {@link RedisCallback} code. Default is "false": a proxy will be
* returned, suppressing {@code quit} and {@code disconnect} calls.
*
* @param exposeConnection
*/
public void setExposeConnection(boolean exposeConnection) {
this.exposeConnection = exposeConnection;
}
/**
* @return Whether or not the default serializer should be used. If not, any serializers not explicitly set will
* remain null and values will not be serialized or deserialized.
*/
public boolean isEnableDefaultSerializer() {
return enableDefaultSerializer;
}
/**
* @param enableDefaultSerializer Whether or not the default serializer should be used. If not, any serializers not
* explicitly set will remain null and values will not be serialized or deserialized.
*/
public void setEnableDefaultSerializer(boolean enableDefaultSerializer) {
this.enableDefaultSerializer = enableDefaultSerializer;
}
/**
* If set to {@code true} {@link RedisTemplate} will participate in ongoing transactions using
* {@literal MULTI...EXEC|DISCARD} to keep track of operations.
*
* @param enableTransactionSupport whether to participate in ongoing transactions.
* @since 1.3
* @see RedisConnectionUtils#getConnection(RedisConnectionFactory, boolean)
* @see TransactionSynchronizationManager#isActualTransactionActive()
*/
public void setEnableTransactionSupport(boolean enableTransactionSupport) {
this.enableTransactionSupport = enableTransactionSupport;
}
/**
* Set the {@link ClassLoader} to be used for the default {@link JdkSerializationRedisSerializer} in case no other
* {@link RedisSerializer} is explicitly set as the default one.
*
* @param classLoader can be {@literal null}.
* @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader
* @since 1.8
*/
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
/**
* Returns the default serializer used by this template.
*
* @return template default serializer
*/
@Nullable
public RedisSerializer<?> getDefaultSerializer() {
return defaultSerializer;
}
/**
* Sets the default serializer to use for this template. All serializers (except the
* {@link #setStringSerializer(RedisSerializer)}) are initialized to this value unless explicitly set. Defaults to
* {@link JdkSerializationRedisSerializer}.
*
* @param serializer default serializer to use
*/
public void setDefaultSerializer(RedisSerializer<?> serializer) {
this.defaultSerializer = serializer;
}
/**
* Sets the key serializer to be used by this template. Defaults to {@link #getDefaultSerializer()}.
*
* @param serializer the key serializer to be used by this template.
*/
public void setKeySerializer(RedisSerializer<?> serializer) {
this.keySerializer = serializer;
}
/**
* Returns the key serializer used by this template.
*
* @return the key serializer used by this template.
*/
@Override
public RedisSerializer<?> getKeySerializer() {
return keySerializer;
}
/**
* Sets the value serializer to be used by this template. Defaults to {@link #getDefaultSerializer()}.
*
* @param serializer the value serializer to be used by this template.
*/
public void setValueSerializer(RedisSerializer<?> serializer) {
this.valueSerializer = serializer;
}
/**
* Returns the value serializer used by this template.
*
* @return the value serializer used by this template.
*/
@Override
public RedisSerializer<?> getValueSerializer() {
return valueSerializer;
}
/**
* Returns the hashKeySerializer.
*
* @return Returns the hashKeySerializer
*/
@Override
public RedisSerializer<?> getHashKeySerializer() {
return hashKeySerializer;
}
/**
* Sets the hash key (or field) serializer to be used by this template. Defaults to {@link #getDefaultSerializer()}.
*
* @param hashKeySerializer The hashKeySerializer to set.
*/
public void setHashKeySerializer(RedisSerializer<?> hashKeySerializer) {
this.hashKeySerializer = hashKeySerializer;
}
/**
* Returns the hashValueSerializer.
*
* @return Returns the hashValueSerializer
*/
@Override
public RedisSerializer<?> getHashValueSerializer() {
return hashValueSerializer;
}
/**
* Sets the hash value serializer to be used by this template. Defaults to {@link #getDefaultSerializer()}.
*
* @param hashValueSerializer The hashValueSerializer to set.
*/
public void setHashValueSerializer(RedisSerializer<?> hashValueSerializer) {
this.hashValueSerializer = hashValueSerializer;
}
/**
* Returns the stringSerializer.
*
* @return Returns the stringSerializer
*/
public RedisSerializer<String> getStringSerializer() {
return stringSerializer;
}
/**
* Sets the string value serializer to be used by this template (when the arguments or return types are always
* strings). Defaults to {@link StringRedisSerializer}.
*
* @see ValueOperations#get(Object, long, long)
* @param stringSerializer The stringValueSerializer to set.
*/
public void setStringSerializer(RedisSerializer<String> stringSerializer) {
this.stringSerializer = stringSerializer;
}
/**
* @param scriptExecutor The {@link ScriptExecutor} to use for executing Redis scripts
*/
public void setScriptExecutor(ScriptExecutor<K> scriptExecutor) {
this.scriptExecutor = scriptExecutor;
}
@Override
@Nullable
public <T> T execute(RedisCallback<T> action) {
@@ -361,299 +547,9 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
return result;
}
/**
* Returns whether to expose the native Redis connection to RedisCallback code, or rather a connection proxy (the
* default).
*
* @return whether to expose the native Redis connection or not
*/
public boolean isExposeConnection() {
return exposeConnection;
}
/**
* Sets whether to expose the Redis connection to {@link RedisCallback} code. Default is "false": a proxy will be
* returned, suppressing {@code quit} and {@code disconnect} calls.
*
* @param exposeConnection
*/
public void setExposeConnection(boolean exposeConnection) {
this.exposeConnection = exposeConnection;
}
/**
* @return Whether or not the default serializer should be used. If not, any serializers not explicitly set will
* remain null and values will not be serialized or deserialized.
*/
public boolean isEnableDefaultSerializer() {
return enableDefaultSerializer;
}
/**
* @param enableDefaultSerializer Whether or not the default serializer should be used. If not, any serializers not
* explicitly set will remain null and values will not be serialized or deserialized.
*/
public void setEnableDefaultSerializer(boolean enableDefaultSerializer) {
this.enableDefaultSerializer = enableDefaultSerializer;
}
/**
* Returns the default serializer used by this template.
*
* @return template default serializer
*/
@Nullable
public RedisSerializer<?> getDefaultSerializer() {
return defaultSerializer;
}
/**
* Sets the default serializer to use for this template. All serializers (except the
* {@link #setStringSerializer(RedisSerializer)}) are initialized to this value unless explicitly set. Defaults to
* {@link JdkSerializationRedisSerializer}.
*
* @param serializer default serializer to use
*/
public void setDefaultSerializer(RedisSerializer<?> serializer) {
this.defaultSerializer = serializer;
}
/**
* Sets the key serializer to be used by this template. Defaults to {@link #getDefaultSerializer()}.
*
* @param serializer the key serializer to be used by this template.
*/
public void setKeySerializer(RedisSerializer<?> serializer) {
this.keySerializer = serializer;
}
/**
* Returns the key serializer used by this template.
*
* @return the key serializer used by this template.
*/
@Override
public RedisSerializer<?> getKeySerializer() {
return keySerializer;
}
/**
* Sets the value serializer to be used by this template. Defaults to {@link #getDefaultSerializer()}.
*
* @param serializer the value serializer to be used by this template.
*/
public void setValueSerializer(RedisSerializer<?> serializer) {
this.valueSerializer = serializer;
}
/**
* Returns the value serializer used by this template.
*
* @return the value serializer used by this template.
*/
@Override
public RedisSerializer<?> getValueSerializer() {
return valueSerializer;
}
/**
* Returns the hashKeySerializer.
*
* @return Returns the hashKeySerializer
*/
@Override
public RedisSerializer<?> getHashKeySerializer() {
return hashKeySerializer;
}
/**
* Sets the hash key (or field) serializer to be used by this template. Defaults to {@link #getDefaultSerializer()}.
*
* @param hashKeySerializer The hashKeySerializer to set.
*/
public void setHashKeySerializer(RedisSerializer<?> hashKeySerializer) {
this.hashKeySerializer = hashKeySerializer;
}
/**
* Returns the hashValueSerializer.
*
* @return Returns the hashValueSerializer
*/
@Override
public RedisSerializer<?> getHashValueSerializer() {
return hashValueSerializer;
}
/**
* Sets the hash value serializer to be used by this template. Defaults to {@link #getDefaultSerializer()}.
*
* @param hashValueSerializer The hashValueSerializer to set.
*/
public void setHashValueSerializer(RedisSerializer<?> hashValueSerializer) {
this.hashValueSerializer = hashValueSerializer;
}
/**
* Returns the stringSerializer.
*
* @return Returns the stringSerializer
*/
public RedisSerializer<String> getStringSerializer() {
return stringSerializer;
}
/**
* Sets the string value serializer to be used by this template (when the arguments or return types are always
* strings). Defaults to {@link StringRedisSerializer}.
*
* @see ValueOperations#get(Object, long, long)
* @param stringSerializer The stringValueSerializer to set.
*/
public void setStringSerializer(RedisSerializer<String> stringSerializer) {
this.stringSerializer = stringSerializer;
}
/**
* @param scriptExecutor The {@link ScriptExecutor} to use for executing Redis scripts
*/
public void setScriptExecutor(ScriptExecutor<K> scriptExecutor) {
this.scriptExecutor = scriptExecutor;
}
@SuppressWarnings("unchecked")
private byte[] rawKey(Object key) {
Assert.notNull(key, "non null key required");
if (keySerializer == null && key instanceof byte[]) {
return (byte[]) key;
}
return keySerializer.serialize(key);
}
private byte[] rawString(String key) {
return stringSerializer.serialize(key);
}
@SuppressWarnings("unchecked")
private byte[] rawValue(Object value) {
if (valueSerializer == null && value instanceof byte[]) {
return (byte[]) value;
}
return valueSerializer.serialize(value);
}
private byte[][] rawKeys(Collection<K> keys) {
final byte[][] rawKeys = new byte[keys.size()][];
int i = 0;
for (K key : keys) {
rawKeys[i++] = rawKey(key);
}
return rawKeys;
}
@SuppressWarnings("unchecked")
private K deserializeKey(byte[] value) {
return keySerializer != null ? (K) keySerializer.deserialize(value) : (K) value;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Nullable
private List<Object> deserializeMixedResults(@Nullable List<Object> rawValues,
@Nullable RedisSerializer valueSerializer, @Nullable RedisSerializer hashKeySerializer,
@Nullable RedisSerializer hashValueSerializer) {
if (rawValues == null) {
return null;
}
List<Object> values = new ArrayList<>();
for (Object rawValue : rawValues) {
if (rawValue instanceof byte[] && valueSerializer != null) {
values.add(valueSerializer.deserialize((byte[]) rawValue));
} else if (rawValue instanceof List) {
// Lists are the only potential Collections of mixed values....
values.add(deserializeMixedResults((List) rawValue, valueSerializer, hashKeySerializer, hashValueSerializer));
} else if (rawValue instanceof Set && !(((Set) rawValue).isEmpty())) {
values.add(deserializeSet((Set) rawValue, valueSerializer));
} else if (rawValue instanceof Map && !(((Map) rawValue).isEmpty())
&& ((Map) rawValue).values().iterator().next() instanceof byte[]) {
values.add(SerializationUtils.deserialize((Map) rawValue, hashKeySerializer, hashValueSerializer));
} else {
values.add(rawValue);
}
}
return values;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private Set<?> deserializeSet(Set rawSet, @Nullable RedisSerializer valueSerializer) {
if (rawSet.isEmpty()) {
return rawSet;
}
Object setValue = rawSet.iterator().next();
if (setValue instanceof byte[] && valueSerializer != null) {
return (SerializationUtils.deserialize(rawSet, valueSerializer));
} else if (setValue instanceof Tuple) {
return convertTupleValues(rawSet, valueSerializer);
} else {
return rawSet;
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private Set<TypedTuple<V>> convertTupleValues(Set<Tuple> rawValues, @Nullable RedisSerializer valueSerializer) {
Set<TypedTuple<V>> set = new LinkedHashSet<>(rawValues.size());
for (Tuple rawValue : rawValues) {
Object value = rawValue.getValue();
if (valueSerializer != null) {
value = valueSerializer.deserialize(rawValue.getValue());
}
set.add(new DefaultTypedTuple(value, rawValue.getScore()));
}
return set;
}
//
// RedisOperations
//
/**
* Execute a transaction, using the default {@link RedisSerializer}s to deserialize any results that are byte[]s or
* Collections or Maps of byte[]s or Tuples. Other result types (Long, Boolean, etc) are left as-is in the converted
* results. If conversion of tx results has been disabled in the {@link RedisConnectionFactory}, the results of exec
* will be returned without deserialization. This check is mostly for backwards compatibility with 1.0.
*
* @return The (possibly deserialized) results of transaction exec
*/
@Override
public List<Object> exec() {
List<Object> results = execRaw();
if (getRequiredConnectionFactory().getConvertPipelineAndTxResults()) {
return deserializeMixedResults(results, valueSerializer, hashKeySerializer, hashValueSerializer);
} else {
return results;
}
}
@Override
public List<Object> exec(RedisSerializer<?> valueSerializer) {
return deserializeMixedResults(execRaw(), valueSerializer, valueSerializer, valueSerializer);
}
protected List<Object> execRaw() {
List<Object> raw = execute(RedisTxCommands::exec);
return raw == null ? Collections.emptyList() : raw;
}
// -------------------------------------------------------------------------
// Methods dealing with Redis Keys
// -------------------------------------------------------------------------
@Override
public Boolean copy(K source, K target, boolean replace) {
@@ -899,54 +795,6 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
}, true);
}
@Override
public void multi() {
execute(connection -> {
connection.multi();
return null;
}, true);
}
@Override
public void discard() {
execute(connection -> {
connection.discard();
return null;
}, true);
}
@Override
public void watch(K key) {
byte[] rawKey = rawKey(key);
execute(connection -> {
connection.watch(rawKey);
return null;
}, true);
}
@Override
public void watch(Collection<K> keys) {
byte[][] rawKeys = rawKeys(keys);
execute(connection -> {
connection.watch(rawKeys);
return null;
}, true);
}
@Override
public void unwatch() {
execute(connection -> {
connection.unwatch();
return null;
}, true);
}
// Sort operations
@Override
@@ -1006,11 +854,103 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
byte[] rawKey = rawKey(query.getKey());
SortParameters params = QueryUtils.convertQuery(query, stringSerializer);
return execute(connection -> connection.sort(rawKey, params, rawStoreKey), true);
return doWithKeys(connection -> connection.sort(rawKey, params, rawStoreKey));
}
// -------------------------------------------------------------------------
// Methods dealing with Redis Transactions
// -------------------------------------------------------------------------
@Override
public void watch(K key) {
byte[] rawKey = rawKey(key);
execute(connection -> {
connection.watch(rawKey);
return null;
}, true);
}
@Override
public void killClient(final String host, final int port) {
public void watch(Collection<K> keys) {
byte[][] rawKeys = rawKeys(keys);
execute(connection -> {
connection.watch(rawKeys);
return null;
}, true);
}
@Override
public void unwatch() {
execute(connection -> {
connection.unwatch();
return null;
}, true);
}
@Override
public void multi() {
execute(connection -> {
connection.multi();
return null;
}, true);
}
@Override
public void discard() {
execute(connection -> {
connection.discard();
return null;
}, true);
}
/**
* Execute a transaction, using the default {@link RedisSerializer}s to deserialize any results that are byte[]s or
* Collections or Maps of byte[]s or Tuples. Other result types (Long, Boolean, etc) are left as-is in the converted
* results. If conversion of tx results has been disabled in the {@link RedisConnectionFactory}, the results of exec
* will be returned without deserialization. This check is mostly for backwards compatibility with 1.0.
*
* @return The (possibly deserialized) results of transaction exec
*/
@Override
public List<Object> exec() {
List<Object> results = execRaw();
if (getRequiredConnectionFactory().getConvertPipelineAndTxResults()) {
return deserializeMixedResults(results, valueSerializer, hashKeySerializer, hashValueSerializer);
} else {
return results;
}
}
@Override
public List<Object> exec(RedisSerializer<?> valueSerializer) {
return deserializeMixedResults(execRaw(), valueSerializer, valueSerializer, valueSerializer);
}
protected List<Object> execRaw() {
List<Object> raw = execute(RedisTxCommands::exec);
return raw == null ? Collections.emptyList() : raw;
}
// -------------------------------------------------------------------------
// Methods dealing with Redis Server Commands
// -------------------------------------------------------------------------
@Override
public List<RedisClientInfo> getClientList() {
return execute(RedisServerCommands::getClientList);
}
@Override
public void killClient(String host, int port) {
execute((RedisCallback<Void>) connection -> {
connection.killClient(host, port);
@@ -1018,16 +958,11 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
});
}
@Override
public List<RedisClientInfo> getClientList() {
return execute(RedisServerCommands::getClientList);
}
/*
* @see org.springframework.data.redis.core.RedisOperations#replicaOf(java.lang.String, int)
*/
@Override
public void replicaOf(final String host, final int port) {
public void replicaOf(String host, int port) {
execute((RedisCallback<Void>) connection -> {
@@ -1045,6 +980,24 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
});
}
@Override
public void convertAndSend(String channel, Object message) {
Assert.hasText(channel, "a non-empty channel is required");
byte[] rawChannel = rawString(channel);
byte[] rawMessage = rawValue(message);
execute(connection -> {
connection.publish(rawChannel, rawMessage);
return null;
}, true);
}
// -------------------------------------------------------------------------
// Methods to obtain specific operations interface objects.
// -------------------------------------------------------------------------
@Override
public ClusterOperations<K, V> opsForCluster() {
return clusterOps;
@@ -1133,29 +1086,104 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
return zSetOps;
}
/**
* If set to {@code true} {@link RedisTemplate} will participate in ongoing transactions using
* {@literal MULTI...EXEC|DISCARD} to keep track of operations.
*
* @param enableTransactionSupport whether to participate in ongoing transactions.
* @since 1.3
* @see RedisConnectionUtils#getConnection(RedisConnectionFactory, boolean)
* @see TransactionSynchronizationManager#isActualTransactionActive()
*/
public void setEnableTransactionSupport(boolean enableTransactionSupport) {
this.enableTransactionSupport = enableTransactionSupport;
@SuppressWarnings("unchecked")
private byte[] rawKey(Object key) {
Assert.notNull(key, "non null key required");
if (keySerializer == null && key instanceof byte[]) {
return (byte[]) key;
}
return keySerializer.serialize(key);
}
/**
* Set the {@link ClassLoader} to be used for the default {@link JdkSerializationRedisSerializer} in case no other
* {@link RedisSerializer} is explicitly set as the default one.
*
* @param classLoader can be {@literal null}.
* @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader
* @since 1.8
*/
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
private byte[] rawString(String key) {
return stringSerializer.serialize(key);
}
@SuppressWarnings("unchecked")
private byte[] rawValue(Object value) {
if (valueSerializer == null && value instanceof byte[]) {
return (byte[]) value;
}
return valueSerializer.serialize(value);
}
private byte[][] rawKeys(Collection<K> keys) {
final byte[][] rawKeys = new byte[keys.size()][];
int i = 0;
for (K key : keys) {
rawKeys[i++] = rawKey(key);
}
return rawKeys;
}
@SuppressWarnings("unchecked")
private K deserializeKey(byte[] value) {
return keySerializer != null ? (K) keySerializer.deserialize(value) : (K) value;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Nullable
private List<Object> deserializeMixedResults(@Nullable List<Object> rawValues,
@Nullable RedisSerializer valueSerializer, @Nullable RedisSerializer hashKeySerializer,
@Nullable RedisSerializer hashValueSerializer) {
if (rawValues == null) {
return null;
}
List<Object> values = new ArrayList<>();
for (Object rawValue : rawValues) {
if (rawValue instanceof byte[] && valueSerializer != null) {
values.add(valueSerializer.deserialize((byte[]) rawValue));
} else if (rawValue instanceof List) {
// Lists are the only potential Collections of mixed values....
values.add(deserializeMixedResults((List) rawValue, valueSerializer, hashKeySerializer, hashValueSerializer));
} else if (rawValue instanceof Set && !(((Set) rawValue).isEmpty())) {
values.add(deserializeSet((Set) rawValue, valueSerializer));
} else if (rawValue instanceof Map && !(((Map) rawValue).isEmpty())
&& ((Map) rawValue).values().iterator().next() instanceof byte[]) {
values.add(SerializationUtils.deserialize((Map) rawValue, hashKeySerializer, hashValueSerializer));
} else {
values.add(rawValue);
}
}
return values;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private Set<?> deserializeSet(Set rawSet, @Nullable RedisSerializer valueSerializer) {
if (rawSet.isEmpty()) {
return rawSet;
}
Object setValue = rawSet.iterator().next();
if (setValue instanceof byte[] && valueSerializer != null) {
return (SerializationUtils.deserialize(rawSet, valueSerializer));
} else if (setValue instanceof Tuple) {
return convertTupleValues(rawSet, valueSerializer);
} else {
return rawSet;
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private Set<TypedTuple<V>> convertTupleValues(Set<Tuple> rawValues, @Nullable RedisSerializer valueSerializer) {
Set<TypedTuple<V>> set = new LinkedHashSet<>(rawValues.size());
for (Tuple rawValue : rawValues) {
Object value = rawValue.getValue();
if (valueSerializer != null) {
value = valueSerializer.deserialize(rawValue.getValue());
}
set.add(new DefaultTypedTuple(value, rawValue.getScore()));
}
return set;
}
}