springboot redisTemplate序列化与反序列化

2022-07-17 10:15:31

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方法
  • 作者:Pingszi
  • 原文链接:https://blog.csdn.net/zhouping118/article/details/106103216
    更新时间:2022-07-17 10:15:31