SpringBoot SerializationUtils克隆(反序列化) 类加载器不一致问题(ClassCastException)

问题分析

在SpringBoot中使用 org.apache.commons.lang.SerializationUtils.clone 方法时,发现克隆出来的类强转对应类时发生类型不一致的错误,经过检测发现两个看似相同的类的类加载器不一致

场景

在这里插入图片描述

报错信息

java.lang.ClassCastException: com.tianqiauto.tis.pc.dingdanyupai.po.PrePoint cannot be cast to com.tianqiauto.tis.pc.dingdanyupai.po.PrePoint

检测信息

在这里插入图片描述

在这里插入图片描述

解决方法分析

既然发现类加载器不一致,那么需要找到类反序列化时的类加载器是如何指定得
在这里插入图片描述

深入SerializationUtils.clone方法时发现内部是通过jdk的反序列化类ObjectInputStream将字节码转为对象得
在这里插入图片描述

在这里插入图片描述

发现返回对象是由cons创建的,cons 是一个Constructor,那么需要判断cons是在哪里生成的,从而推断出类加载器的生成依据,而cons存在于ObjectStreamClass,进入ObjectStreamClass desc = readClassDesc(false);判断cons何时赋值
在这里插入图片描述

发现执行完desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false));这段代码时,cons有值,进入initNonProxy方法中
在这里插入图片描述

发现最终指向Caches.localDescs一个map中
在这里插入图片描述

localDescs是一个全局静态变量,所以需要知道在什么地方添加值的
在这里插入图片描述

打断点debug发现在序列化的时候会new ObjectStreamClass(cl)并放在localDescs里,所以进入new ObjectStreamClass(cl)的方法里,找cons的来源
在这里插入图片描述

发现cons是由Class<?> cl生成,也就是说cons的类加载器信息是由Class<?> cl的类加载器决定的,反向查找cl的加载
在这里插入图片描述

发现cl的类加载信息由latestUserDefinedLoader(),查阅资料发现,latestUserDefinedLoader()会根据栈帧信息查找第一个非根类加载器或扩展类加载器,而SerializationUtils属于ApplicationClassLoader加载的范围,所以SerializationUtils.clone(point)返回的对象是由ApplicationClassLoader加载
在这里插入图片描述

解决方案

方案一(推荐)

SerializationUtils.clone中的方法复制到项目中

public class TestClassLoaderController {

    private static PrePoint point = new PrePoint();


    @GetMapping("/testClassLoader")
    public AjaxResult testClassLoader() {
        PrePoint deserialize = (PrePoint) cloneObject(point);
        return null;

    }

    private static Object cloneObject(PrePoint point) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
        serialize(point, baos);
        byte[] bytes = baos.toByteArray();
        return deserialize(bytes);
    }

    public static Object deserialize(byte[] objectData) {
        if (objectData == null) {
            throw new IllegalArgumentException("The byte[] must not be null");
        }
        ByteArrayInputStream bais = new ByteArrayInputStream(objectData);
        return deserialize(bais);
    }

    public static Object deserialize(InputStream inputStream) {
        if (inputStream == null) {
            throw new IllegalArgumentException("The InputStream must not be null");
        }
        ObjectInputStream in = null;
        try {
            // stream closed in the finally
            in = new ObjectInputStream(inputStream);
            return in.readObject();

        } catch (ClassNotFoundException ex) {
            throw new SerializationException(ex);
        } catch (IOException ex) {
            throw new SerializationException(ex);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                // ignore close exception
            }
        }
    }

    public static void serialize(Serializable obj, OutputStream outputStream) {
        if (outputStream == null) {
            throw new IllegalArgumentException("The OutputStream must not be null");
        }
        ObjectOutputStream out = null;
        try {
            // stream closed in the finally
            out = new ObjectOutputStream(outputStream);
            out.writeObject(obj);

        } catch (IOException ex) {
            throw new SerializationException(ex);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException ex) {
                // ignore close exception
            }
        }
    }
}

方案二

关闭热加载

spring:
  devtools:
    restart:
      enabled: false

或者

@SpringBootApplication
public class SSMPApplication {
    public static void main(String[] args) {
        System.setProperty("spring.devtools.restart.enabled","false");
        SpringApplication.run(SSMPApplication.class);
    }
}

方案三

