美文网首页
springboot环境下相同类进行转换出现ClassCastE

springboot环境下相同类进行转换出现ClassCastE

作者: 重色思倾国 | 来源:发表于2018-02-08 19:50 被阅读0次

最近项目组出现一个很奇怪的问题,为了实现用户的单点登录,项目通过redis进行session管理。而用户的相关身份信息是以字节数组的形式存储在redis中的。既然是字节数组,自然就要进行反序列化才能还原成相关对象。而在反序列化的类型转换的时候,明明是同一个类却总是抛出ClassCastException的异常让人摸不着头脑。现将具体的解决过程总结如下。

1.   查找异常

2. 通过异常链定位源码

为了更加方便的观察问题,源码改为如下形式:

3. 问题重现,观察打印信息:

4. 根据问题查找官方文档:

https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-devtools.html

5. 问题分析

1.       JVM判断两个类对象是否相同的依据:一是类全称;一个是类加载器.(具体原理请自行百度,在此不再赘述)。

2.       大家都知道虚拟机的默认类加载机制是通过双亲委派实现的。springboot为了实现程序动态性(比如:代码热替换、模块热部署等,白话讲就是类文件修改后容器不重启),“破坏或牺牲” 了双亲委派模型。springboot通过强行干预-- “截获”了用户自定义类的加载(由jvm的加载器AppClassLoader变为springboot自定义的加载器RestartClassLoader,一旦发现类路径下有文件的修改,springboot中的spring-boot-devtools模块会立马丢弃原来的类文件及类加载器,重新生成新的类加载器来加载新的类文件,从而实现热部署。比较流行的OSGI也能实现热部署)。

6. 问题解决

既然源头因热部署而起,所以只要想办法关掉springboot的热部署即可。

<方案一>  通过卸掉springboot的热部署模块spring-boot-devtools来实现

在pom中注释掉springboot的spring-boot-devtools

<方案二>如果不想卸掉spring-boot-devtools模块也可禁用部署功能

读者也可以在application.properties设置禁用属性,但它的作用域只发生在当前模块,如果你的项目牵扯到多个模块,最好通过上面的方式在整个运行系统的级别禁用,以免出现多个模块之间实现类文件调用时类加载器不一致的问题。

<方案三>既然是类加载器的问题也可使用Spring的ConfigurableObjectInputStream配合Thread.currentThread().getContextClassLoader() 来使用。

7. 解决的结果

从上面的解决结果可以看到类加载机制又恢复了JVM本身的双亲委托机制,最终所有的类都是通过JVM中的类加载器AppClassLoader来加载。

8. 后续补充

8.1    spring-boot-devtools会检测类路径的变化,当类路径内容发生变化后会自动重启应用程序。Spring Boot的重启技术通过使用两个类加载器。由于使用的是双类加载机制重启会非常快,如果启动较慢也可使用JRebel重加载技术。

(1)base classloader (Base类加载器):加载不改变的Class,如第三方提供的jar包。

(2)restart classloader(Restart类加载器):加载正在开发的Class。

到这里相信大家知道了,为什么重启很快,因为重启的时候只是加载了在开发的Class,没有重新加载第三方的jar包。

8.2  因为类文件的修改(一般在IDE环境下修改)只会发生在开发阶段,所以就解释了ClassCastException为什么总是发生在开发阶段,而测试或生产环境却运行正常。

8.3  针对上面问题我们也能自然想到以后只要是在反序列化及热部署的场景下出现的类型转换异常基本上就是这个问题了。

相关文章

  • springboot环境下相同类进行转换出现ClassCastE

    最近项目组出现一个很奇怪的问题,为了实现用户的单点登录,项目通过redis进行session管理。而用户的相关身份...

  • js在不同类型的值比较时的隐性类型转换

    我们知道在js中,==是进行的值比较,在比较运算之前,js会将不同类型的值转换为相同类型的值在进行比较,转换情况如...

  • SpringBoot系列 Mybatis 之自定义类型转换 Ty

    SpringBoot系列 Mybatis 之自定义类型转换 TypeHandler 在使用 mybatis 进行 ...

  • 1.3.基本类型之间的转换

    俩种: 1.自动类型转换(隐式转换) 不同类型的数据进行混合运算时(包括赋值)java会自动进行数据类型转换(想表...

  • 数据类型、运算符与表达式

    一、数据类型 类型转换的规则1)两个不同类型的数据进行运算时,需要进行类型转换,将占内存小的数据转换为占内存大额数...

  • 类型转换

    1.在golang中不同类型的数据进行赋值的时候需要进行类型转换。 package mainimport "fmt...

  • day15-06-集合框架(泛型概述)

    /*泛型:JDK1.5版本以后出现了新特性。用于解决类型安全问题。 好处:1.将运行时期出现的ClassCastE...

  • JAVA-Day4

    小类型向大类型转换 不同类型的数据经常出现相互转换的现象. 1, 在Java中小类型向大类型的转换会自动完成, 即...

  • 十一:Java基础入门-小类型向大类型转换

    1:概述 不同类型的数据经常出现相互转换的现象 例如: 2:小类型向大类型转换 小类型向大类型的转换会自动完成,即...

  • (一)数据类型转换

      C语言规定,不同类型的数据需要转换为同一类型才可以进行计算。在整型,实型和字符型之间通过类型转换就可以进行混合...

网友评论

      本文标题:springboot环境下相同类进行转换出现ClassCastE

      本文链接:https://www.haomeiwen.com/subject/ujottftx.html