IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java序列化踩坑指南 -> 正文阅读

[Java知识库]Java序列化踩坑指南

前提概要

首先,我们来说一下为什么要使用序列化?直接传输一个个的对象不就好了?

以我理解的三个角度来说明:

1.深拷贝,我们都知道浅拷贝的坏处,如果一个对象,使用=赋值,由于对象引用指向是不变的,一个对象改变了,千千万万个复制体都会随之改变。

2.持久化,通过序列化的方式可以将我们的对象以文件的形式访问,典型的就是将对象转化为JSON格式,存入数据库或者其他文件中。

3.统一管理,由于我们采用相同的格式进行处理,那么下次序列化,反序列化都可以轻松的转化为字符串,对象。

比较主流的序列化方式就是JSON格式,还有一种就是protobuf,速度更快,这里不多做介绍,主要是使用位运算,压缩等提高传输效率。

正反序列化算法要一致

我们以redis举例,一般我们都是使用的redisTemplate对象进行存取的,但是有一些坑是需要避免的。

下图所示,是redisTemplate默认的序列化方式,即jdk序列化,如果使用默认的在redis中查看会发现很多乱码,当然不推荐使用。
在这里插入图片描述
如果要用的话,不如使用stringRedisTemplate类,采用的是String序列化,如下图所示。
在这里插入图片描述
这里有一点需要注意,你不能存对象用redisTemplate,取对象使用redisTemplate,这样是会出问题的,总而言之,正反序列化算法要一直

以下给大家推荐一个通用的redis配置,无脑用就可以了。

@Configuration
public class RedisConfig {

    @Bean
    public <T> RedisTemplate<String, T> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, T> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //key用字符串序列化
        redisTemplate.setKeySerializer(RedisSerializer.string());
        //value采用json格式序列化 下同
        redisTemplate.setValueSerializer(RedisSerializer.json());
        redisTemplate.setHashKeySerializer(RedisSerializer.string());
        redisTemplate.setHashValueSerializer(RedisSerializer.json());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

总结一下,Spring中针对redis的4中序列化方式。
1.jdk序列化,默认的不好用,会出现乱码。
2.字符串序列化RedisSerializer.string(),自带utf8编码,强烈推荐。
3.Jackson2JsonRedisSerializer,可能有用过,这个也不推荐,value会被转化为LinkedHashMap
4.RedisSerializer.json(),内部其实是创建了一个GenericJackson2JsonRedisSerializer对象,强烈推荐。

RedisTemplate踩坑

如果我们要在上面的泛型里定义Long类型,如下所示。

RedisTemplate<String, Long> redisTemplate

那么在存取值的时候会出什么问题呢?

这里就不卖关子了。

如果使用该数字在整型范围内,需要用Integer类型接收,否则爆强转类型错误。
如果超出整型范围,才可以用Long类型接收。

反序列化要小心构造方法

话不多说,直接上例子。

@Data
@NoArgsConstructor
@AllArgsConstructor
public class MyResult {
    private Integer code;
    private Boolean success;

    public MyResult(Integer code) {
        this.code = code;
        if (code == 200) {
            success = true;
        } else {
            success = false;
        }
    }
}

可以看到,我们创建了结果返回类,我们想要的效果是,如果code=200,直接让success=true

开始进行测试。

    @Test
    public void test2() throws JsonProcessingException {
        String json1 = "{\n" +
                "\"code\":200\n" +
                "}";
        String json2 = "{\n" +
                "\"code\":404\n" +
                "}";
        ObjectMapper objectMapper = new ObjectMapper();
        MyResult myResult1 = objectMapper.readValue(json1, MyResult.class);
        MyResult myResult2 = objectMapper.readValue(json2, MyResult.class);
        System.out.println(myResult1);
        System.out.println(myResult2);
    }

返回结果

MyResult(code=200, success=null)
MyResult(code=404, success=null)

有点出乎我们意料,这是为什么呢?

原因在于,jackson默认采用的是无参构造执行序列化,如果真要达到我们预期的效果,代码如下所示:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class MyResult {
    private Integer code;
    private Boolean success;

    @JsonCreator //指定json反序列化构造
    public MyResult(@JsonProperty("code") Integer code) {//指定json中的属性
        this.code = code;
        if (code == 200) {
            success = true;
        } else {
            success = false;
        }
    }
}

打印结果如下所示

MyResult(code=200, success=true)
MyResult(code=404, success=false)

还有一个坑,这里就不上例子了,只是给出一点小建议。

不到万不得已,不要用枚举类作为DTO在服务中传输,一切返回值都最基本的构成都使用那8种数据类型就好了,枚举的坑会让你多写很多代码,还会出莫名的bug。

人生并不是一场谁掌控最多知识谁就能胜利的竞赛,最重要的是不断学习和成长。真正的损失是,因为害怕被人发现自己的无知,你完完全全逃避了生活,失去了太多宝贵的生命体验。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-24 00:21:20  更:2022-03-24 00:23:26 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 6:38:32-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码