移除热加载的jar包

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-devtools</artifactId>
  <optional>true</optional> <!-- 这个需要为 true 热部署才有效 -->
</dependency>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/114478.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【PyTorch 卷积】实战自定义的图片归类

前言 卷积神经网络是一类包含卷积计算且具有深度结构的前馈神经网络&#xff0c;是深度学习的代表算法之一&#xff0c;它通过卷积层、池化层、全连接层等结构&#xff0c;可以有效地处理如时间序列和图片数据等。关于卷积的概念网络上也比较多&#xff0c;这里就不一一描述了。…

大数据之LibrA数据库系统告警处理(ALM-12010 Manager主备节点间心跳中断)

告警解释 当主Manager节点在7秒内没有收到备Manager节点的心跳信号时&#xff0c;产生该告警。 当主Manager节点收到备Manager节点的心跳信号后&#xff0c;告警恢复。 告警属性 告警参数 对系统的影响 如果主Manager进程异常&#xff0c;主备倒换无法进行&#xff0c;影响…

我做云原生的那几年

背景介绍 在2020年6月&#xff0c;我加入了一家拥有超过500人的企业。彼时&#xff0c;前端团队人数众多&#xff0c;有二三十名成员。在这样的大团队中&#xff0c;每个人都要寻找自己的独特之处和核心竞争力。否则&#xff0c;你可能会沉没于常规的增删改查工作中&#xff0…

人工智能基础_机器学习016_BGD批量梯度下降求解多元一次方程_使用SGD随机梯度下降计算一元一次方程---人工智能工作笔记0056

然后上面我们用BGD计算了一元一次方程,那么现在我们使用BGD来进行计算多元一次方程 对多元一次方程进行批量梯度下降. import numpy as np X = np.random.rand(100,8) 首先因为是8元一次方程,我们要生成100行8列的X的数据对应x1到x8 w = np.random.randint(1,10,size = (8…

mac matplotlib显示中文

以下默认字体&#xff0c;在mac ventura上测试能成功显示中文&#xff1a; import matplotlib.pyplot as plt import matplotlib#from matplotlib import font_manager #plt.rcParams[font.sans-serif] [Heiti TC]#plt.rcParams[font.sans-serif] [Songti SC]#plt.rcParams[f…

Jupyter notebook如何加载torch环境

默认你已经安装了anaconda 和 pytorch 环境。 1&#xff0c;必须要以管理员身份打开 Anaconda prompt终端&#xff0c; 2&#xff0c;进入pytorch环境中&#xff1a; conda activate pytorch_393&#xff0c;安装必要插件&#xff1a; &#xff08;1&#xff09;conda inst…

13、Kubernetes核心技术 - Ingress

目录 一、概述 二、Ingress工作原理 三、Ingress 使用 3.1)、Ingress-http方式 3.1.1)、创建Ingress Controller和对应的Service 3.1.2)、创建tomcat的Pod和Service 3.1.3)、创建nginx的Pod和Service 3.1.4)、创建ingress http代理 3.1.5)、配置本地host文件 3.1.6)、…

GitHub经常打不开或者访问解决办法

访问慢或无法访问的原因&#xff1a;DNS解析是最为基础的一个环节。由于Github的服务器在全球各地&#xff0c;域名解析所需的时间也会不同&#xff0c;这就导致了在特定地区可能会出现Github无法正常访问的情况。 解决&#xff1a;查询到github对应的IP&#xff0c;然后在host…

水库大坝可视化智能远程监管方案,助力安全监测智能巡检

一、背景需求 水库大坝作为防洪度汛的重要设施&#xff0c;其安全问题直接关系到人民群众的生命财产安全。因此&#xff0c;必须加强对大坝水库的安全管理&#xff0c;对水库除险加固和运行管护要消除存量隐患&#xff0c;实现常态化管理&#xff0c;同时要配套完善重点小型水…

直播界很火的无线领夹麦克风快充方案 Type-C接口 PD快充+无线麦克风可同时进行

当前市场上流行一款很火的直播神器&#xff0c;无线领夹麦克风&#xff08;MIC&#xff09;&#xff0c;应用于网红直播&#xff0c;网课教学&#xff0c;采访录音&#xff0c;视频录制&#xff0c;视频会议等等场景。 麦克风对我们来说并不陌生&#xff0c;而且品类有很多。随…

