【RedisUtils工具类专题】Jackson2JsonRedisSerializer和GenericFastJsonRedisSerializer的对比分析



前言

在SpringBoot中使用Redis数据库时,如果RedisSerializer使用JdkSerializationRedisSerializer(默认值),需要被序列化Class实现Serializable接口,而且Redis数据库中数据很不直观(下图为Redis中存储的User类),不利于程序的调试和使用。

代码如下(以User为例,需实现Serializable接口):

User user = new User();
user.setId("1");
user.setUsername("zs");
user.setPassword("123");
RedisUtils.set("key",user);
User valueRedis = (User)RedisUtils.get("key");

Redis中存储结果如下:

Redis中的key:\xac\xed\x00\x05t\x00\x03key
Redis中的value:\xac\xed\x00\x05sr\x00\x1ecom.carl.security.entity.User1\xa1\xfd\xa2\xa8\xddV\xce\xc0\x02\x00\x03L\x00\x02idt\x00\x12Ljava/lang/String;L\x00\x08passwordq\x00~\x00\x01L\x00\x08usernameq\x00~\x00\x01xpt\x00\x011t\x00\x03123t\x00\x02zs


一、常用的RedisSerializer介绍

目前常用的RedisSerializer包括:JdkSerializationRedisSerializer(默认值)、StringRedisSerializer、Jackson2JsonRedisSerializer/GenericJackson2JsonRedisSerializer、GenericFastJsonRedisSerializer(来自com.alibaba.fastjson.support.spring包)等,正如前言所说,JdkSerializationRedisSerializer面临各种问题,所以这里主要介绍Jackson2JsonRedisSerializer和GenericFastJsonRedisSerializer两种RedisSerializer的特点与不足。
提示:本文中对于key都采用StringRedisSerializer进行序列化。

二、Jackson2JsonRedisSerializer的特点

1.将RedisSerializer改为Jackson2JsonRedisSerializer

代码如下:

@Component
public class RedisUtils {
    private static RedisTemplate<String, Object> redisTemplate;
    public static RedisTemplate<String, Object> getRedisTemplate() {
        return redisTemplate;
    }
    @Autowired
    private RedisUtils(RedisConnectionFactory redisConnectionFactory){
        //为了方便,一般直接使用<String,Object>
        redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // String的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // 将对象序列化
        ObjectMapper om=new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
                ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        // json序列化配置
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer=new Jackson2JsonRedisSerializer<>(Object.class);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        //key采用String的序列化方式
        redisTemplate.setKeySerializer(stringRedisSerializer);
        //hash的key也采用String 的序列化方式
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        //value的序列化方式采用jackson的方式
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        //hash的value序列化方式采用jackson
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
    }
    public static boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    public static Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }
}

2.序列化和反序列化Object类(以User为例,不实现Serializable接口)

Redis中存储结果如下:

Redis中的key:key
Redis中的value:{"@class": “com.carl.security.entity.User”, “id”: “1”, “username”: “zs”, “password”: “123”}
其序列化和反序列化都可正常进行。

3.序列化和反序列化String类

代码如下:

RedisUtils.set("key","value");
String valueRedis = (String) RedisUtils.get("key");

Redis中存储结果如下:

Redis中的key:key
Redis中的value:value
其序列化和反序列化都可正常进行。

4.序列化和反序列化Object类数组

代码如下:

User[] value = new User[]{user,user};
RedisUtils.set("key","value");
User[] valueRedis = (User[])RedisUtils.get("key");

Redis中存储结果如下:

