2.springboot-reids redisTemplate序列化與反序列化

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方法
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章