前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring Boot 结合 Redis 的序列化配置

Spring Boot 结合 Redis 的序列化配置

作者头像
Vincent-yuan
发布2021-10-28 10:59:36
3.9K0
发布2021-10-28 10:59:36
举报
文章被收录于专栏:Vincent-yuan

默认情况下,Spring 为我们提供了一个 RedisTemplate 来进行对 Redis 的操作,但是 RedisTemplate 默认配置的是使用Java本机序列化。

这种序列化方式,对于操作字符串或数字来说,用起来还行,但是如果要对对象操作,就不是那么的方便了。

所以我们需要配置合适的序列化方式。在 Spring 官方的文档中,官方也建议了我们使用其他的方式来进行序列化。比如JSON

配置类

配置 Jackson2JsonRedisSerializer 序列化策略

下面就开始自动配置类的书写

我使用的是 Jackson2JsonRedisSerializer 来对对象进行序列化,所以首先需要一个方法,来配置 Jackson2JsonRedisSerializer 序列化策略

代码语言:javascript
复制
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;
    }

这里要注意的是

代码语言:javascript
复制
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);

这一句,这一句非常的重要,作用是序列化时将对象全类名一起保存下来

设置之后的序列化结果如下:

代码语言:javascript
复制
[
    "com.buguagaoshu.redis.model.User",
    {
        "name": "1",
        "age": "11",
        "message": "牛逼"
    }
]

不设置的话,序列化结果如下,将无法反序列化

代码语言:javascript
复制
    {
        "name": "1",
        "age": "11",
        "message": "牛逼"
    }

网上大多数教程因为时间的原因,这一句用的是

代码语言:javascript
复制
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

但当把这段代码写入的时候,发现Idea提示,这是一个过时的方法,由于我当时并不知道这句话的意思,就把这段代码注释了,觉得可能没什么用,但注释后在向Redis里写数据的时候,数据会变成

导致数据无法反序列化。

最后我查看了这个方法的源码,找到了

通过注释,我得到了这段代码的最新写法。

也明白了这段代码的作用。

配置 RedisTemplate

代码语言:javascript
复制
    @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;
    }

这里就没有什么需要注意的了,按照自己的需求,来配置序列化的方式

配置缓存策略

代码语言:javascript
复制
    @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();
    }

测试代码

代码语言:javascript
复制
@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中的数据

数据正常,并且系统也能正常的反序列化了。

完整代码

代码语言:javascript
复制
 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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-10-26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 配置类
    • 配置 Jackson2JsonRedisSerializer 序列化策略
      • 配置 RedisTemplate
        • 配置缓存策略
        • 测试代码
        • 完整代码
        相关产品与服务
        文件存储
        文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档