赞
踩
在开发在项目中遇到这样的问题:
进行XML转换成bean类的时候要进行强转,单老是会出现类转换异常,还是同一种bean类的类转换异常,报错如下:
java.lang.ClassCastException: com.fcar.kbyj.api.entities.wxmsg.pojo.WeChatBuyPost_v3 cannot be cast to com.fcar.kbyj.api.entities.wxmsg.pojo.WeChatBuyPost_v3
at com.fcar.kbyj.userservice.controller.WxPayController.wxPayBackApp(WxPayController.java:117)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209)
如上报错信息:相同类不能转换成相同类
去找了很多资料,后面找了篇文章,查找了官方文档:
官方文档:
https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-devtools.html
文章出处(作者是在redis 转换出错的):
https://www.jianshu.com/p/e6d5a3969343
分析出以下问题 :
JVM判断两个类对象是否相同的依据:一是类全称;一个是类加载器.(具体原理请自行百度,在此不再赘述)。
大家都知道虚拟机的默认类加载机制是通过双亲委派实现的。springboot为了实现程序动态性(比如:代码热替换、模块热部署等,白话讲就是类文件修改后容器不重启),“破坏或牺牲” 了双亲委派模型。springboot通过强行干预-- “截获”了用户自定义类的加载(由jvm的加载器AppClassLoader变为springboot自定义的加载器RestartClassLoader,一旦发现类路径下有文件的修改,springboot中的spring-boot-devtools模块会立马丢弃原来的类文件及类加载器,重新生成新的类加载器来加载新的类文件,从而实现热部署。比较流行的OSGI也能实现热部署)。
解决方法:
既然源头因热部署而起,所以只要想办法关掉springboot的热部署即可。
<方案一> 通过卸掉springboot的热部署模块spring-boot-devtools来实现
<!-- 修改后立即生效,热部署 -->
<!--
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>-->
<方案二>如果不想卸掉spring-boot-devtools模块也可禁用部署功能
读者也可以在application.properties设置禁用属性,但它的作用域只发生在当前模块,如果你的项目牵扯到多个模块,最好通过上面的方式在整个运行系统的级别禁用,以免出现多个模块之间实现类文件调用时类加载器不一致的问题。
<方案三>既然是类加载器的问题也可使用Spring的ConfigurableObjectInputStream配合Thread.currentThread().getContextClassLoader() 来使用。
spring-boot-devtools会检测类路径的变化,当类路径内容发生变化后会自动重启应用程序。Spring Boot的重启技术通过使用两个类加载器。由于使用的是双类加载机制重启会非常快,如果启动较慢也可使用JRebel重加载技术。
(1)base classloader (Base类加载器):加载不改变的Class,如第三方提供的jar包。
(2)restart classloader(Restart类加载器):加载正在开发的Class。
到这里相信大家知道了,为什么重启很快,因为重启的时候只是加载了在开发的Class,没有重新加载第三方的jar包。
因为类文件的修改(一般在IDE环境下修改)只会发生在开发阶段,所以就解释了ClassCastException为什么总是发生在开发阶段,而测试或生产环境却运行正常。
针对上面问题我们也能自然想到以后只要是在反序列化及热部署的场景下出现的类型转换异常基本上就是这个问题了。
再次注明文章出处:
https://www.jianshu.com/p/e6d5a3969343 (感谢!!!)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。