Redis中的key:key
Redis中的value:
[
“[Lcom.carl.security.entity.User1;”,
[
{
“@class”: “com.carl.security.entity.User1”,
“id”: “1”,
“username”: “zs”,
“password”: “123”
},
{
“@class”: “com.carl.security.entity.User1”,
“id”: “1”,
“username”: “zs”,
“password”: “123”
}
]
]

其序列化和反序列化都可正常进行。

5.序列化和反序列化String数组

代码如下:

String[] value = new String[]{"a","b","c","d"};
RedisUtils.set("key", value);
String[] valueRedis = (String[])RedisUtils.get("key");

Redis中存储结果如下:

Redis中的key:key
Redis中的value:[“a”, “b”, “c”, “d”]
其序列化可正常进行,但是反序列化有问题,异常信息如下:

Caused by: com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'a' as a subtype of `java.lang.Object`: no such class found
 at [Source: (byte[])"["a","b","c","d"]"; line: 1, column: 6]

综合上一节结论,可以发现:Jackson2JsonRedisSerializer对String数组进行序列化时会省略其类型的描述,直接进行存储,因此导致反序列化时认为“a”是一个类型参数,导致反序列化失败,该问题作者暂未发现解决方法

三、GenericFastJsonRedisSerializer的特点

1.将RedisSerializer改为GenericFastJsonRedisSerializer

代码如下:

@Component
public class RedisUtils {
    private static RedisTemplate<String, Object> redisTemplate;
    public static RedisTemplate<String, Object> getRedisTemplate() {
        return redisTemplate;
    }
    @Autowired
    private RedisUtils(RedisConnectionFactory redisConnectionFactory){
        //为了方便,一般直接使用<String,Object>
        redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // String的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // json序列化配置
        GenericFastJsonRedisSerializer jackson2JsonRedisSerializer = new GenericFastJsonRedisSerializer();
        //key采用String的序列化方式
        redisTemplate.setKeySerializer(stringRedisSerializer);
        //hash的key也采用String 的序列化方式
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        //value的序列化方式采用jackson的方式
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        //hash的value序列化方式采用jackson
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
    }
    public static boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    public static Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }
}

2.序列化和反序列化Object类(以User为例,不实现Serializable接口)

Redis中存储结果如下:

Redis中的key:key
Redis中的value:{"@type": “com.carl.security.entity.User”, “id”: “1”, “username”: “zs”, “password”: “123”}
其序列化和反序列化都可正常进行。

3.序列化和反序列化String类

代码如下:

RedisUtils.set("key","value");
String valueRedis = (String) RedisUtils.get("key");

Redis中存储结果如下:

Redis中的key:key
Redis中的value:value
其序列化和反序列化都可正常进行。

4.序列化和反序列化Object类数组

代码如下:

User[] value = new User[]{user,user};
RedisUtils.set("key","value");
User[] valueRedis = (User[])RedisUtils.get("key");

Redis中存储结果如下:

Redis中的key:key
Redis中的value:
[
{
“@type”: “com.carl.security.entity.User”,
“id”: “1”,
“password”: “123”,
“username”: “zs”
},
{
“$ref”: “$[0]”
}
]

其序列化可正常进行,但是反序列化报异常,异常信息如下:

