在使用 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

参考链接