• 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();
        }
    }
    
  • 相关阅读:
    写个比较通用的makefile
    十款原型设计工具
    网站色彩搭配
    [导入]用我的MyGeneration模板生成NHibernate映射文件和关系(onetoone,onetomany,manytomany)
    概要设计与详细设计
    原型设计样图
    PHPUnit安装
    php去掉字符串的最后一个字符 substr()的用法
    文档阅读器开发思路
    非原型 不设计
  • 原文地址:https://www.cnblogs.com/jiangdewen/p/15433126.html
Copyright © 2020-2023  润新知