Spring Boot 结合 Redis 的序列化配置
默认情况下,Spring 为我们提供了一个 RedisTemplate 来进行对 Redis 的操作,但是 RedisTemplate 默认配置的是使用Java本机序列化。
这种序列化方式,对于操作字符串或数字来说,用起来还行,但是如果要对对象操作,就不是那么的方便了。
所以我们需要配置合适的序列化方式。在 Spring 官方的文档中,官方也建议了我们使用其他的方式来进行序列化。比如JSON
配置类
配置 Jackson2JsonRedisSerializer 序列化策略
下面就开始自动配置类的书写
我使用的是 Jackson2JsonRedisSerializer 来对对象进行序列化,所以首先需要一个方法,来配置 Jackson2JsonRedisSerializer 序列化策略
private Jackson2JsonRedisSerializer<Object> serializer() { // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值 Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); ObjectMapper objectMapper = new ObjectMapper(); // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常 objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(objectMapper); return jackson2JsonRedisSerializer; }
这里要注意的是
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
这一句,这一句非常的重要,作用是序列化时将对象全类名一起保存下来
设置之后的序列化结果如下:
[ "com.buguagaoshu.redis.model.User", { "name": "1", "age": "11", "message": "牛逼" } ]
不设置的话,序列化结果如下,将无法反序列化
{ "name": "1", "age": "11", "message": "牛逼" }
网上大多数教程因为时间的原因,这一句用的是
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
但当把这段代码写入的时候,发现Idea提示,这是一个过时的方法,由于我当时并不知道这句话的意思,就把这段代码注释了,觉得可能没什么用,但注释后在向Redis里写数据的时候,数据会变成
导致数据无法反序列化。
最后我查看了这个方法的源码,找到了
通过注释,我得到了这段代码的最新写法。
也明白了这段代码的作用。
配置 RedisTemplate
@Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); // 用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值 redisTemplate.setValueSerializer(serializer()); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // 使用StringRedisSerializer来序列化和反序列化redis的key值 redisTemplate.setKeySerializer(stringRedisSerializer); // hash的key也采用String的序列化方式 redisTemplate.setHashKeySerializer(stringRedisSerializer); // hash的value序列化方式采用jackson redisTemplate.setHashValueSerializer(serializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; }
这里就没有什么需要注意的了,按照自己的需求,来配置序列化的方式
配置缓存策略
@Bean public CacheManager cacheManager(RedisConnectionFactory factory) { RedisSerializer<String> redisSerializer = new StringRedisSerializer(); // 配置序列化(解决乱码的问题) RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() // 缓存有效期 .entryTtl(timeToLive) // 使用StringRedisSerializer来序列化和反序列化redis的key值 .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)) // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer())) // 禁用空值 .disableCachingNullValues(); return RedisCacheManager.builder(factory) .cacheDefaults(config) .build(); }
测试代码
@SpringBootTest public class RedisApplicationTests { @Autowired private RedisTemplate<String, Object> redisTemplate; @Test void contextLoads() throws Exception { User user = new User(); user.setName("15"); user.setAge(20); user.setMessage("牛逼"); redisTemplate.opsForValue().set(user.getName(), user); User getUser = (User) redisTemplate.opsForValue().get(user.getName()); System.out.println(getUser); System.out.println(getUser.getMessage()); } }
再来查看Redis中的数据
数据正常,并且系统也能正常的反序列化了。
完整代码
1 package com.buguagaoshu.redis.config; 2 3 4 import com.fasterxml.jackson.annotation.JsonAutoDetect; 5 import com.fasterxml.jackson.annotation.PropertyAccessor; 6 import com.fasterxml.jackson.databind.ObjectMapper; 7 import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; 8 import org.springframework.beans.factory.annotation.Value; 9 import org.springframework.cache.CacheManager; 10 import org.springframework.cache.annotation.CachingConfigurerSupport; 11 import org.springframework.cache.annotation.EnableCaching; 12 import org.springframework.context.annotation.Bean; 13 import org.springframework.context.annotation.Configuration; 14 import org.springframework.data.redis.cache.RedisCacheConfiguration; 15 import org.springframework.data.redis.cache.RedisCacheManager; 16 import org.springframework.data.redis.connection.RedisConnectionFactory; 17 import org.springframework.data.redis.core.RedisTemplate; 18 import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 19 import org.springframework.data.redis.serializer.RedisSerializationContext; 20 import org.springframework.data.redis.serializer.RedisSerializer; 21 import org.springframework.data.redis.serializer.StringRedisSerializer; 22 23 import java.time.Duration; 24 25 /** 26 * @author Pu Zhiwei {@literal puzhiweipuzhiwei@foxmail.com} 27 * create 2020-03-17 21:08 28 * 继承 CachingConfigurerSupport,为了自定义生成 KEY 的策略。可以不继承。 29 */ 30 @Configuration 31 @EnableCaching 32 public class RedisConfig extends CachingConfigurerSupport { 33 @Value("${spring.cache.redis.time-to-live}") 34 private Duration timeToLive = Duration.ZERO; 35 36 /** 37 * 配置Jackson2JsonRedisSerializer序列化策略 38 * */ 39 private Jackson2JsonRedisSerializer<Object> serializer() { 40 // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值 41 Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); 42 ObjectMapper objectMapper = new ObjectMapper(); 43 44 // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public 45 objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); 46 47 objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); 48 49 // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常 50 objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); 51 52 jackson2JsonRedisSerializer.setObjectMapper(objectMapper); 53 return jackson2JsonRedisSerializer; 54 } 55 56 57 @Bean 58 public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { 59 RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); 60 redisTemplate.setConnectionFactory(redisConnectionFactory); 61 // 用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值 62 redisTemplate.setValueSerializer(serializer()); 63 64 StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); 65 // 使用StringRedisSerializer来序列化和反序列化redis的key值 66 redisTemplate.setKeySerializer(stringRedisSerializer); 67 68 // hash的key也采用String的序列化方式 69 redisTemplate.setHashKeySerializer(stringRedisSerializer); 70 // hash的value序列化方式采用jackson 71 redisTemplate.setHashValueSerializer(serializer()); 72 redisTemplate.afterPropertiesSet(); 73 return redisTemplate; 74 } 75 76 77 78 79 @Bean 80 public CacheManager cacheManager(RedisConnectionFactory factory) { 81 RedisSerializer<String> redisSerializer = new StringRedisSerializer(); 82 // 配置序列化(解决乱码的问题) 83 RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() 84 // 缓存有效期 85 .entryTtl(timeToLive) 86 // 使用StringRedisSerializer来序列化和反序列化redis的key值 87 .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)) 88 // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值 89 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer())) 90 // 禁用空值 91 .disableCachingNullValues(); 92 93 return RedisCacheManager.builder(factory) 94 .cacheDefaults(config) 95 .build(); 96 } 97 }
参考:https://www.cnblogs.com/puzhiwei/p/12519304.html