au如何分离人声和背景音乐?帮你整理了几个必备的!

Audition专为在照相室、广播设备和后期制作设备方面工作的音频和视频专业人员设计&#xff0c;可提供先进的音频混合、编辑、控制和效果处理功能。因为软件的专业性&#xff0c;所以有些功能使用起来就比较复杂&#xff0c;下面介绍了详细的操作步骤。 方法一&#xff1a;直接使…

设备接入服务组件->微服务and容器化改造说明文档

SVN路径 https://192.0.0.241/USTA-dac/branches/dev/V1.10.500/dac 目录结构 das为设备接入服务&#xff0c;负责驱动管理&#xff0c;资源同步&#xff0c;订阅下发。下面有两个文件夹分别对应了openssl1.0的版本和后面更换接口后openssl1.1的版本。das_proxy为设备信令下发…

Spring Cloud智慧工地源码,利用计算机技术、互联网、物联网、云计算、大数据等新一代信息技术开发,微服务架构

智慧工地系统充分利用计算机技术、互联网、物联网、云计算、大数据等新一代信息技术&#xff0c;以PC端&#xff0c;移动端&#xff0c;设备端三位一体的管控方式为企业现场工程管理提供了先进的技术手段。让劳务、设备、物料、安全、环境、能源、资料、计划、质量、视频监控等…

Flutter 02 基础组件 Container、Text、Image、Icon、ListView

一、Container容器组件&#xff1a; demo1&#xff1a; import package:flutter/material.dart;void main() {runApp(MaterialApp(home: Scaffold(appBar: AppBar(title: const Text("你好Flutter")),body: const MyApp(),),)); }// 容器组件 class MyApp extends St…

BUUCTF 数据包中的线索 1

BUUCTF:https://buuoj.cn/challenges 题目描述&#xff1a; 公安机关近期截获到某网络犯罪团伙在线交流的数据包&#xff0c;但无法分析出具体的交流内容&#xff0c;聪明的你能帮公安机关找到线索吗&#xff1f; 密文&#xff1a; 下载附件&#xff0c;解压得到一个.pcapng文…

tensorflow-gpu 找不到指定模块

排除&#xff1a; 1.python编译器是64位 查询教程 2. cuda cudnn版本 均是12.2 可以向下兼容 cmd&#xff1a; nvcc -V即可 另一种方法 tensorflow官网教程 pip install tensorflow_gpu1.12.0 4.安装torch-gpu 检查所在环境 解决&#xff01;&#xff01; conda install …

Apollo云实验:使用Sim control仿真自动驾驶

使用Sim control仿真自动驾驶 概述Sim control仿真自动驾驶启动DreamView仿真系统 实验目的福利活动 主页传送门&#xff1a;&#x1f4c0; 传送 概述 自动驾驶汽车在实现落地应用前&#xff0c;需要经历大量的道路测试来验证算法的可行性和系统的稳定性&#xff0c;但道路测试…

麒麟KYLINIOS软件仓库搭建01-新创建软件仓库服务器

原文链接&#xff1a;麒麟KYLINIOS软件仓库搭建01-新创建软件仓库服务器 hello&#xff0c;大家好啊&#xff0c;今天给大家带来麒麟桌面操作系统软件仓库搭建的文章01-新创建软件仓库服务器&#xff0c;本篇文章主要给大家介绍了如何在麒麟桌面操作系统2203-x86版本上搭建内网…

opencv复习(简短的一次印象记录)

2-高斯与中值滤波_哔哩哔哩_bilibili 1、均值滤波 2、高斯滤波 3、中值滤波 4、腐蚀操作 卷积核不都是255就腐蚀掉 5、膨胀操作 6、开运算 先腐蚀再膨胀 7、闭运算 先膨胀再腐蚀 8、礼帽 原始数据-开运算结果 9、黑帽 闭运算结果-原始数据 10、Sobel算子 左-右&#x…

在Qt中List View和List Widget的区别是什么,以及如何使用它们

2023年10月29日&#xff0c;周日晚上 目录 List View和List Widget的区别 如何使用QListView 如何使用QListWidget List View和List Widget的区别 在Qt中&#xff0c;QListView 和 QListWidget 是用于显示列表数据的两个常用控件&#xff0c;它们有一些区别和特点。 1. 数…