SpringBoot从Redis中取出缓存的对象,但却出现同一类型对象无法转换为同一类型的对象问题java.lang.ClassCastException:

在SpringBoot项目中使用Redis缓存时遇到一个罕见问题,即从Redis取出的User对象在转换回User类型时抛出ClassCastException。问题源于Springboot的DevTools热部署工具,它在代码变更后使用不同的类加载器,导致同一类的两个实例无法相互转换。关闭DevTools后问题得到解决。

问题:

从Redis中取出的缓存对象,出现同一类型转换错误

最近在写Springboot项目,用到Redis缓存对象User,通过key取出来后的value并赋值给同一类型的对象,但是却出现了一个神奇的报错,同一对象无法转换为同一对象的报错,这个问题我还是第一次见,刚开始真的百思不得其解

java.lang.ClassCastException: com.blog.bean.User cannot be cast to com.blog.bean.User

解决:

开始试着找错误,在test上看能不能打印取出的缓存对象信息,开始是直接用Object类接收,打印信息完全一致,是我想要的东西;后面转换为实体类的类型User,神奇的是在springboot上的测试类上却能运行成功,没有报错,类型能成功转换,真的是伤脑筋。

最后无奈开启百度大法

终于解决:

把springboot热部署DevTools工具去掉

<!--<dependency>-->
    <!--<groupId>org.springframework.boot</groupId>-->
    <!--<artifactId>spring-boot-devtools</artifactId>-->
    <!--<optional>true</optional>-->
<!--</dependency>-->

原因:

当User对象被序列化并存到Redis缓存里时,使用的类加载器是C1,而在此之后你改变了一些代码或者配置文件的时候,DevTools工具将会自动重新启动这个容器,并且创建一个新的类加载器 C2,这时前后两次加载User类的类加载器就不同了,两个不同类加载器加载的两个对象,JVM会认为这是两个不同的对象

也就是Springboot为了实现代码热部署破坏了双亲委派模型,导致(User类)的类加载器由AppClassLoader变了Springboot的自定义加载器RestartClassLoader

只有类全称相同且类加载器相同JVM才认为类是相同的,你两次生成的对象调用不同的类加载器,虽然是同一类型的对象,但是JVM就会认为这是两个不同的对象,因此也就无法完成类型的转换。

java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.String at org.springframework.data.redis.serializer.StringRedisSerializer.serialize(StringRedisSerializer.java:36) ~[spring-data-redis-2.6.2.jar:2.6.2] at org.springframework.data.redis.core.script.DefaultScriptExecutor.keysAndArgs(DefaultScriptExecutor.java:112) ~[spring-data-redis-2.6.2.jar:2.6.2] at org.springframework.data.redis.core.script.DefaultScriptExecutor.lambda$execute$0(DefaultScriptExecutor.java:60) ~[spring-data-redis-2.6.2.jar:2.6.2] at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:223) ~[spring-data-redis-2.6.2.jar:2.6.2] at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:190) ~[spring-data-redis-2.6.2.jar:2.6.2] at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:177) ~[spring-data-redis-2.6.2.jar:2.6.2] at org.springframework.data.redis.core.script.DefaultScriptExecutor.execute(DefaultScriptExecutor.java:58) ~[spring-data-redis-2.6.2.jar:2.6.2] at org.springframework.data.redis.core.script.DefaultScriptExecutor.execute(DefaultScriptExecutor.java:52) ~[spring-data-redis-2.6.2.jar:2.6.2] at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:344) ~[spring-data-redis-2.6.2.jar:2.6.2] at com.hmdp.service.impl.VoucherOrderServiceImpl.seckillVoucher(VoucherOrderServiceImpl.java:102) ~[classes/:na] at com.hmdp.service.impl.VoucherOrderServiceImpl$$FastClassBySpringCGLIB$$ba28bb10.invoke(<generated>) ~[classes/:na] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.2.15.RELEASE.jar:5.2.15.RELEASE] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779) ~[spring-aop-5.2.15.RELEASE.jar:5.2.15.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.2.15.RELEASE.jar:5.2.15.RELEASE] at org.s
04-01
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值