美文网首页
类加载器不一致导致的转换异常

类加载器不一致导致的转换异常

作者: luncene_e110 | 来源:发表于2021-03-26 15:59 被阅读0次

最近在一个项目中使用rocketmq发送消息,在消费消息时,反序列化是出现一个报错,最开始以为是alibaba的fastjson报的错。

详细报错为:

java.lang.ClassCastException: com.dtyunxi.amdu.dms.common.event.clue.dto.PlatformClueMsgDto cannot be cast to com.dtyunxi.amdu.dms.common.event.clue.dto.PlatformClueMsgDto

at com.alibaba.fastjson.serializer.ASMSerializer_14_PlatformClueMsgDto.write(Unknown Source)

at com.alibaba.fastjson.serializer.JSONSerializer.writeWithFieldName(JSONSerializer.java:314)

at com.alibaba.fastjson.serializer.ASMSerializer_11_MessageVo.write(Unknown Source)

at com.alibaba.fastjson.serializer.JSONSerializer.write(JSONSerializer.java:285)

at com.alibaba.fastjson.JSON.toJSONString(JSON.java:731)

at com.alibaba.fastjson.JSON.toJSONString(JSON.java:669)

at com.alibaba.fastjson.JSON.toJSONString(JSON.java:634)

at com.dtyunxi.huieryun.mq.provider.rocket.RocketConsumer$1.consumeMessage(RocketConsumer.java:205)

at org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService$ConsumeRequest.run(ConsumeMessageConcurrentlyService.java:411)

at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)

at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)

at java.util.concurrent.FutureTask.run(FutureTask.java)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)

从原文看是castException。检查包全路径,没有区别。初步以为是fastjson的bug。

后来通过类加载器,在consumer端查看本地加载的PlatformClueMsgDto,和消息体力的body消息体的加载器不一致,导致转换失败。

如下图

图1 图2

platformClueMsgDto是在本地加载的dto对象,而message.getData()也是platClueMsgDto(注:MessageVo是由第三方的jar包封装的对象)。

从截图看本地包的platformClueMsgDto的类加载器对象是RestartClassLoader,而MessageVo里的platClueMsgDto的类加载器是AppClassLoader。

一般情况下,我们的类加载器按理都应该是AppClassLoader。

所以我们来看看RestartCalssLoader类加载器是什么。

RestartCalssLoader是由Spring-boot-devtools引入的类加载器。

整个启动流程大概:

main() -> SpringApplication.run() -> SpringApplicationRunListeners.starting() ->

SimpleApplicationEventMulticaster.multicastEvent() RestartApplicationListener.onApplicationEvent() ->

RestartApplicationListener.onApplicationStartingEvent() -> Restarter.initialize()

由此我们看到是由实现ApplicationListener的RestartApplicationListener完成对Restarter的初始化的,而此是传入的Thread正是main线程,此线程的ContextClassLoader便是AppClassLoader,所以经过过滤后就将只有类似于 file:/projectPath/projectName/module/target/classes这样的属于此项目代码的URL,所以此类加载器不负责加载第三方jar包的类文件。

ClassLoader不一致的解决方法

1.最粗暴的方式就是直接去除依赖 Spring-boot-devtools

2.如果确实想要热部署功能,Springboot也提供了配置,没错就是上文提到的过滤URLs时使用DevToolsSettings读取META-INF/spring-devtools.properties配置文件进行纳入、排查,你可以自己新建 spring-devtools.properties 文件,配置上需要此自定义类加载器负责来加载的正则表达式,形式如(exclude表示排查、include表示纳入):

restart.exclude.spring-boot=/spring-boot/target/classes/

restart.exclude.spring-boot-devtools=/spring-boot-devtools/target/classes/

restart.exclude.spring-boot-starters=/spring-boot-starter-[\\w-]+/

restart.include.commons-pool2=/org/apache/commons/commons-pool2/2.4.3/commons-pool2-2.4.3.jar

相关文章

  • 类加载器不一致导致的转换异常

    最近在一个项目中使用rocketmq发送消息,在消费消息时,反序列化是出现一个报错,最开始以为是alibaba的f...

  • ClassLoader-父子类转换

    父类=子类能转换的条件为: 子类的类加载器==父类的类加载器or 父类的类加载器是子类的类加载器的parent(不...

  • 理解类加载机制

    类加载器 1. 类加载器作用类加载器本身作用就是用于加载类的,将类转换成java.lang.Class的实例;类加...

  • java.lang.ClassCastException的jav

    dev热部署中累加器和本地累加器不一致导致类型转换错误,以后在项目中谨慎使用dev热部署 其次遇到这样的异常的时候...

  • Java 类加载机制-何时初始化类

    类加载器 负责读取 Java 字节代码,并转换成java.lang.Class类的一个实例; 类加载器与类的”相同...

  • 【笔记】Java类加载器

    类加载器负责读取Java字节码,并转换成java.lang.Class类的一个实例。 1. 类加载器的分类 站在虚...

  • 深入类加载器

    类加载器原理 类加载器的作用:把class文件字节码内容加载到内存种,并将这些静态数据转换为方法区中运行时数据结构...

  • 浅谈Java的类加载机制

    类是怎么被加载的 .java--->.class--->二进制字节流--->类加载器--->转换成 java.la...

  • java类加载器及其原理

    java类加载器 : java中默认有三种类加载器:引导类加载器,扩展类加载器,系统类加载器(也叫应用类加载器) ...

  • java基础知识之java类加载器

    1. 什么是类加载器 类加载器就是用来加载类的东西!类加载器也是一个类:ClassLoader 类加载器可以被加载...

网友评论

      本文标题:类加载器不一致导致的转换异常

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