目錄
二,RedisTemplate和StringRedisTemplate的代碼結構
JdkSerializationRedisSerializer
一,簡介
簡單的說,RedisTemplate和StringRedisTemplate的關係如下:
1,StringRedisTemplate是RedisTemplate的子類。
2,StringRedisTemplate的各個序列化策略都是StringRedisSerializer,而RedisTemplate用的是JdkSerializationRedisSerializer。
二,RedisTemplate和StringRedisTemplate的代碼結構
從RedisTemplate類說起。
在RedisTemplate類中,定義了這樣四個變量:
@Nullable
private RedisSerializer keySerializer = null;
@Nullable
private RedisSerializer valueSerializer = null;
@Nullable
private RedisSerializer hashKeySerializer = null;
@Nullable
private RedisSerializer hashValueSerializer = null;
分別代表了普通key,value,和Hash類型的key,value的序列化策略,可以分別設置。
另外定義變量,用來指定默認的序列化策略:
@Nullable
private RedisSerializer<?> defaultSerializer;
在RedisTemplate類中,定義了afterPropertiesSet()方法,當Spring創建RedisTemplate類的對象時,會調用這個方法:
public void afterPropertiesSet() {
super.afterPropertiesSet();
boolean defaultUsed = false;
if (this.defaultSerializer == null) {
this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null ? this.classLoader : this.getClass().getClassLoader());
}
if (this.enableDefaultSerializer) {
if (this.keySerializer == null) {
this.keySerializer = this.defaultSerializer;
defaultUsed = true;
}
if (this.valueSerializer == null) {
this.valueSerializer = this.defaultSerializer;
defaultUsed = true;
}
if (this.hashKeySerializer == null) {
this.hashKeySerializer = this.defaultSerializer;
defaultUsed = true;
}
if (this.hashValueSerializer == null) {
this.hashValueSerializer = this.defaultSerializer;
defaultUsed = true;
}
}
if (this.enableDefaultSerializer && defaultUsed) {
Assert.notNull(this.defaultSerializer, "default serializer null and not all serializers initialized");
}
if (this.scriptExecutor == null) {
this.scriptExecutor = new DefaultScriptExecutor(this);
}
this.initialized = true;
}
可以看到,在默認情況下,RedisTemplate使用的默認序列化策略是JdkSerializationRedisSerializer。包括RedisTemplate下的key,value,hash-key,hash-value的序列化,都用這種策略。
再來看看StringRedisTemplate,他作爲RedisTemplate的子類,只是修改了序列化策略:
public class StringRedisTemplate extends RedisTemplate<String, String> {
public StringRedisTemplate() {
RedisSerializer<String> stringSerializer = new StringRedisSerializer();
this.setKeySerializer(stringSerializer);
this.setValueSerializer(stringSerializer);
this.setHashKeySerializer(stringSerializer);
this.setHashValueSerializer(stringSerializer);
}
public StringRedisTemplate(RedisConnectionFactory connectionFactory) {
this();
this.setConnectionFactory(connectionFactory);
this.afterPropertiesSet();
}
protected RedisConnection preProcessConnection(RedisConnection connection, boolean existingConnection) {
return new DefaultStringRedisConnection(connection);
}
}
以上就是StringRedisTemplate整個類的內容,可以看到,在他的默認構造中,key,value,hash-key,hash-value都使用的是StringRedisSerializer類作爲序列化策略。這也就是StringRedisTemplate和他的父類RedisTemplate的主要區別。
三,序列化策略
更進一步,看一下這個序列化策略是什麼。
上面提到的StringRedisSerializer和JdkSerializationRedisSerializer都是序列化策略類,他們都實現了一個RedisSerializer<T>接口:
public interface RedisSerializer<T> {
@Nullable
byte[] serialize(@Nullable T var1) throws SerializationException;
@Nullable
T deserialize(@Nullable byte[] var1) throws SerializationException;
}
接口表達的意思很簡單,兩個方法,serialize用於序列化,把對象變爲byte數組,deserialize用於反序列化,把byte數組轉爲對象。
StringRedisSerializer
看看StringRedisSerializer是怎麼做的:
1,StringRedisSerializer的構造:
public StringRedisSerializer() {
this(StandardCharsets.UTF_8);
}
public StringRedisSerializer(Charset charset) {
Assert.notNull(charset, "Charset must not be null!");
this.charset = charset;
}
定義了編碼格式,默認UTF_8。
2,StringRedisSerializer的serialize和deserialize方法:
public String deserialize(@Nullable byte[] bytes) {
return bytes == null ? null : new String(bytes, this.charset);
}
public byte[] serialize(@Nullable String string) {
return string == null ? null : string.getBytes(this.charset);
}
可以看到,StringRedisSerializer採用的是字符串和對應編碼下二進制數組之間的轉換。
在這種編碼格式下,如果我們向redis保存信息,然後用客戶端訪問Redis時,只要編碼格式一致,就能看到保存信息的原文。保存字符串ABC,客戶端看到的也是字符串ABC。
JdkSerializationRedisSerializer
然後對比看看JdkSerializationRedisSerializer是怎麼做的。
1,JdkSerializationRedisSerializer的構造:
private final Converter<Object, byte[]> serializer;
private final Converter<byte[], Object> deserializer;
public JdkSerializationRedisSerializer() {
this(new SerializingConverter(), new DeserializingConverter());
}
public JdkSerializationRedisSerializer(ClassLoader classLoader) {
this(new SerializingConverter(), new DeserializingConverter(classLoader));
}
可以看到,JdkSerializationRedisSerializer定義了兩個變量,serializer和deserializer,顯然是用來序列化和反序列化的,他們兩個的類型是一樣的,都是Converter接口,只是泛型不同。
Converter接口:
@FunctionalInterface
public interface Converter<S, T> {
@Nullable
T convert(S source);
}
就一個方法。
另外在JdkSerializationRedisSerializer的構造中,對serializer和deserializer進行了初始化,使用SerializingConverter和DeserializingConverter作爲實現類。
2,JdkSerializationRedisSerializer的serialize和deserialize方法:
public Object deserialize(@Nullable byte[] bytes) {
if (SerializationUtils.isEmpty(bytes)) {
return null;
} else {
try {
return this.deserializer.convert(bytes);
} catch (Exception var3) {
throw new SerializationException("Cannot deserialize", var3);
}
}
}
public byte[] serialize(@Nullable Object object) {
if (object == null) {
return SerializationUtils.EMPTY_ARRAY;
} else {
try {
return (byte[])this.serializer.convert(object);
} catch (Exception var3) {
throw new SerializationException("Cannot serialize", var3);
}
}
}
其實就是調用了對應Converter的convert方法。
3,關於Converter
既然到這了,就再深入一步,看看SerializingConverter和DeserializingConverter的convert方法。
首先,序列化:
SerializingConverter的相關方法,貼一部分關鍵的:
public SerializingConverter() {
this.serializer = new DefaultSerializer();
}
@Override
public byte[] convert(Object source) {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(1024);
try {
this.serializer.serialize(source, byteStream);
return byteStream.toByteArray();
}
catch (Throwable ex) {
throw new SerializationFailedException("Failed to serialize object using " +
this.serializer.getClass().getSimpleName(), ex);
}
}
可以看到,SerializingConverter類定義了serializer變量,用DefaultSerializer類實現,序列化的方式是調用DefaultSerializer的serialize方法:
@Override
public void serialize(Object object, OutputStream outputStream) throws IOException {
if (!(object instanceof Serializable)) {
throw new IllegalArgumentException(getClass().getSimpleName() + " requires a Serializable payload " +
"but received an object of type [" + object.getClass().getName() + "]");
}
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(object);
objectOutputStream.flush();
}
DefaultSerializer的serialize方法使用了ObjectOutputStream,調用writeObject方法序列化對象。
對應的,反序列化:
DeserializingConverter的convert方法,貼一下相關代碼:
public DeserializingConverter() {
this.deserializer = new DefaultDeserializer();
}
@Override
public Object convert(byte[] source) {
ByteArrayInputStream byteStream = new ByteArrayInputStream(source);
try {
return this.deserializer.deserialize(byteStream);
}
catch (Throwable ex) {
throw new SerializationFailedException("Failed to deserialize payload. " +
"Is the byte array a result of corresponding serialization for " +
this.deserializer.getClass().getSimpleName() + "?", ex);
}
}
可見DeserializingConverter使用了DefaultDeserializer作爲反序列化工具,調用了他的deserialize方法:
@Override
@SuppressWarnings("resource")
public Object deserialize(InputStream inputStream) throws IOException {
ObjectInputStream objectInputStream = new ConfigurableObjectInputStream(inputStream, this.classLoader);
try {
return objectInputStream.readObject();
}
catch (ClassNotFoundException ex) {
throw new NestedIOException("Failed to deserialize object type", ex);
}
}
對比SerializingConverter,DeserializingConverter使用的是ConfigurableObjectInputStream,並調用他的readObject方法進行反序列化。
這種序列化方式,如果保存信息至redis,用客戶端查看時,保存的信息看起來像是在原來的字符前面加了幾個字符。
比如:
JdkSerializationRedisSerializer jdkSerializer = new JdkSerializationRedisSerializer();
StringRedisSerializer stringSerializer = new StringRedisSerializer();
byte[] jdkByteArr = jdkSerializer.serialize("CSDN博客");
byte[] stringByteArr = stringSerializer.serialize("CSDN博客");
這種情況下,得到的byte數組是:
jdkByteArr:
{-84,-19,0,5,116,0,10,67,83,68,78,-27,-115,-102,-27,-82,-94}
stringByteArr:
{67,83,68,78,-27,-115,-102,-27,-82,-94}
StringRedisSerializer把字符串本身轉化成byte數組,而JdkSerializationRedisSerializer在數組前面加了幾個字符,這些字符也會被保存到redis中。
所以,從數據上來說,這兩種序列化策略處理的數據是不會共通的,各人管各人的。
四,關於redisTemplate的Operations
使用redisTemplate時,除了調用execute方法並自定義RedisCallback之外,還可以使用redisTemplate提供的幾個Operations接口。
redisTemplate中定義了以下幾個Operations:
@Nullable
private ValueOperations<K, V> valueOps;
@Nullable
private ListOperations<K, V> listOps;
@Nullable
private SetOperations<K, V> setOps;
@Nullable
private ZSetOperations<K, V> zSetOps;
@Nullable
private GeoOperations<K, V> geoOps;
@Nullable
private HyperLogLogOperations<K, V> hllOps;
這幾個Operations接口,分別提供了對不同種類數據的操作方法。
以ValueOperations爲例,他提供的方法有:
void set(K var1, V var2);
void set(K var1, V var2, long var3, TimeUnit var5);
@Nullable
Boolean setIfAbsent(K var1, V var2);
void multiSet(Map<? extends K, ? extends V> var1);
@Nullable
Boolean multiSetIfAbsent(Map<? extends K, ? extends V> var1);
@Nullable
V get(Object var1);
@Nullable
V getAndSet(K var1, V var2);
@Nullable
List<V> multiGet(Collection<K> var1);
@Nullable
Long increment(K var1, long var2);
@Nullable
Double increment(K var1, double var2);
@Nullable
Integer append(K var1, String var2);
@Nullable
String get(K var1, long var2, long var4);
void set(K var1, V var2, long var3);
@Nullable
Long size(K var1);
@Nullable
Boolean setBit(K var1, long var2, boolean var4);
@Nullable
Boolean getBit(K var1, long var2);
其他的Operations提供的方法各有不同,但是這些Operations的使用方式都是相同的。
不同的Operations分別通過RedisTemplate的以下方法獲取:
public ValueOperations<K, V> opsForValue() {
if (this.valueOps == null) {
this.valueOps = new DefaultValueOperations(this);
}
return this.valueOps;
}
public ListOperations<K, V> opsForList() {
if (this.listOps == null) {
this.listOps = new DefaultListOperations(this);
}
return this.listOps;
}
public SetOperations<K, V> opsForSet() {
if (this.setOps == null) {
this.setOps = new DefaultSetOperations(this);
}
return this.setOps;
}
public ZSetOperations<K, V> opsForZSet() {
if (this.zSetOps == null) {
this.zSetOps = new DefaultZSetOperations(this);
}
return this.zSetOps;
}
public GeoOperations<K, V> opsForGeo() {
if (this.geoOps == null) {
this.geoOps = new DefaultGeoOperations(this);
}
return this.geoOps;
}
可見,在這些獲得Operations的方法中,都提供了一個默認實現類,並且把RedisTemplate對象本身當做參數傳給了這個實現類。
還是以ValueOperations爲例,RedisTemplate提供的默認實現類是DefaultValueOperations,看看這個類的源碼:
package org.springframework.data.redis.core;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.AbstractOperations.ValueDeserializingRedisCallback;
class DefaultValueOperations<K, V> extends AbstractOperations<K, V> implements ValueOperations<K, V> {
DefaultValueOperations(RedisTemplate<K, V> template) {
super(template);
}
public V get(Object key) {
return this.execute(new AbstractOperations<K, V>.ValueDeserializingRedisCallback(key) {
protected byte[] inRedis(byte[] rawKey, RedisConnection connection) {
return connection.get(rawKey);
}
}, true);
}
public V getAndSet(K key, V newValue) {
final byte[] rawValue = this.rawValue(newValue);
return this.execute(new AbstractOperations<K, V>.ValueDeserializingRedisCallback(key) {
protected byte[] inRedis(byte[] rawKey, RedisConnection connection) {
return connection.getSet(rawKey, rawValue);
}
}, true);
}
public Long increment(K key, long delta) {
byte[] rawKey = this.rawKey(key);
return (Long)this.execute((connection) -> {
return connection.incrBy(rawKey, delta);
}, true);
}
public Double increment(K key, double delta) {
byte[] rawKey = this.rawKey(key);
return (Double)this.execute((connection) -> {
return connection.incrBy(rawKey, delta);
}, true);
}
public Integer append(K key, String value) {
byte[] rawKey = this.rawKey(key);
byte[] rawString = this.rawString(value);
return (Integer)this.execute((connection) -> {
Long result = connection.append(rawKey, rawString);
return result != null ? result.intValue() : null;
}, true);
}
public String get(K key, long start, long end) {
byte[] rawKey = this.rawKey(key);
byte[] rawReturn = (byte[])this.execute((connection) -> {
return connection.getRange(rawKey, start, end);
}, true);
return this.deserializeString(rawReturn);
}
public List<V> multiGet(Collection<K> keys) {
if (keys.isEmpty()) {
return Collections.emptyList();
} else {
byte[][] rawKeys = new byte[keys.size()][];
int counter = 0;
Object hashKey;
for(Iterator var4 = keys.iterator(); var4.hasNext(); rawKeys[counter++] = this.rawKey(hashKey)) {
hashKey = var4.next();
}
List<byte[]> rawValues = (List)this.execute((connection) -> {
return connection.mGet(rawKeys);
}, true);
return this.deserializeValues(rawValues);
}
}
public void multiSet(Map<? extends K, ? extends V> m) {
if (!m.isEmpty()) {
Map<byte[], byte[]> rawKeys = new LinkedHashMap(m.size());
Iterator var3 = m.entrySet().iterator();
while(var3.hasNext()) {
Entry<? extends K, ? extends V> entry = (Entry)var3.next();
rawKeys.put(this.rawKey(entry.getKey()), this.rawValue(entry.getValue()));
}
this.execute((connection) -> {
connection.mSet(rawKeys);
return null;
}, true);
}
}
public Boolean multiSetIfAbsent(Map<? extends K, ? extends V> m) {
if (m.isEmpty()) {
return true;
} else {
Map<byte[], byte[]> rawKeys = new LinkedHashMap(m.size());
Iterator var3 = m.entrySet().iterator();
while(var3.hasNext()) {
Entry<? extends K, ? extends V> entry = (Entry)var3.next();
rawKeys.put(this.rawKey(entry.getKey()), this.rawValue(entry.getValue()));
}
return (Boolean)this.execute((connection) -> {
return connection.mSetNX(rawKeys);
}, true);
}
}
public void set(K key, V value) {
final byte[] rawValue = this.rawValue(value);
this.execute(new AbstractOperations<K, V>.ValueDeserializingRedisCallback(key) {
protected byte[] inRedis(byte[] rawKey, RedisConnection connection) {
connection.set(rawKey, rawValue);
return null;
}
}, true);
}
public void set(K key, V value, final long timeout, final TimeUnit unit) {
final byte[] rawKey = this.rawKey(key);
final byte[] rawValue = this.rawValue(value);
this.execute(new RedisCallback<Object>() {
public Object doInRedis(RedisConnection connection) throws DataAccessException {
this.potentiallyUsePsetEx(connection);
return null;
}
public void potentiallyUsePsetEx(RedisConnection connection) {
if (!TimeUnit.MILLISECONDS.equals(unit) || !this.failsafeInvokePsetEx(connection)) {
connection.setEx(rawKey, TimeoutUtils.toSeconds(timeout, unit), rawValue);
}
}
private boolean failsafeInvokePsetEx(RedisConnection connection) {
boolean failed = false;
try {
connection.pSetEx(rawKey, timeout, rawValue);
} catch (UnsupportedOperationException var4) {
failed = true;
}
return !failed;
}
}, true);
}
public Boolean setIfAbsent(K key, V value) {
byte[] rawKey = this.rawKey(key);
byte[] rawValue = this.rawValue(value);
return (Boolean)this.execute((connection) -> {
return connection.setNX(rawKey, rawValue);
}, true);
}
public void set(K key, V value, long offset) {
byte[] rawKey = this.rawKey(key);
byte[] rawValue = this.rawValue(value);
this.execute((connection) -> {
connection.setRange(rawKey, rawValue, offset);
return null;
}, true);
}
public Long size(K key) {
byte[] rawKey = this.rawKey(key);
return (Long)this.execute((connection) -> {
return connection.strLen(rawKey);
}, true);
}
public Boolean setBit(K key, long offset, boolean value) {
byte[] rawKey = this.rawKey(key);
return (Boolean)this.execute((connection) -> {
return connection.setBit(rawKey, offset, value);
}, true);
}
public Boolean getBit(K key, long offset) {
byte[] rawKey = this.rawKey(key);
return (Boolean)this.execute((connection) -> {
return connection.getBit(rawKey, offset);
}, true);
}
}
所有Operations實現類都是AbstractOperations的子類,另外各自實現各自的接口。
實現類的方法中多數都是調用了this.execute()方法,這個方法在父類AbstractOperations中,最終調用的其實也是RedisTemplate的execute()方法。
以上面DefaultValueOperations的set()方法爲例,看一下代碼:
public void set(K key, V value) {
final byte[] rawValue = this.rawValue(value);
this.execute(new AbstractOperations<K, V>.ValueDeserializingRedisCallback(key) {
protected byte[] inRedis(byte[] rawKey, RedisConnection connection) {
connection.set(rawKey, rawValue);
return null;
}
}, true);
}
首先是對value的處理,調用this.rawValue()方法,把value序列化成byte數組,這個方法在父類AbstractOperations中:
byte[] rawValue(Object value) {
return this.valueSerializer() == null && value instanceof byte[] ? (byte[])((byte[])value) : this.valueSerializer().serialize(value);
}
可見,代碼用的是自己的valueSerializer來序列化value,這個valueSerializer來自RedisTemplate。
回到set()方法,value序列化完成後,調用this.execute()方法,給此方法傳遞的第一個參數是:
new AbstractOperations<K, V>.ValueDeserializingRedisCallback(key) {
protected byte[] inRedis(byte[] rawKey, RedisConnection connection) {
connection.set(rawKey, rawValue);
return null;
}
}
這個參數實際上是一個ValueDeserializingRedisCallback對象,在其中定義了inRedis()方法的實現。
this.execute()方法在父類AbstractOperations中:
@Nullable
<T> T execute(RedisCallback<T> callback, boolean b) {
return this.template.execute(callback, b);
}
其中this.template指的就是初始化時傳入的RedisTemplate,其execute()方法是這樣的:
@Nullable
public <T> T execute(RedisCallback<T> action, boolean exposeConnection) {
return this.execute(action, exposeConnection, false);
}
然後調用下面的方法:
@Nullable
public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline) {
Assert.isTrue(this.initialized, "template not initialized; call afterPropertiesSet() before using it");
Assert.notNull(action, "Callback object must not be null");
RedisConnectionFactory factory = this.getRequiredConnectionFactory();
RedisConnection conn = null;
Object var11;
try {
if (this.enableTransactionSupport) {
conn = RedisConnectionUtils.bindConnection(factory, this.enableTransactionSupport);
} else {
conn = RedisConnectionUtils.getConnection(factory);
}
boolean existingConnection = TransactionSynchronizationManager.hasResource(factory);
RedisConnection connToUse = this.preProcessConnection(conn, existingConnection);
boolean pipelineStatus = connToUse.isPipelined();
if (pipeline && !pipelineStatus) {
connToUse.openPipeline();
}
RedisConnection connToExpose = exposeConnection ? connToUse : this.createRedisConnectionProxy(connToUse);
T result = action.doInRedis(connToExpose);
if (pipeline && !pipelineStatus) {
connToUse.closePipeline();
}
var11 = this.postProcessResult(result, connToUse, existingConnection);
} finally {
RedisConnectionUtils.releaseConnection(conn, factory);
}
return var11;
}
方法初始化了RedisConnection,最後面調用了RedisCallback的doInRedis()方法,也就是這一行:
T result = action.doInRedis(connToExpose);
這裏的變量action就是在set()方法中自定義的new AbstractOperations<K, V>.ValueDeserializingRedisCallback(key)。
ValueDeserializingRedisCallback類是AbstractOperations的內部抽象類,他的doInRedis()方法是這樣的:
public final V doInRedis(RedisConnection connection) {
byte[] result = this.inRedis(AbstractOperations.this.rawKey(this.key), connection);
return AbstractOperations.this.deserializeValue(result);
}
可見調用了inRedis()方法,其第一個參數是序列化後的key,調用的是AbstractOperations的rawKey()方法,代碼如下:
byte[] rawKey(Object key) {
Assert.notNull(key, "non null key required");
return this.keySerializer() == null && key instanceof byte[] ? (byte[])((byte[])key) : this.keySerializer().serialize(key);
}
這裏把key進行序列化,keySerializer()方法從RedisTemplate中獲取keySerializer,並由keySerializer對key進行序列化。
在ValueDeserializingRedisCallback類中的inRedis()方法是抽象方法,具體的實現在DefaultValueOperations的set()方法中,也就是這一部分:
protected byte[] inRedis(byte[] rawKey, RedisConnection connection) {
connection.set(rawKey, rawValue);
return null;
}
最終調用的是RedisConnection的set()方法,完成Redis的set操作。
以上就是在RedisTemplate中使用ValueOperations進行set操作的全部代碼流程。
對Redis的不同操作分散在RedisTemplate的不同Operations中,只是調用的方法不同,調用流程都差不多。
完