1.序列化與反序列化
1、序列化和反序列化簡介:
- 序列化就是指把對象轉換爲字節碼;
- 對象傳遞和保存時,保證對象的完整性和可傳遞性。把對象轉換爲有字節碼,以便在網絡上傳輸或保存在本地文件中;
- 反序列化就是指把字節碼恢復爲對象;
- 根據字節流中保存的對象狀態及描述信息,通過反序列化重建對象;
2.redis序列化與反序列化
- redis底層以二進制/字符串形式存儲內容;
- 序列化
- 把java對象轉換爲二進制/字符串,然後存儲到內存中;
- 反序列化
- 讀取內存中的二進制/字符串,然後轉換爲java對象;
3.RedisTemplate序列化與反序列化
- 序列化的相關屬性
//**是否初始化,需調用afterPropertiesSet進行初始化,執行redis命令時會判斷是否已經初始化
private boolean initialized = false;
//**啓用默認的序列化
private boolean enableDefaultSerializer = true;
//**默認的序列化器
private @Nullable RedisSerializer<?> defaultSerializer;
//**key序列化器
@SuppressWarnings("rawtypes") private @Nullable RedisSerializer keySerializer = null;
//**value序列化器
@SuppressWarnings("rawtypes") private @Nullable RedisSerializer valueSerializer = null;
//**hash key序列化器,在hash類型的hash key和stream類型field中使用
@SuppressWarnings("rawtypes") private @Nullable RedisSerializer hashKeySerializer = null;
//**hash value序列化器,在hash類型value和stream類型value中使用
@SuppressWarnings("rawtypes") private @Nullable RedisSerializer hashValueSerializer = null;
//**字符串序列化器,在redis發佈訂單模式發佈消息時,序列化channel
private RedisSerializer<String> stringSerializer = RedisSerializer.string();
//**操作string類型
private final ValueOperations<K, V> valueOps = new DefaultValueOperations<>(this);
//**操作list類型
private final ListOperations<K, V> listOps = new DefaultListOperations<>(this);
//**操作set類型
private final SetOperations<K, V> setOps = new DefaultSetOperations<>(this);
//**操作stream流類型
private final StreamOperations<K, ?, ?> streamOps = new DefaultStreamOperations<>(this, new ObjectHashMapper());
//**操作zset類型
private final ZSetOperations<K, V> zSetOps = new DefaultZSetOperations<>(this);
//**操作geo地理位置類型
private final GeoOperations<K, V> geoOps = new DefaultGeoOperations<>(this);
//**操作hyperLogLog類型
private final HyperLogLogOperations<K, V> hllOps = new DefaultHyperLogLogOperations<>(this);
//**操作cluster集羣
private final ClusterOperations<K, V> clusterOps = new DefaultClusterOperations<>(this);
@Override
public <T> T execute(SessionCallback<T> session) {
//**執行redis命令時會判斷是否已經初始化,需調用afterPropertiesSet進行初始化
Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it");
...
}
- afterPropertiesSet初始化序列化屬性
@Override
public void afterPropertiesSet() {
//**調用父類的afterPropertiesSet方法,判斷是否初始化redis連接工廠
super.afterPropertiesSet();
boolean defaultUsed = false;
//**如果沒的設置默認的序列化器,則使用jdk序列化器爲默認的序列化器,可調用setDefaultSerializer設置默認的序列化器
if (defaultSerializer == null) {
defaultSerializer = new JdkSerializationRedisSerializer(
classLoader != null ? classLoader : this.getClass().getClassLoader());
}
if (enableDefaultSerializer) {
//**如果啓用默認的序列化,且沒有設置key序列化器,則使用默認的序列化器爲key的序列化器
if (keySerializer == null) {
keySerializer = defaultSerializer;
defaultUsed = true;
}
//**如果啓用默認的序列化,且沒有設置value序列化器,則使用默認的序列化器爲value的序列化器
if (valueSerializer == null) {
valueSerializer = defaultSerializer;
defaultUsed = true;
}
//**如果啓用默認的序列化,且沒有設置key序列化器,則使用默認的序列化器爲hash key的序列化器
if (hashKeySerializer == null) {
hashKeySerializer = defaultSerializer;
defaultUsed = true;
}
//**如果啓用默認的序列化,且沒有設置value序列化器,則使用默認的序列化器爲hash value的序列化器
if (hashValueSerializer == null) {
hashValueSerializer = defaultSerializer;
defaultUsed = true;
}
}
//**啓用默認的序列化,則默認的序列化器不能不空
if (enableDefaultSerializer && defaultUsed) {
Assert.notNull(defaultSerializer, "default serializer null and not all serializers initialized");
}
//**如果沒有設置redis腳本執行器,則設置redis腳本執行器爲DefaultScriptExecutor
if (scriptExecutor == null) {
this.scriptExecutor = new DefaultScriptExecutor<>(this);
}
//**設置已初始化
initialized = true;
}
//**設置默認的序列化器
public void setDefaultSerializer(RedisSerializer<?> serializer) {
this.defaultSerializer = serializer;
}
- 使用
- 執行寫入,先調用對應的序列化器,把key/value序列化爲二進制碼,然後在保存到redis中
- 執行讀取,先根據key獲取value的二進制碼,然後調用value序列化器反序化爲java對象
- string類型的序列化和反序列化
- 首先調用DefaultValueOperations的set/get方法保存/獲取鍵值對
//**保存 @Override public void set(K key, V value) { //**使用value序列化器把value轉換成二進制碼 byte[] rawValue = rawValue(value); //**創建匿名內部類實現ValueDeserializingRedisCallback,然後調用redistemplate的execute方法 execute(new ValueDeserializingRedisCallback(key) { //**把序列化後的key和value的二進制碼保存到redis中 @Override protected byte[] inRedis(byte[] rawKey, RedisConnection connection) { connection.set(rawKey, rawValue); return null; } }, true); } //**獲取 @Override public V get(Object key) { //**創建匿名內部類實現ValueDeserializingRedisCallback,然後調用redistemplate的execute方法 return execute(new ValueDeserializingRedisCallback(key) { //**把根據序列化後的key獲和value的二進制碼 @Override protected byte[] inRedis(byte[] rawKey, RedisConnection connection) { return connection.get(rawKey); } }, true); } //**使用key序列化器把key轉換成二進制碼 @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); } //**使用value序列化器把value轉換成二進制碼 @SuppressWarnings("unchecked") private byte[] rawValue(Object value) { if (valueSerializer == null && value instanceof byte[]) { return (byte[]) value; } return valueSerializer.serialize(value); }
- Redistemplate的execute方法調用ValueDeserializingRedisCallback的doInRedis方法
@Nullable public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline) { ... //**調用ValueDeserializingRedisCallback的doInRedis方法,返回執行的結果 T result = action.doInRedis(connToExpose); ... }
- ValueDeserializingRedisCallback.doInRedis方法調用inRedis方法
public final V doInRedis(RedisConnection connection) { //**調用inRedis方法,把序列化後的key和value的二進制碼保存到redis中(set方法會返回null) byte[] result = inRedis(rawKey(key), connection); //**使用value序列化器把二進制的value反序列化爲java對象 return deserializeValue(result); } //**使用value序列化器把二進制的value反序列化爲java對象 @SuppressWarnings("unchecked") V deserializeValue(byte[] value) { if (valueSerializer() == null) { return (V) value; } return (V) valueSerializer().deserialize(value); }
- hash類型的序列化和反序列化
- Redistemplate沒有爲hash類型設置一個成員屬性
@Override public <HK, HV> HashOperations<K, HK, HV> opsForHash() { return new DefaultHashOperations<>(this); }
- 首先調用DefaultHashOperations的put/get方法保存/獲取鍵值對
//**獲取 @Override @SuppressWarnings("unchecked") public HV get(K key, Object hashKey) { //**使用key序列化器把key轉換成二進制碼 byte[] rawKey = rawKey(key); //**使用hash key序列化器把hashKey轉換成二進制碼 byte[] rawHashKey = rawHashKey(hashKey); //**lambda表達式實現RedisCallback接口,然後調用redistemplate的execute方法,根據key和hashKey獲取value的二進制碼 byte[] rawHashValue = execute(connection -> connection.hGet(rawKey, rawHashKey), true); //**使用hash value序列化器把二進制碼的value反序列化爲java對象 return (HV) rawHashValue != null ? deserializeHashValue(rawHashValue) : null; } //**保存 @Override public void put(K key, HK hashKey, HV value) { //**使用key序列化器把key轉換成二進制碼 byte[] rawKey = rawKey(key); //**使用hash key序列化器把hashKey轉換成二進制碼 byte[] rawHashKey = rawHashKey(hashKey); //**使用hash value序列化器把value轉換成二進制碼 byte[] rawHashValue = rawHashValue(value); //**lambda表達式實現RedisCallback接口,然後調用redistemplate的execute方法,把序列化後的key、hashKey和value的二進制碼保存到redis中 execute(connection -> { connection.hSet(rawKey, rawHashKey, rawHashValue); return null; }, true); } //**使用hash key序列化器把hashKey轉換成二進制碼 @SuppressWarnings("unchecked") <HK> byte[] rawHashKey(HK hashKey) { Assert.notNull(hashKey, "non null hash key required"); if (hashKeySerializer() == null && hashKey instanceof byte[]) { return (byte[]) hashKey; } return hashKeySerializer().serialize(hashKey); } //**使用hash value序列化器把value轉換成二進制碼 @SuppressWarnings("unchecked") <HV> byte[] rawHashValue(HV value) { if (hashValueSerializer() == null && value instanceof byte[]) { return (byte[]) value; } return hashValueSerializer().serialize(value); } //**使用hash value序列化器把二進制碼的value反序列化爲java對象 @SuppressWarnings("unchecked") <HV> HV deserializeHashValue(byte[] value) { if (hashValueSerializer() == null) { return (HV) value; } return (HV) hashValueSerializer().deserialize(value); }
- Redistemplate的execute方法調用的RedisCallback接口doInRedis方法