redis 序列化


前言

redis版本的變更對於spring封裝的java API影響不大,集成也沒什么難度。重要的是序列化方面需要注意。
本次 spring-data-redis版本為2.5.5

序列化

spring-data-redis的序列化統統派生於 org.springframework.data.redis.serializer.RedisSerializer 接口
image
最終入redis都會是字節數組,但是不同的序列化器會進行不同的序列化策略,有的先轉換jackson對象,再將該對象以字節數組的方式入redis。

  1. ByteArrayRedisSerializer 對象 <——> 字節數組
  2. GenericJackson2JsonRedisSerializer 對象 <——> jackson2Json對象
  3. GenericToStringSerializer 對象 <——> 字符串
  4. Jackson2JsonRedisSerializer 對象 <——> jackson2Json對象
  5. JdkSerializationRedisSerializer 對象 <——> 字節數組
  6. OxmSerializer 對象 <——> Spring's O/X Mapping
  7. StringRedisSerializer 對象 <——> 字符串

着重說三類

字符串序列化

  1. StringRedisSerializer
  2. GenericToStringSerializer
    兩個都是字符串序列化使用,只是GenericToStringSerializer多了一個轉換器操作。
// GenericToStringSerializer先將對象通過傳喚器轉換成字符串,再(指定編碼)獲得字節數組
	@Override
	public T deserialize(@Nullable byte[] bytes) {

		if (bytes == null) {
			return null;
		}

		String string = new String(bytes, charset);
		return converter.convert(string, type);
	}

	@Override
	public byte[] serialize(@Nullable T object) {
		if (object == null) {
			return null;
		}
		String string = converter.convert(object, String.class);
		return string.getBytes(charset);
	}

// StringRedisSerializer直接進行字符串與字節數組(指定編碼)轉換操作,charset默認默認為UTF8
	 */
	@Override
	public String deserialize(@Nullable byte[] bytes) {
		return (bytes == null ? null : new String(bytes, charset));
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.serializer.RedisSerializer#serialize(java.lang.Object)
	 */
	@Override
	public byte[] serialize(@Nullable String string) {
		return (string == null ? null : string.getBytes(charset));
	}

JSON序列化

有時候我們想直接在redis相關的UI界面(RDM等)直觀的看到數據,而我們的數組通常都是對象的形式存在,此時我們就可以使用先將原始java對象轉為json對象,再由json對象轉字節數組入redis

  1. Jackson2JsonRedisSerializer
  2. GenericJackson2JsonRedisSerializer
    兩者的區別:
    GenericJackson2JsonRedisSerializer有個構造方法可以使用給定名稱為默認類型配置ObjectMapper,或者配置默認的ObjectMapper
    Jackson2JsonRedisSerializer不管ObjectMapper怎么來的,只管用。
    兩種方式最終的操作都是ObejctMapper對象,只要ObjectMapper對象一樣,兩者沒有任何區別
    此處由於GenericJackson2JsonRedisSerializer構造方法里面使用默認ObjectMapper的方式調用了過時方法,所以下文案例將采用Jackson2JsonRedisSerializer
    image

image

JDK序列化

  1. JdkSerializationRedisSerializer
    不配置序列化方式,則會采用的默認序列化規則,上面的兩種json序列化方式有個問題,就是反序列化的時候強依賴於對象是否由標准的構造方法,對於某些框架對象而言,都是有特定的流程場景使用的,例如Spring Securit的Authorization對象。如果使用上面的json序列化方式的話,會反序列化出錯。
org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Cannot construct instance of `org.springframework.security.authentication.UsernamePasswordAuthenticationToken` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

此時我們就可以使用JDK序列化,不便的是我們無法直接在redis UI界面直觀的看數據值。

附上本人的redis配置

package com.example.demo;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @author ListJiang
 * @since 2021/10/21
 * description redis配置
 */
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {

        // RedisTemplate
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();

        // 序列化配置
        RedisSerializer<Object> jdkSerializer = jdkSerializer();
        RedisSerializer<String> stringSerializer = new StringRedisSerializer();
        // String
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(jdkSerializer);
        // Hash
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(jdkSerializer);

        // 連接工廠配置
        redisTemplate.setConnectionFactory(lettuceConnectionFactory);
        redisTemplate.afterPropertiesSet();

        return redisTemplate;
    }

    private Jackson2JsonRedisSerializer jackson2JsonSerializer() {
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
                ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        return jackson2JsonRedisSerializer;
    }

    private JdkSerializationRedisSerializer jdkSerializer() {
        return new JdkSerializationRedisSerializer();
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM