在使用 spring-boot-devtools 时,经常会出现 class x.x.A cannot be cast to x.x.A 的情况。
例如我在集成 Tio
的时候遇见这样的报错:
Exception in thread "redisson-3-2" java.lang.ClassCastException: com.gammaos.gateway.socket.packet.GammaPacket cannot be cast to com.gammaos.gateway.socket.packet.GammaPacket at com.alibaba.fastjson.serializer.ASMSerializer_2_GammaPacket.writeDirectNonContext(Unknown Source) at com.alibaba.fastjson.serializer.ASMSerializer_2_GammaPacket.write(Unknown Source) at com.alibaba.fastjson.serializer.JSONSerializer.writeWithFieldName(JSONSerializer.java:333) at com.alibaba.fastjson.serializer.ASMSerializer_1_TioClusterVo.writeDirectNonContext(Unknown Source) at com.alibaba.fastjson.serializer.ASMSerializer_1_TioClusterVo.write(Unknown Source) at com.alibaba.fastjson.serializer.JSONSerializer.write(JSONSerializer.java:285) at com.alibaba.fastjson.JSON.toJSONString(JSON.java:758) at com.alibaba.fastjson.JSON.toJSONString(JSON.java:722) at com.alibaba.fastjson.JSON.toJSONString(JSON.java:715) at org.tio.utils.json.Json.toJson(Json.java:87) at org.tio.cluster.TioClusterMessageListener.onMessage(TioClusterMessageListener.java:34) at org.tio.cluster.redisson.RedissonMessageListener.onMessage(RedissonMessageListener.java:21) at org.tio.cluster.redisson.RedissonMessageListener.onMessage(RedissonMessageListener.java:11) at org.redisson.PubSubMessageListener.onMessage(PubSubMessageListener.java:79) at org.redisson.client.RedisPubSubConnection.onMessage(RedisPubSubConnection.java:78) at org.redisson.client.handler.CommandPubSubDecoder.lambda$enqueueMessage$0(CommandPubSubDecoder.java:184) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.lang.Thread.run(Thread.java:748)
主要原因是: 同一个类如果使用了不同的类加载器,就会产生这样的错误。
spring-boot-devtools 默认会对 IDE 中引入的所有项目使用 restart 类加载器,对于引入的 jar 包使用 base 类加载器, 因此要想解决这类问题就是对指定的 jar 包使用 restart 类加载器即可。
Spring 官方给出的教程是创建属性文件: META-INF/spring-devtools.properties
然后在属性文件中添加:
restart.exclude.companycommonlibs=/mycorp-common-[/w-]+.jar restart.include.projectcommon=/mycorp-myproj-[/w-]+.jar
这里就是告诉 spring,哪一些 jar 用 RestartClassLoader 来装载类。
那我们这里只需要在 META-INF/spring-devtools.properties
加上如何指定 tio 的 jar 包使用 restart 类加载器加载即可:
restart.include.tio=/tio-[//w-//.]+jar