java.lang.ClassCastException: com.alibaba.fastjson.JSONArray cannot be cast to [Lcom.carl.security.entity.User;

从异常信息我们可以看出,GenericFastJsonRedisSerializer是将数组反序列化为JSONArray ,查看JSONArray类的定义就可以看出其是一种List集合,所以将其强转为User数组就会报错。

public class JSONArray extends JSON implements List<Object>, Cloneable, RandomAccess, Serializable {
......
}

修改反序列化后的强转类型,就没有异常信息了。

List<User> valueRedis = (List<User>)RedisUtils.get("key");

5.序列化和反序列化String数组

代码如下:

String[] value = new String[]{"a","b","c","d"};
RedisUtils.set("key", value);
List<String> valueRedis = (List<String>)RedisUtils.get("key");

Redis中存储结果如下:

Redis中的key:key
Redis中的value:[“a”, “b”, “c”, “d”]
其序列化和反序列化都可正常进行。


总结

本文对几种常见的RedisSerializer进行对比分析,总结出Jackson2JsonRedisSerializer和GenericFastJsonRedisSerializer的技术特点和目前遇到的问题,结论如下:

  1. Jackson2JsonRedisSerializer对String数组进行序列化时会省略其类型的描述,直接进行存储,因此导致反序列化时认为“a”是一个类型参数,导致反序列化失败(该问题作者暂未发现解决方法);
  2. GenericFastJsonRedisSerializer是将数组反序列化为JSONArray ,查看JSONArray类的定义就可以看出其是一种List集合,所以需要注意其强转的数据类型;
  3. 鉴于遇到的问题以及配置的复杂难度,建议选用GenericFastJsonRedisSerializer作为RedisSerializer。
### 回答1: Jackson2JsonRedisSerializer 是一种将 Java 对象序列化为 JSON 并存储在 Redis 中的序列化器。它使用 Jackson 框架来实现序列化和反序列化操作。这种序列化器通常用于将 Java 对象存储在 Redis 缓存中。 ### 回答2: Jackson2JsonRedisSerializer是Spring Data Redis提供的一种序列化工具,用于将Java对象序列化为JSON格式并存储到Redis数据库中。它基于Jackson库,可以很方便地进行对象和JSON之间的转换。 Jackson2JsonRedisSerializer的主要作用是解决默认的JdkSerializationRedisSerializer在序列化时产生的一系列问题。JdkSerializationRedisSerializer虽然简单易用,但它会将序列化后的对象存储为字节数组,不易阅读和调试,并且在不同的Java版本之间存在不兼容的问题。 相比之下,Jackson2JsonRedisSerializer将对象序列化为JSON字符串,具有更好的人类可读性和跨版本的兼容性。它可以序列化任何可以被Jackson库支持的对象,包括JavaBean、集合、数组等。同时,Jackson2JsonRedisSerializer还支持设置对象的属性进行序列化和反序列化,增加了灵活性。 在使用Jackson2JsonRedisSerializer时,需要将其配置为RedisTemplate或者RedisOperations对象的value序列化器。这样,当通过RedisTemplate操作Redis数据库时,存入和取出的对象就会自动进行JSON序列化和反序列化。 总的来说,Jackson2JsonRedisSerializer是一种方便可靠的序列化工具,可以解决JdkSerializationRedisSerializer的一些不足之处。它简化了对象的存储和读取过程,使得在使用Redis作为数据存储时,可以更加灵活、高效地处理Java对象。 ### 回答3: Jackson2JsonRedisSerializer是一个用于将Java对象序列化为JSON格式并存储到Redis中的工具类。它是Spring Data Redis库中的一部分,并基于Jackson JSON库实现。 使用Jackson2JsonRedisSerializer时,可以将Java对象转换为JSON字符串,并将其存储在Redis中。反之,我们还可以从Redis中获取JSON字符串并将其转换回Java对象。 Jackson2JsonRedisSerializer提供了一种用于序列化和反序列化的机制,可以将Java对象和Redis中的数据进行相互转换。它支持的数据类型包括基本数据类型(如字符串、整数、布尔值等)以及复杂的对象类型(如List、Map等)。 使用Jackson2JsonRedisSerializer的好处包括: 1. 简单易用:Jackson2JsonRedisSerializer封装了序列化和反序列化的逻辑,简化了开发人员的工作。我们只需要调用相应的方法即可完成对象与JSON字符串之间的转换。 2. 数据格式标准:Jackson2JsonRedisSerializer采用了标准的JSON格式,数据之间的交互更加方便和可读。 3. 版本兼容性:Jackson2JsonRedisSerializer与不同版本的Jackson JSON库兼容性较好,可以支持各种版本的Jackson库。 4. 扩展性:Jackson2JsonRedisSerializer可以自定义序列化和反序列化的规则,适应各种复杂对象的存储需求。 总之,Jackson2JsonRedisSerializer是一个功能强大且易于使用的工具类,可以方便地将Java对象序列化为JSON字符串并存储在Redis中,同时也可以将JSON字符串从Redis中获取并反序列化为Java对象。这使得我们能够更加灵活和高效地处理Redis中的数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值