SpringBoot结合Redis实现序列化的方法详解

作者:陕西颜值扛把子 时间:2023-06-11 15:11:40 

前言

最近在学习Spring Boot结合Redis时看了一些网上的教程,发现这些教程要么比较老,要么不知道从哪抄得,运行起来有问题。这里分享一下我最新学到的写法

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

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

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

SpringBoot结合Redis实现序列化的方法详解

https://docs.spring.io/spring-data/redis/docs/2.2.5.RELEASE/reference/html/#redis:serializer

配置类

配置 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提示我

SpringBoot结合Redis实现序列化的方法详解

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

SpringBoot结合Redis实现序列化的方法详解

SpringBoot结合Redis实现序列化的方法详解

导致数据无法反序列化。

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

SpringBoot结合Redis实现序列化的方法详解

SpringBoot结合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中的数据

SpringBoot结合Redis实现序列化的方法详解

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

完整代码

package com.buguagaoshu.redis.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

/**
* @author Pu Zhiwei {@literal puzhiweipuzhiwei@foxmail.com}
* create          2020-03-17 21:08
* 继承 CachingConfigurerSupport,为了自定义生成 KEY 的策略。可以不继承。
*/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
   @Value("${spring.cache.redis.time-to-live}")
   private Duration timeToLive = Duration.ZERO;

/**
    * 配置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);

objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
       objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);

jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
       return jackson2JsonRedisSerializer;
   }

@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();
   }
}

来源:https://www.cnblogs.com/puzhiwei/p/12519304.html

标签:SpringBoot,Redis,序列化
0
投稿

猜你喜欢

  • Java 数据结构与算法系列精讲之单向链表

    2023-07-10 08:22:12
  • java抛出异常的几种情况小结

    2022-01-11 05:46:40
  • Android需要提升权限的操作方法

    2021-07-17 11:25:47
  • GateWay动态路由与负载均衡详细介绍

    2022-02-10 15:12:29
  • java跟踪执行的sql语句示例分享

    2022-07-30 20:13:18
  • Mybatis Plus使用XML编写动态sql的超简易方法

    2022-02-20 01:49:16
  • C#检测远程计算机端口是否打开的方法

    2023-12-11 08:55:31
  • Android动态加载布局实现技巧介绍

    2022-03-06 13:31:48
  • Java设计模式之状态模式

    2022-05-08 07:24:25
  • 解析Java程序中对象内存的分配和控制的基本方法

    2023-01-07 21:46:10
  • 教你如何用C#制作文字转换成声音程序

    2022-01-15 07:14:40
  • Java 并发编程之线程挂起、恢复与终止

    2022-02-18 11:51:51
  • java容器详细解析

    2023-08-23 16:13:38
  • 详解Android studio中正确引入so文件的方法

    2022-06-17 23:21:32
  • java异常处理执行顺序详解try catch finally

    2022-10-01 04:10:10
  • java的各种类型转换全部汇总(推荐)

    2022-03-01 01:25:43
  • 排序算法图解之Java冒泡排序及优化

    2022-07-16 01:28:38
  • Mybatis @SelectKey用法解读

    2022-04-18 18:01:35
  • C#导出数据到CSV文件的通用类实例

    2023-05-22 09:23:16
  • 深入谈谈C#9新特性的实际运用

    2021-05-26 16:08:23
  • asp之家 软件编程 m.aspxhome.com